Barre de navigation latérale : des sections repliables en accordéon contenant des entrées à icône, avec bandeau d'accent sur l'entrée courante et repli en rail d'icônes.
▶ Le voir en vrai — Application de démonstration, tuile Listbar : l'aperçu, le code qui le produit et cette page, côte à côte.
Remplacer un menu latéral bricolé à coups de boutons par une navigation structurée, thémée et repliable
Options opt-in
ib_auto_width, ib_reorderable
C'est le seul composant de la bibliothèque à publier ib_auto_width : sa largeur naturelle a un sens, puisque le rail replié est nettement plus étroit que la barre déployée. Le cas courant est d'ailleurs déjà couvert sans rien activer — ib_collapsed = true rétrécit la barre au rail, et lui rend sa largeur au dépliage.
Un identifiant d'entrée n'est unique que dans sa section : il n'existe donc aucun raccourci vers l'entrée. Tout accès passe par la section, ce qui rend l'écriture non ambiguë — voir Hiérarchies.
true replie la barre en rail d'icônes : les libellés disparaissent, les icônes restent cliquables
ib_auto_width
boolean
false
Opt-in : idem pour la largeur, y compris dépliée (la barre se cale sur le libellé le plus long). Le repli en rail, lui, se rétrécit déjà tout seul ; ue_auto_width suit dans les deux cas
ib_reorderable
boolean
false
Opt-in : l'utilisateur peut déplacer une entrée à la souris. Le déplacement reste dans sa section — un identifiant d'entrée n'est unique que là, donc traverser risquerait deux clés identiques (déclenche ue_item_reordered)
ib_veto_selection
boolean
true
Demander avant que la sélection ne se déplace (déclenche ue_selection_changing, qui peut refuser). Actif par défaut : ne rien scripter laisse toujours passer. Mettez-le à false pour supprimer l'aller-retour vers PowerBuilder (~35 ms) là où il se verrait — navigation clavier, sélection déplacée en boucle
is_theme_style
string
fluent
Style visuel du composant (constantes THEME_STYLE_*)
is_theme_mode
string
light
Variante claire ou sombre (constantes THEME_MODE_*)
il_theme_accent
long
-1
Couleur d'accent de ce composant (-1 = accent du thème)
is_tooltip
string
""
Info-bulle simple affichée au survol du composant
is_super_tooltip_title
string
""
Titre de l'info-bulle enrichie (prend le pas sur is_tooltip)
is_super_tooltip_text
string
""
Texte de l'info-bulle enrichie (balisage riche accepté)
Déplace une entrée existante dans sa section, en conservant son état
of_remove_item (string as_section, string as_id)
Retire une entrée désignée par son couple section / identifiant
of_clear ( )
Vide la barre : toutes les sections et toutes les entrées
of_select_item (string as_section, string as_id)
Sélectionne une entrée — strictement équivalent à un clic de l'utilisateur : ue_selection_changing est posée d'abord, puis ue_selection_changed annonce le déplacement
of_get_layout ( )
Relit la disposition courante en JSON : les sections dans l'ordre, chacune avec ses entrées dans l'ordre et son état replié. À stocker (fichier, base, registre) et à rendre par of_set_layout au démarrage suivant. La même paire porte les mêmes noms sur tous les composants réorganisables
of_set_layout (string as_layout_json)
Restaure une disposition lue par of_get_layout ou reçue par ue_layout_changed. Ce que la disposition ne nomme pas garde sa place à la fin : une disposition d'hier ne doit pas faire disparaître ce qui a été ajouté depuis. L'appliquer ne déclenche aucun event — c'est vous qui l'avez fournie
of_clear_selection ( )
Ne laisse aucune entrée sélectionnée. Annoncé comme n'importe quel autre déplacement
of_selected_key ( )
Identifiant de l'entrée sélectionnée, "" si aucune. Toujours l'entrée courante : un clic et of_select_item repassent tous deux par ue_selection_changed
of_selected_section ( )
Section qui porte l'entrée sélectionnée — un identifiant d'entrée n'est unique que dans sa section, c'est donc le couple qui désigne la sélection. "" si aucune
of_reset ( )
Vide la barre puis ramène le composant à son état neuf
of_set_redraw (boolean)
Regroupe une rafale de modifications en un seul rendu
La sélection a bougé — par clic ou par of_select_item. Mêmes arguments que ue_selection_changing : la question et son issue se lisent pareil, et le couple as_from_* désigne l'entrée quittée (vide si aucune)
L'utilisateur a fini de faire glisser une entrée. ai_index est son nouveau rang dans sa section, à partir de 1. Conservez cet ordre pour rendre à l'utilisateur sa barre telle qu'il l'a laissée
ue_layout_changed (string as_layout_json)
L'arrangement a changé — l'utilisateur a réorganisé quelque chose, ou votre propre code l'a fait. Porte la disposition entière, pas seulement ce qui a bougé : la conserver tient en une affectation
Annulable, posé avant que la sélection ne se déplace. Levé par défaut ; ib_veto_selection = false le supprime. Renvoyez false pour garder l'utilisateur où il est
ue_auto_width (long al_width)
Le composant a recalculé sa largeur idéale — nécessite ib_auto_width = true
ue_ready ( )
Le composant a fini de charger ; tout ce qui a été envoyé avant a été rejoué
ue_runtime_missing ( )
Le runtime WebView2 est absent : le composant reste vide
ue_bg_color (long al_color)
Le composant a calculé sa couleur de fond de thème ; l'userobject l'a déjà adoptée (backcolor)
// Replier en rail d'icones : la barre se retrecit d'elle-meme (et reprend sa
// largeur quand vous la depliez).
uo_nav.ib_collapsed = true
// event ue_auto_width de uo_nav : (long al_width)
// La barre vient d'adopter sa largeur ideale : recaler ce qui se trouve a droite.
uo_contenu.x = uo_nav.x + al_width
uo_contenu.width = parent.width - uo_contenu.x
// event ue_selection_changed de uo_nav : (string as_from_section, string as_from_id,
// string as_section, string as_id)
// La section fait partie de la cle : deux sections peuvent avoir une entree "liste".
choose case as_section
case "dossiers" ; of_ouvrir_dossier(as_id)
case "outils" ; of_lancer_outil(as_id)
end choose
// La question est posee par DEFAUT : rien a activer. Cette ligne fait l'inverse,
// elle la supprime quand l'arbitrage ne sert pas et que le cout se verrait.
uo_nav.ib_veto_selection = false
// event ue_selection_changing de uo_nav :
// (string as_from_section, string as_from_id, string as_section, string as_id)
// Renvoyer FALSE garde l'utilisateur sur l'entree qu'il quitte.
if of_saisie_en_cours(as_from_section, as_from_id) then
MessageBox("Saisie", "Terminez la fiche en cours avant de naviguer.")
return false
end if
return true
n_pbt_listbar_item lnv_entree
// Le chemin complet est obligatoire : composant -> section -> entree
lnv_entree = uo_nav.of_section("dossiers").of_item("recents")
lnv_entree.is_text = "Recents (12)"
lnv_entree.is_image = "mono:img\clock_full.svg"
// Griser ou masquer selon les droits, sans reconstruire la barre
uo_nav.of_section("outils").of_item("import").ib_enabled = of_a_le_droit("import")
uo_nav.of_section("outils").of_item("export").ib_visible = gb_mode_expert
Conservez le handle de section renvoyé par of_add_header dans une variable locale : c'est plus lisible que de rappeler of_section(...) à chaque entrée.
Utilisez mono: pour les icônes : elles se recolorent avec le thème, clair comme sombre, et restent lisibles une fois la barre repliée en rail.
Un titre de section vide sert de regroupement discret : les entrées sont espacées sans qu'aucune ligne d'en-tête n'apparaisse.
ib_collapsed rétrécit l'userobject au rail, mais il ne déplace pas vos autres contrôles : traitez ue_auto_width pour occuper la place libérée, sinon elle reste vide.
En mode rail, seules les icônes subsistent : renseignez une info-bulle sur chaque entrée pour que les libellés restent accessibles.
La question est posée par défaut : un ue_selection_changing laissé vide autorise toujours le déplacement, vous n'avez rien à faire. Coupez-la avec ib_veto_selection = false là où le clic est répété — navigation clavier, sélection pilotée en boucle — car chaque question coûte un aller-retour vers PowerBuilder.
ib_enabled = false vaut mieux que ib_visible = false quand l'entrée redeviendra disponible : le menu ne change pas de forme sous les yeux de l'utilisateur.