Slint Kit Documentation

Fichiers

Sélecteur de fichiers pour Slint

KitFilePicker · Slint Kit 0.3.0

Action Parcourir et liste des fichiers reliées à une boîte de dialogue native.

Action Parcourir et liste des fichiers reliées à une boîte de dialogue native.
Application native de l’exemple ci-dessous.

Les dialogues de fichiers et le dépôt depuis le système nécessitent l’application native ci-dessous.

Essayer le composant

Télécharger le projet complet, le décompresser et lancer cargo run --locked dans son dossier. Rust 1.92+ ; Slint Kit 0.3.0 depuis crates.io. Vous pouvez aussi copier les quatre fichiers ci-dessous.

Choisissez de vrais fichiers dans le dialogue natif puis retirez-en un de la liste. Les requêtes sont asynchrones ; annulation, plateforme non prise en charge et erreurs restent explicites.

ui/app.slint

export { KitFormValidation, HtmlInputKind, NumberInputFormat, KitInputConstraints, KitValidationResult, KitValidityState } from "@kit/kit.slint";
import {KitFilePicker,KitFileDropZone,KitThemes,FileViewEntry,FileSelectionMode,HostRequestPresentation,DropCapability} from "@kit/kit.slint";
export {FileViewEntry,FileSelectionMode,HostRequestPresentation,DropCapability}
export component App inherits Window{
 title:"file-picker";preferred-width:580px;preferred-height:480px;max-width:100000px;max-height:100000px;background:KitThemes.light.canvas;
 in property <[FileViewEntry]> entries;in property <HostRequestPresentation> request-state;in property <string> error;in property <string> status;
 callback browse(FileSelectionMode);callback remove(int,int);
 VerticalLayout{padding:24px;spacing:16px;alignment:start;
 control:=KitFilePicker{label:"Selected files";description:"Names only; file content is not read.";mode:FileSelectionMode.multiple;entries:root.entries;request-state:root.request-state;error:root.error;browse-requested(mode)=>{root.browse(mode);}remove-requested(token,generation)=>{root.remove(token,generation);}}
 Text{text:root.status;color:KitThemes.light.text-primary;wrap:word-wrap;}
 }
}

src/main.rs

use slint::ComponentHandle;
use slint_kit::{
    FileHandle, FileRequest, HostCapability, HostError, HostRequestController, SelectionOutcome,
};
use std::{cell::RefCell, rc::Rc};
mod ui {
    slint::include_modules!();
}
#[derive(Clone, Copy, PartialEq)]
struct FileId(i32);
struct Entry {
    id: FileId,
    handle: FileHandle,
}
struct Files {
    generation: i32,
    next_id: i32,
    entries: Vec<Entry>,
    requests: HostRequestController<Vec<FileHandle>>,
}
fn publish(app: &ui::App, state: &Files) {
    app.set_entries(slint::ModelRc::new(slint::VecModel::from(
        state
            .entries
            .iter()
            .map(|entry| ui::FileViewEntry {
                token: entry.id.0,
                generation: state.generation,
                name: entry.handle.display_name.as_str().into(),
                detail: "Selected resource".into(),
                removable: true,
            })
            .collect::<Vec<_>>(),
    )));
    app.set_status(format!("{} selected files", state.entries.len()).into());
}
fn replace(state: &mut Files, files: Vec<FileHandle>) {
    state.entries.clear();
    for handle in files {
        let id = FileId(state.next_id);
        state.next_id = state.next_id.checked_add(1).expect("resource identity");
        state.entries.push(Entry { id, handle });
    }
    state.generation = state.generation.checked_add(1).expect("view generation");
}
fn failed(app: &ui::App, error: HostError) {
    app.set_request_state(if error == HostError::Unsupported {
        ui::HostRequestPresentation::Unsupported
    } else {
        ui::HostRequestPresentation::Failed
    });
    app.set_error(format!("{error:?}").into());
}
fn main() -> Result<(), slint::PlatformError> {
    let app = ui::App::new()?;
    slint_kit::init_form_validation!(ui, app);
    let state = Rc::new(RefCell::new(Files {
        generation: 1,
        next_id: 1,
        entries: Vec::new(),
        requests: HostRequestController::default(),
    }));
    publish(&app, &state.borrow());
    if slint_kit::native::capabilities().files == HostCapability::Unsupported {
        app.set_request_state(ui::HostRequestPresentation::Unsupported);
    }
    let weak = app.as_weak();
    let shared = state.clone();
    app.on_browse(move |mode| {
        let Some(app) = weak.upgrade() else {
            return;
        };
        let ticket = shared.borrow_mut().requests.begin();
        app.set_request_state(ui::HostRequestPresentation::Pending);
        app.set_error("".into());
        let shared_async = shared.clone();
        let weak_async = weak.clone();
        if slint::spawn_local(async move {
            let outcome = slint_kit::native::pick_files(FileRequest {
                selection: if mode == ui::FileSelectionMode::Single {
                    slint_kit::FileSelectionMode::Single
                } else {
                    slint_kit::FileSelectionMode::Multiple
                },
                filters: Vec::new(),
                suggested_name: None,
            })
            .await;
            let Some(app) = weak_async.upgrade() else {
                return;
            };
            let mut state = shared_async.borrow_mut();
            if !state.requests.finish(ticket, outcome) {
                return;
            }
            match state.requests.take_result().unwrap() {
                SelectionOutcome::Selected(files) => {
                    replace(&mut state, files);
                    app.set_request_state(ui::HostRequestPresentation::Idle);
                    publish(&app, &state);
                }
                SelectionOutcome::Cancelled => {
                    app.set_request_state(ui::HostRequestPresentation::Cancelled)
                }
                SelectionOutcome::Failed(error) => failed(&app, error),
            }
        })
        .is_err()
        {
            shared.borrow_mut().requests.cancel();
            failed(&app, HostError::Unavailable);
        }
    });
    let weak = app.as_weak();
    let shared = state.clone();
    app.on_remove(move |token, generation| {
        if let Some(app) = weak.upgrade() {
            let mut state = shared.borrow_mut();
            if state.generation != generation {
                return;
            }
            state.requests.cancel();
            state.entries.retain(|entry| entry.id != FileId(token));
            state.generation = state.generation.checked_add(1).expect("view generation");
            app.set_request_state(ui::HostRequestPresentation::Idle);
            publish(&app, &state);
        }
    });

    app.run()
}

Cargo.toml et build.rs

Cargo.toml

[package]
name = "slint-kit-file-picker-example"
version = "0.1.0"
edition = "2024"
rust-version = "1.92"
license = "GPL-3.0-or-later"
publish = false

[dependencies]
slint-kit = { version = "=0.3.0", features = ["native"] }
slint = { version = "=1.18.1", default-features = false, features = ["std", "compat-1-18", "backend-winit", "renderer-skia", "accessibility"] }

[build-dependencies]
slint-kit-build = "=0.3.0"

[workspace]

build.rs

fn main() {
    slint_kit_build::compile("ui/app.slint").expect("compile component example");
}

Fichiers : Cargo.toml · build.rs · ui/app.slint · src/main.rs

Activez la fonctionnalité native du kit et attendez native::pick_files avec FileRequest. Publiez les noms FileHandle et conservez des identifiants stables.

L’exemple gère attente, sélection, annulation, absence de prise en charge et erreur. L’aperçu navigateur n’ouvre pas de boîte de dialogue native.

Choisir entre une option intégrée et une composition personnalisée

Options partagées

Composition visuelle

Le fichier ci-dessous produit la capture. Pour les composants pilotés par un contrôleur, il montre l’état affiché sans fournir le branchement Rust. Créer un projet.

Afficher le fichier de la capture
Action Parcourir et liste des fichiers reliées à une boîte de dialogue native.
Capture native du même exemple, moteur Skia.
// Public label overrides localize this fixture; toolkit/host defaults keep their language.
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitFilePicker, KitTheme, KitThemes } from "@kit/kit.slint";

export component Example inherits Window {
    title: "KitFilePicker — exemple";
    preferred-width: 520px;
    preferred-height: 330px;
    max-width: 100000px;
    max-height: 100000px;
    background: root.theme.canvas;
    in-out property <KitTheme> theme: KitThemes.light;
    in-out property <string> status;
    VerticalLayout {
        padding: 24px; spacing: 16px; alignment: start;
        Text { text: "Sélecteur de fichiers"; color: root.theme.text-primary; font-size: 20px * root.theme.text-scale; font-weight: 600; }
        KitFilePicker { label: "Pièces jointes"; theme: root.theme; entries: [{ token: 11, generation: 1, name: "project-brief.txt", detail: "Document texte · 2,4 Ko", removable: true }, { token: 23, generation: 1, name: "meeting-notes.md", detail: "Markdown · 1,2 Ko", removable: true }]; remove-requested(token, generation) => { root.status = "Retirer le fichier d’identifiant " + token; } }
        if root.status != "": Text { text: root.status; color: root.theme.text-secondary; font-size: 12px * root.theme.text-scale; wrap: word-wrap; }
    }
}

Télécharger cet exemple

API publique

Hérite de Rectangle.

Propriétés

Nom Type Sens
required bool in
required-message string in
custom-validity string in-out
validity KitValidityState out
will-validate bool out
validation-message string out
theme KitTheme in
control-size ControlSize in
access FieldAccess in
mode FileSelectionMode in
request-state HostRequestPresentation in
entries [FileViewEntry] in
label string in
description string in
error string in

Types et variantes

Type Déclaration
enum ControlSize compact, medium, comfortable
enum FieldAccess editable, read-only, disabled
enum FileSelectionMode single, multiple
struct FileViewEntry token: int, generation: int, name: string, detail: string, removable: bool
enum HostRequestPresentation idle, pending, cancelled, failed, unsupported
struct KitValidityState valid: bool, value-missing: bool, type-mismatch: bool, pattern-mismatch: bool, too-long: bool, too-short: bool, range-underflow: bool, range-overflow: bool, step-mismatch: bool, bad-input: bool, custom-error: bool,

Signaux

Fonctions

Voir aussi