PBToolboxAI v2 ← Site

listbar — u_pbt_listbar #

← Référence des composants · Sommaire du guide

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.


En bref #

Userobjectu_pbt_listbar
Classes d'itemsn_pbt_listbar_section (section) → n_pbt_listbar_item (entrée)
Sert àRemplacer un menu latéral bricolé à coups de boutons par une navigation structurée, thémée et repliable
Options opt-inib_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.


Démarrage rapide #

// event open de la fenetre

uo_nav.of_add_section(/*key*/ "nav", /*titre*/ "Navigation")
uo_nav.of_add_item(/*keys*/ "nav/accueil",   /*libelle*/ "Accueil",   /*icone*/ "mono:img\home.svg")
uo_nav.of_add_item(/*keys*/ "nav/documents", /*libelle*/ "Documents", /*icone*/ "mono:img\doc.svg")
uo_nav.of_add_item(/*keys*/ "nav/recherche", /*libelle*/ "Recherche", /*icone*/ "mono:img\find.svg")

uo_nav.of_add_section(/*key*/ "config", /*titre*/ "Parametres")
uo_nav.of_add_item(/*keys*/ "config/preferences", /*libelle*/ "Preferences", /*icone*/ "mono:img\gear.svg")

// La selection se pose sur l'ENTREE, par son chemin complet
uo_nav.of_select_item("nav", "accueil")
// event ue_selection_changed de uo_nav : (string as_from_keys, string as_keys)
choose case as_keys
    case "nav/accueil"       ; of_ouvrir_accueil()
    case "nav/documents"     ; of_ouvrir_documents()
    case "config/preferences"; of_ouvrir_preferences()
end choose

Deux niveaux, un chemin obligatoire #

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.

// Composant  ->  section        ->  entree      ->  propriete
uo_nav        .of_section("nav") .of_item("docs") .is_text = "Documents"

Les events portent eux aussi le chemin complet, et l'entrée quittée avec : ue_selection_changed(as_from_keys, as_keys).


Propriétés #

PropriétéTypeDéfautRôle
ib_collapsedbooleanfalsetrue replie la barre en rail d'icônes : les libellés disparaissent, les icônes restent cliquables
ib_auto_widthbooleanfalseOpt-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_reorderablebooleanfalseOpt-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_selectionbooleantrueDemander 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_stylestringfluentStyle visuel du composant (constantes THEME_STYLE_*)
is_theme_modestringlightVariante claire ou sombre (constantes THEME_MODE_*)
il_theme_accentlong-1Couleur d'accent de ce composant (-1 = accent du thème)
is_tooltipstring""Info-bulle simple affichée au survol du composant
is_super_tooltip_titlestring""Titre de l'info-bulle enrichie (prend le pas sur is_tooltip)
is_super_tooltip_textstring""Texte de l'info-bulle enrichie (balisage riche accepté)
is_super_tooltip_imagestring""Image de l'info-bulle enrichie

Propriétés d'une section — n_pbt_listbar_section #

PropriétéTypeDéfautRôle
is_titlestring""Titre de la section. Accepte le balisage riche. Un titre vide n'affiche aucune ligne d'en-tête : la section devient un simple regroupement invisible
ib_collapsedbooleanfalseAccordéon : true replie les entrées de cette section. L'en-tête reste visible, son chevron pivote

Propriétés d'une entrée — n_pbt_listbar_item #

PropriétéTypeDéfautRôle
is_textstring""Libellé de l'entrée, modifiable à chaud sans reconstruire la barre. Accepte le balisage riche
is_imagestring""Icône, modifiable à chaud (formes acceptées : chemin, mono:, tint:, ressource de DLL)
ib_enabledbooleantruefalse grise l'entrée et bloque son clic
ib_visiblebooleantruefalse masque l'entrée sans la retirer de la barre
of_is_selected ( ) → boolean——Cette entrée est-elle la sélectionnée ? Lecture seule, et volontairement : la sélection est un état de la barre entière, pas un drapeau par entrée. Pour la poser, of_select sur le composant — qui lève toujours l'événement
is_tooltipstring""Info-bulle simple affichée au survol de l'item
is_super_tooltip_titlestring""Titre de l'info-bulle enrichie de l'item (prend le pas sur is_tooltip)
is_super_tooltip_textstring""Texte de l'info-bulle enrichie de l'item (balisage riche accepté)
is_super_tooltip_imagestring""Image de l'info-bulle enrichie de l'item

Méthodes #

Sur le composant #

MéthodeRôle
of_add_section (string as_key, string as_text)Ajoute une section. Renvoie 0 (-5 sur un argument invalide, -2 si le composant n'est pas créé), comme tout geste de structure : le handle vient d'of_section("nav") quand vous voulez poser une propriété
of_insert_section (string as_key, string as_text, integer ai_index)Ajoute une section au rang demandé (première position = 0) plutôt qu'à la fin. L'index compte des sections, pas des lignes. Un nom déjà pris est laissé tel quel : deux sections sous un même nom rendraient ambiguë l'adresse de chacune de leurs entrées. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
of_move_section (string as_key, integer ai_index)Déplace une section au rang ai_index, avec ses entrées. Déplacer l'en-tête seul larguerait ses entrées dans la section qui se retrouve au-dessus d'elles. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
of_remove_section (string as_key)Retire une section et tout ce qu'elle contient. La vider en gardant ses entrées les rendrait orphelines : elles porteraient un identifiant de section qui ne nomme plus rien. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
of_section (string as_key)Handle d'une section existante (créé au premier accès)
of_add_item (string as_keys, string as_text, string as_image)Ajoute une entrée à son adresse, "nav/accueil" : la section où elle atterrit, puis son propre identifiant. Renvoie 0 (-5 sur un argument invalide, -2 si le composant n'est pas créé) — -5 si le parent n'est pas une section, plutôt que de laisser l'entrée disparaître. Une surcharge omet l'icône
of_item (string as_keys)Handle d'une entrée, par son adresse (créé au premier accès)
of_insert_item (string as_keys, string as_text, integer ai_index)Insère une entrée à la position ai_index dans sa section. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
of_insert_item (string as_keys, string as_text, string as_image, integer ai_index)Idem, avec l’icône de l’entrée : of_add_item en prend une, insérer doit pouvoir en prendre une aussi. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
of_move_item (string as_keys, integer ai_index)Déplace une entrée existante dans sa section, en conservant son état. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
of_remove_item (string as_keys)Retire une entrée désignée par son couple section / identifiant. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
of_clear ( )Vide la barre : toutes les sections et toutes les entrées. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé
of_select_item (string as_keys)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. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
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. Renvoie 0 une fois appliqué, -5 sur un argument invalide (clé vide, adresse fausse), -2 si le composant n'est pas créé
of_clear_selection ( )Ne laisse aucune entrée sélectionnée. Annoncé comme n'importe quel autre déplacement. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé
of_selected_key ( )Adresse de l'entrée sélectionnée — "nav/docs", "" si aucune. C'est exactement ce que ue_selection_changed vous remet : une comparaison est une comparaison, et non un recollage. Toujours l'entrée courante : un clic et of_select_item repassent tous deux par l'event
of_reset ( )Vide la barre puis ramène le composant à son état neuf. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé
of_set_redraw (boolean)Regroupe une rafale de modifications en un seul rendu. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé
of_save_as_png (string) · of_save_as_jpg (string)Exporte le rendu en image. Renvoie 0 une fois l'image écrite, -4 si l'écriture échoue, -2 si le composant n'est pas créé

Sur une section — n_pbt_listbar_section #

MéthodeRôle

Événements #

ÉvénementDéclenché quand
ue_selection_changed (string as_from_keys, string as_keys)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)
ue_section_toggled (string as_key, boolean ab_collapsed)L'utilisateur plie ou déplie une section par son en-tête
ue_item_reordered (string as_keys, integer ai_index)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
ue_selection_changing (string as_from_keys, string as_keys) → booleanAnnulable, 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)

Exemples #


uo_nav.of_set_redraw(false)

uo_nav.of_add_section("dossiers", "Dossiers")
uo_nav.of_add_item("dossiers/recents",  "Recents",  "mono:img\clock.svg")
uo_nav.of_add_item("dossiers/clients",  "Clients",  "mono:img\user.svg")
uo_nav.of_add_item("dossiers/archives", "Archives", "mono:img\box.svg")

uo_nav.of_add_section("outils", "Outils")
uo_nav.of_add_item("outils/import", "Importer", "mono:img\import.svg")
uo_nav.of_add_item("outils/export", "Exporter", "mono:img\export.svg")

uo_nav.of_set_redraw(true)
uo_nav.of_select_item("dossiers", "recents")

Rail repliable qui libère la place #

// 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

Accordéon : replier une section #

// Replier la section des archives, rarement utilisee
uo_nav.of_section("archives").ib_collapsed = true
// event ue_section_toggled de uo_nav : (string as_keys, boolean ab_collapsed)
of_enregistrer_preference("section_" + as_keys, String(ab_collapsed))

Réagir à la navigation #

// event ue_selection_changed de uo_nav : (string as_from_keys, string as_keys)
// L'adresse porte les deux niveaux : deux sections peuvent avoir une entree "liste".
n_pbt_utils lnv_utils   // autoinstantiate : rien a creer, rien a detruire
string ls_ids[]

if lnv_utils.of_split_path(as_keys, ls_ids) < 2 then return
choose case ls_ids[1]
    case "dossiers" ; of_ouvrir_dossier(ls_ids[2])
    case "outils"   ; of_lancer_outil(ls_ids[2])
end choose

Refuser un changement de sélection #

// 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_keys, string as_keys)
// Renvoyer FALSE garde l'utilisateur sur l'entree qu'il quitte.
if of_saisie_en_cours(as_from_keys) then
    MessageBox("Saisie", "Terminez la fiche en cours avant de naviguer.")
    return false
end if
return true

Mettre une entrée à jour à chaud #

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

Sélection pilotée depuis le code #

// Poser la selection ailleurs : le bandeau d'accent suit
uo_nav.of_select_item("dossiers", "clients")

// Ou l'effacer completement
uo_nav.of_clear_selection()

Reconstruire la barre #

// of_clear vide sections et entrees ; of_reset y ajoute les defauts du composant
uo_nav.of_clear()
of_construire_menu_selon_profil()

Bonnes pratiques #

Hérité du socle commun #

Ces membres existent sur tous les composants visuels — ils ne sont pas propres à celui-ci. Ils sont détaillés une seule fois, dans les chapitres transverses ; cette table dit seulement où les lire.

MembresRôleDétaillé dans
of_count · of_keys_at · of_hasParcourir ce que le composant contient3.2 Les items
of_resetRemettre le composant à zéro3.6 Remettre un composant à zéro : of_reset()
of_register_shortcut · of_clear_shortcutsRaccourcis clavier du composant3.5 Les raccourcis clavier
of_is_created · of_is_ready · of_get_last_errorS'il est né, s'il est prêt, ce qui a échoué3.7 Diagnostic
of_save_as_png · of_save_as_jpgExporter le rendu en image3.8 Exporter le rendu en image
of_set_redrawGrouper les modifications en un seul repaint3.10 Bonnes pratiques
of_preload_iconsIcônes affichées sans délaiAffichage instantané : of_icon
of_set_translationTraduire un libellé du composant5.2 Adapter un libellé : of_set_translation
of_focus_webviewDonner le focus au composant6.4 Clavier et focus
of_print · of_print_to_pdfImprimer, ou écrire un PDF6.9 Imprimer

Deux aides ne sont pas héritées : of_icon et of_escape_markup vivent sur n_pbt_utils. Déclarez-en une — n_pbt_utils lnv_utils, rien à créer — et appelez-les dessus.

← Référence des composants · Sommaire du guide