Clavier de sélection pour Slint
KitSelectKeyboard · Slint Kit 0.3.1
Traducteur clavier partagé pour les sélecteurs et menus composés.

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 Activity au pointeur, ou naviguez au clavier puis appuyez sur Entrée. Rust accepte sa clé.
ui/app.slint
export { KitFormValidation, HtmlInputKind, NumberInputFormat, KitInputConstraints, KitValidationResult, KitValidityState } from "@kit/kit.slint";
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitSelectKeyboard, KitOption, OptionRow, SelectState, NavigationStep, CloseReason, SelectionAvailability, KitTheme, KitThemes } from "@kit/kit.slint";
export component App inherits Window {
title: "KitSelectKeyboard example";
preferred-width: 520px;
preferred-height: 360px;
max-width: 100000px;
max-height: 100000px;
background: root.theme.canvas;
in-out property <KitTheme> theme: KitThemes.light;
in property <[OptionRow]> rows;
in property <SelectState> select-state;
in property <string> selected-label: "Overview";
in-out property <string> query;
callback select-open();
callback select-navigate(NavigationStep);
callback select-activate(int, int);
callback select-dismiss(CloseReason);
callback select-query(string);
callback select-typeahead(string);
VerticalLayout {
padding: 24px;
spacing: 16px;
alignment: start;
control := KitSelectKeyboard {
height: root.rows.length * 48px; vertical-stretch: 0;
state: root.select-state; init => { self.focus(); }
open-requested => { root.select-open(); }
navigate(step) => { root.select-navigate(step); }
activate(token, generation) => { root.select-activate(token, generation); }
dismiss(reason) => { root.select-dismiss(reason); }
typeahead(text) => { root.select-typeahead(text); }
tab-navigation(reverse) => { return reject; }
VerticalLayout {
alignment: start;
for row in root.rows: KitOption {
theme: root.theme; option-data: row; height: 48px;
active: root.select-state.active.present && root.select-state.active.token == row.token;
selected: root.select-state.selected.present && root.select-state.selected.token == row.token;
activate(token, generation) => { root.select-activate(token, generation); }
Text { x: 0px; y: 0px; width: parent.width; height: parent.height; horizontal-alignment: left; font-size: 14px * root.theme.text-scale; overflow: elide; text: row.label; color: root.theme.text-primary; vertical-alignment: center; }
}
}
}
result := Text { text: "Selected: " + root.selected-label; color: root.theme.text-primary; }
}
}
src/main.rs
// SPDX-License-Identifier: GPL-3.0-or-later
use slint::ComponentHandle;
use slint_kit::{Ownership, SelectOption, SelectionIntent};
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
enum Destination { Overview, Activity, Settings }
impl Destination {
fn label(self) -> &'static str {
match self { Self::Overview => "Overview", Self::Activity => "Activity", Self::Settings => "Settings" }
}
}
mod ui { slint::include_modules!(); }
fn main() -> Result<(), slint::PlatformError> {
let app = ui::App::new()?;
slint_kit::init_form_validation!(ui, app);
let selection = slint_kit::bind_select!(ui, app, vec![
SelectOption::new(Destination::Overview, "Overview"),
SelectOption::new(Destination::Activity, "Activity"),
SelectOption::new(Destination::Settings, "Settings"),
], Some(Destination::Overview), Ownership::Local);
let weak = app.as_weak();
selection.on_intent(move |intent| {
if let Some(app) = weak.upgrade() {
app.set_selected_label(match intent {
SelectionIntent::Commit(key) => key.label(),
SelectionIntent::Clear => "No selection",
}.into());
}
});
selection.open();
let persistent = selection.clone();
app.on_select_activate(move |token, generation| {
persistent.activate(token, generation);
persistent.open();
});
app.run()
}
Cargo.toml et build.rs
Cargo.toml
[package]
name = "slint-kit-select-keyboard-example"
version = "0.1.0"
edition = "2024"
rust-version = "1.92"
license = "GPL-3.0-or-later"
publish = false
[dependencies]
slint-kit = "=0.3.0"
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
Placez-le dans le contrôle qui détient le focus, ou appelez handle-key(event) depuis une primitive de déclenchement. Reliez ses callbacks au contrôleur avec le même SelectState.
Il transforme les touches en NavigationStep, CloseReason, activation par token et recherche incrémentale. Le contrôleur conserve la sélection, l’identité et les règles de saut des éléments désactivés ; tab-navigation retourne un EventResult.
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

// Public label overrides localize this fixture; toolkit/host defaults keep their language.
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitOption, KitSelectKeyboard, KitSelectTrigger, KitTheme, KitThemes, SelectionAvailability } from "@kit/kit.slint";
export component Example inherits Window {
title: "KitSelectKeyboard — exemple";
preferred-width: 420px;
preferred-height: 340px;
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: "Clavier de sélection"; color: root.theme.text-primary; font-size: 20px * root.theme.text-scale; font-weight: 600; }
KitSelectKeyboard { init => { self.focus(); } state: { open: true, generation: 1, active-index: 0, active: { present: true, token: 11 }, selected: { present: true, token: 11 }, selection-availability: SelectionAvailability.available }; navigate(step) => { root.status = "Navigation au clavier demandée"; } activate(token, generation) => { root.status = "Activation demandée pour l’identifiant " + token; } VerticalLayout { spacing: 8px; KitSelectTrigger { theme: root.theme; state: { open: true, generation: 1, active-index: 0, active: { present: true, token: 11 }, selected: { present: true, token: 11 }, selection-availability: SelectionAvailability.available }; accessible-name: "Navigation du projet"; Text { text: "Vue d’ensemble"; color: root.theme.text-primary; vertical-alignment: center; font-size: 14px * root.theme.text-scale; } } Rectangle { background: root.theme.surface-raised; border-color: root.theme.border-subtle; border-width: 1px; border-radius: 8px; VerticalLayout { padding: 6px; spacing: 4px; for row in [{ token: 11, generation: 1, label: "Vue d’ensemble", description: "Résumé du projet", disabled: false }, { token: 23, generation: 1, label: "Activité", description: "Modifications récentes", disabled: false }, { token: 38, generation: 1, label: "Réglages", description: "Préférences du projet", disabled: false }]: KitOption { theme: root.theme; option-data: row; active: row.token == 11; selected: row.token == 11; height: 42px; Text { text: row.label; color: root.theme.text-primary; font-size: 14px * root.theme.text-scale; vertical-alignment: center; horizontal-alignment: left; } } } } } }
if root.status != "": Text { text: root.status; color: root.theme.text-secondary; font-size: 12px * root.theme.text-scale; wrap: word-wrap; }
}
}
API publique
Hérite de FocusScope.
Propriétés
| Nom | Type | Sens |
|---|---|---|
state |
SelectState |
in |
dismiss-on-system-back |
bool |
in |
Types et variantes
| Type | Déclaration |
|---|---|
enum CloseReason |
escape, outside-press, system-back, trigger-toggle, programmatic, host-closed |
enum NavigationStep |
next, previous, first, last, page-next, page-previous |
enum SelectionAvailability |
absent, available, unavailable |
struct SelectionRef |
present: bool, token: int |
struct SelectState |
selection-availability: SelectionAvailability, selected: SelectionRef, active: SelectionRef, open: bool, active-index: int, generation: int |
Signaux
open-requested()navigate(NavigationStep)activate(int, int)dismiss(CloseReason)typeahead(string)tab-navigation(bool) → EventResult
Fonctions
handle-key(event: KeyEvent) → EventResult