Liste de contenus pour Slint
KitContentList · Slint Kit 0.3.1
Liste Slint virtualisée avec titres, extraits et sélection.

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.
Sélectionnez un article à la souris, ou déplacez-vous avec les flèches et validez avec Entrée. Rust affiche le titre choisi.
ui/app.slint
export { KitFormValidation, HtmlInputKind, NumberInputFormat, KitInputConstraints, KitValidationResult, KitValidityState } from "@kit/kit.slint";
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitContentList, KitThemes, ContentItem, NavigationStep } from "@kit/kit.slint";
export { ContentItem, NavigationStep }
export component App inherits Window {
title: "Slint content list";
preferred-width: 580px; preferred-height: 390px;
max-width: 100000px; max-height: 100000px;
background: KitThemes.light.canvas;
in property <[ContentItem]> items;
in property <int> active-index: -1;
in property <string> selected-label: "Choose an article";
callback choose(int, int);
callback move(NavigationStep);
VerticalLayout {
padding: 24px; spacing: 16px;
list := KitContentList { height: 280px; items: root.items; generation: 1;
active-index: root.active-index;
activate(token, generation) => { root.choose(token, generation); }
navigate(step) => { root.move(step); }
}
Text { text: root.selected-label; color: KitThemes.light.text-primary; }
}
}
src/main.rs
// SPDX-License-Identifier: GPL-3.0-or-later
use slint::{ComponentHandle, ModelRc, VecModel};
use std::{cell::RefCell, rc::Rc};
mod ui {
slint::include_modules!();
}
fn next_index(current: Option<usize>, length: usize, step: ui::NavigationStep) -> usize {
use ui::NavigationStep::*;
let current = current.unwrap_or(0);
match step {
First => 0,
Last => length.saturating_sub(1),
Previous | PagePrevious => current.saturating_sub(1),
Next | PageNext => (current + 1).min(length.saturating_sub(1)),
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Article {
Setup,
State,
}
impl Article {
fn token(self) -> i32 {
match self {
Self::Setup => 11,
Self::State => 23,
}
}
fn title(self) -> &'static str {
match self {
Self::Setup => "Install Slint Kit",
Self::State => "Keep selection stable",
}
}
fn excerpt(self) -> &'static str {
match self {
Self::Setup => "Import a component and connect its Rust callback.",
Self::State => "Use an application key when the display order changes.",
}
}
}
const ARTICLES: [Article; 2] = [Article::Setup, Article::State];
#[derive(Default)]
struct State {
selected: Option<Article>,
active: Option<Article>,
}
fn publish(state: &RefCell<State>, app: &ui::App) {
let state = state.borrow();
let items = ARTICLES
.iter()
.map(|article| ui::ContentItem {
token: article.token(),
title: article.title().into(),
excerpt: article.excerpt().into(),
metadata: "Guide".into(),
link_label: "Select article".into(),
thumbnail: slint::Image::default(),
selected: state.selected == Some(*article),
disabled: false,
})
.collect::<Vec<_>>();
let index = ARTICLES
.iter()
.position(|a| Some(*a) == state.active)
.map_or(-1, |i| i as i32);
let label = state.selected.map_or("Choose an article".to_owned(), |a| {
format!("Selected: {}", a.title())
});
drop(state);
app.set_items(ModelRc::new(VecModel::from(items)));
app.set_active_index(index);
app.set_selected_label(label.into());
}
fn main() -> Result<(), slint::PlatformError> {
let app = ui::App::new()?;
slint_kit::init_form_validation!(ui, app);
let state = Rc::new(RefCell::new(State::default()));
publish(&state, &app);
let (model, weak) = (state.clone(), app.as_weak());
app.on_choose(move |token, generation| {
if generation != 1 {
return;
}
let Some(article) = ARTICLES.iter().copied().find(|a| a.token() == token) else {
return;
};
{
let mut state = model.borrow_mut();
state.selected = Some(article);
state.active = Some(article);
}
if let Some(app) = weak.upgrade() {
publish(&model, &app);
}
});
let weak = app.as_weak();
app.on_move(move |step| {
{
let mut state = state.borrow_mut();
let current = ARTICLES.iter().position(|a| Some(*a) == state.active);
state.active = Some(ARTICLES[next_index(current, ARTICLES.len(), step)]);
}
if let Some(app) = weak.upgrade() {
publish(&state, &app);
}
});
app.run()
}
Cargo.toml et build.rs
Cargo.toml
[package]
name = "slint-kit-content-list-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
Fournissez items, generation et active-index. Traitez activate(token, generation) dans Rust avec la clé applicative, puis navigate pour déplacer le focus. Donnez une hauteur bornée à la liste.
Chaque ContentItem fournit son titre, sa description, ses métadonnées et une vignette facultative. Les lignes sont rendues dans le viewport. Définissez empty-label pour un modèle vide.
Choisir entre une option intégrée et une composition personnalisée
Options partagées
label— propriété intégrée ; exemple de composition personnalisé
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 { KitContentList, KitTheme, KitThemes } from "@kit/kit.slint";
export component Example inherits Window {
title: "KitContentList — exemple";
preferred-width: 620px;
preferred-height: 410px;
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: "Liste de contenus"; color: root.theme.text-primary; font-size: 20px * root.theme.text-scale; font-weight: 600; }
KitContentList { empty-label: "Aucun article trouvé"; label: "Articles"; theme: root.theme; height: 260px; generation: 1; items: [{ token: 101, title: "Guide du design natif", excerpt: "Créez des interfaces qui trouvent naturellement leur place sur le bureau.", metadata: "Design · 5 min de lecture", link-label: "Lire l’article", selected: false, disabled: false }, { token: 205, title: "Préserver l’exactitude des valeurs métier", excerpt: "Utilisez des valeurs validées et des identités stables dans l’application.", metadata: "Ingénierie · 8 min de lecture", link-label: "Lire l’article", selected: false, disabled: false }]; }
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 Rectangle.
Propriétés
| Nom | Type | Sens |
|---|---|---|
theme |
KitTheme |
in |
items |
[ContentItem] |
in |
generation |
int |
in |
active-index |
int |
in |
label |
string |
in |
empty-label |
string |
in |
scroll-y |
length |
out |
Types et variantes
| Type | Déclaration |
|---|---|
struct ContentItem |
token: int, title: string, excerpt: string, metadata: string, link-label: string, thumbnail: image, selected: bool, disabled: bool |
enum NavigationStep |
next, previous, first, last, page-next, page-previous |
Signaux
activate(int,int)navigate(NavigationStep)
Fonctions
take-focus()