PBToolboxAI v5 ← 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, ib_search

ib_auto_width a ici un sens particulier : 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 ; ib_auto_width se relit toujours tel que vous l'avez posé.


Démarrage rapide #

// event open de la fenetre

// Une section, puis ses entrees : chaque entree s'adresse par section/entree
uo_nav.of_add_section(/*key*/ "nav", /*text*/ "Navigation")
uo_nav.of_add_item(/*keys*/ "nav/home",   /*text*/ "Home",      /*image*/ "mono:img\home.svg")
uo_nav.of_add_item(/*keys*/ "nav/docs",   /*text*/ "Documents", /*image*/ "mono:img\doc.svg")
uo_nav.of_add_item(/*keys*/ "nav/search", /*text*/ "Search",    /*image*/ "mono:img\find.svg")

// Une deuxieme section, avec une seule entree
uo_nav.of_add_section(/*key*/ "settings", /*text*/ "Settings")
uo_nav.of_add_item(/*keys*/ "settings/prefs", /*text*/ "Preferences", /*image*/ "mono:img\gear.svg")

// La selection se pose sur l'ENTREE, par son adresse : la section puis l'entree
uo_nav.of_select_item(/*keys*/ "nav/home")

// of_select_item leve ue_selection_changed, comme un clic : la premiere page s'ouvre la
// event ue_selection_changed de uo_nav : (string as_from_keys, string as_keys)
choose case as_keys
    case "nav/home"       ; of_open_home()
    case "nav/docs"       ; of_open_documents()
    case "settings/prefs" ; of_open_preferences()
end choose

Deux niveaux, une adresse #

Un identifiant d'entrée n'est unique que dans sa section : une entrée se désigne donc par son adresse, la section puis l'entrée jointes par / — "nav/docs". C'est le composant qui la reçoit (of_item, of_select_item, of_remove_item…) ; une section, elle, se désigne par sa seule clé (of_section("nav")). Voir Hiérarchies.

// Une section par sa cle, une entree par son adresse
uo_nav.of_section(/*key*/ "nav").is_title = "Navigation"
uo_nav.of_item(/*keys*/ "nav/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 : titres de section et libellés laissent place à un filet entre les sections, et toutes les entrées restent visibles, même celles d'une section repliée (le pli revient à la sortie du rail). Une entrée sans icône montre son initiale, et chaque entrée dit son libellé au survol
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_selectionbooleanfalseOpt-in : demander avant que la sélection ne bouge — un geste de l'utilisateur et of_select_item / of_clear_selection (déclenche ue_selection_changing, qui peut refuser ; un ordre refusé renvoie -4). Désactivé par défaut, comme tout événement annulable de la bibliothèque : posez true quand vous devez pouvoir refuser (saisie non enregistrée). Chaque question d'un geste coûte un aller-retour vers PowerBuilder (~35 ms)
ib_searchbooleanfalseOpt-in : un champ de recherche en haut de la barre. Ce que l'utilisateur tape filtre les entrées (is_filter, ue_filter_changed) ; Ctrl+F atteint le champ, Échap le vide, Flèche bas descend sur la première entrée, Entrée choisit la première correspondance. Pas dessiné dans le rail (pas de place) : is_filter s'y applique quand même
is_filterstring""Le texte qui filtre la barre, lu en direct : les entrées dont le libellé — ou le titre de la section — le contient, casse et accents ignorés. Une section qui contient une correspondance s'affiche ouverte, son pli intact ; une section sans correspondance disparaît tant que le filtre tient. Posé par votre code, il ne lève rien (une valeur, comme SetFilter) ; tapé par l'utilisateur, ue_filter_changed. Pendant qu'il filtre, un titre ne se plie pas et une entrée ne se glisse pas. En démonstration, les six entrées dessinées se comptent sans le filtre : une recherche n'atteint jamais une septième
is_theme_stylestring""Style visuel du composant (constantes THEME_STYLE_*) ; vide = celui de l'application, suivi à chaque changement
is_theme_modestring""Variante claire ou sombre (constantes THEME_MODE_*) ; vide = celle de l'application, suivie à chaque changement
il_theme_accentlong-1Couleur d'accent de ce composant (-1 = l'accent de l'application, ou celui 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 ; un espace la sépare de la section du dessus (un filet en rail), et elle ne se replie plus — personne ne pourrait la rouvrir
ib_collapsedbooleanfalseAccordéon : true replie les entrées de cette section. L'en-tête reste visible, son chevron pivote ; ue_section_toggled suit, comme pour un clic sur l'en-tête
ib_pinnedbooleanfalsetrue épingle la section en bas de la barre (Paramètres, Aide) : un pied qui reste visible pendant que le reste de la barre défile, poussé en bas quand la place ne manque pas, et en bas du rail aussi. Plusieurs sections épinglées s'empilent dans leur ordre. Seul le dessin change : la disposition (of_get_layout) garde l'ordre des sections, et la flèche Bas passe de la dernière entrée du haut à la première du pied
is_imagestring""Icône devant le titre de la section (formes acceptées : chemin, mono:, tint:, ressource de DLL). Une chaîne vide la retire
is_tooltipstring""Info-bulle simple affichée au survol du titre de la section
is_super_tooltip_titlestring""Titre de l'info-bulle enrichie du titre de la section (prend le pas sur is_tooltip)
is_super_tooltip_textstring""Texte de l'info-bulle enrichie de la section (balisage riche accepté)
is_super_tooltip_imagestring""Image de l'info-bulle enrichie de la section
il_accentlong-1Accent de cette section, c'est-à-dire de son titre, et de rien d'autre : ses entrées gardent le leur (-1 = celui du composant)
il_back_colorlong-1Fond du titre de la section, en RGB(r,v,b) (-1 = celui du composant)
il_text_colorlong-1Couleur du texte du titre de la section (-1 = celle du composant)
il_back_color_hoverlong-1Fond du titre sous le pointeur (-1 = celui du composant)
il_text_color_hoverlong-1Couleur du texte du titre sous le pointeur (-1 = celle du composant)

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 : elle reste en place et ne répond plus à rien — ni clic, ni Entrée, ni clic droit, et les flèches la sautent ; son info-bulle s'affiche toujours, pour dire pourquoi. Votre code ne peut pas la sélectionner non plus (of_select_item rend -5) ; griser l'entrée déjà sélectionnée la garde sélectionnée
ib_visiblebooleantruefalse masque l'entrée sans la retirer de la barre. Une entrée masquée ne peut pas devenir la sélection (of_select_item rend -5) ; masquer celle qui est sélectionnée la garde sélectionnée, et la remontrer la rend telle quelle
is_badgestring""Pastille de compteur en fin d'entrée ("12" non lus), aux couleurs de pastille du thème ; en rail, sur le coin de l'icône. Tout texte court, balisage accepté. Une chaîne vide la retire
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_item sur le composant
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
il_accentlong-1Accent de cette entrée : le liseré qui la marque quand elle est sélectionnée le prend (-1 = celui du composant). Pour « cette entrée en rouge », il_back_color / il_text_color
il_back_colorlong-1Fond propre à l'entrée, en RGB(r,v,b) (-1 = ce que donne le thème)
il_text_colorlong-1Couleur du texte de l'entrée (-1 = ce que donne le thème)
il_back_color_hoverlong-1Fond de l'entrée sous le pointeur (-1 = ce que donne le thème)
il_text_color_hoverlong-1Couleur du texte de l'entrée sous le pointeur (-1 = ce que donne le thème)

Méthodes #

Sur le composant #

MéthodeRôle
of_add_section (string as_key, string as_text)Ajoute une section à la fin de la barre. Un texte vide n'affiche aucune ligne de titre. Le handle vient d'of_section("nav") quand vous voulez poser une propriété. Renvoie 0 une fois appliqué, -5 si la clé est vide, déjà prise ou contient / ou `, -2` si le composant n'est pas créé
of_insert_section (string as_key, string as_text, integer ai_index)Ajoute une section au rang demandé (première position = 1) plutôt qu'à la fin. L'index compte des sections, pas des lignes. Un nom déjà pris est refusé : deux sections sous un même nom rendraient ambiguë l'adresse de chacune de leurs entrées. Renvoie 0 une fois appliqué, -5 si la clé est vide, déjà prise ou contient / ou `, -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 pour une section que cette barre n'a jamais ajoutée, -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. Si la sélection y était, ue_selection_changed annonce qu'il n'y en a plus. Renvoie 0 une fois appliqué, -5 pour une section que cette barre n'a jamais ajoutée, -2 si le composant n'est pas créé
of_section (string as_key)Handle d'une section, par sa clé : son titre, son icône, son pli et ses couleurs se posent par lui (créé au premier accès). Une entrée, elle, s'atteint depuis le composant par son adresse (of_item)
of_add_item (string as_keys, string as_text, string as_image)Ajoute une entrée à son adresse, "nav/home" : la section où elle atterrit, puis son propre identifiant. Une surcharge omet l'icône. Renvoie 0 une fois ajoutée, -5 si la section n'a pas été ajoutée par cette barre, si l'adresse est déjà prise ou si la clé contient `, -2` si le composant n'est pas créé
of_item (string as_keys)Handle d'une entrée, par son adresse (créé au premier accès). Une adresse qui n'est pas section/entrée donne un handle qui ne nomme rien : ce qui s'écrit par lui ne fait rien (une section s'atteint par of_section)
of_insert_item (string as_keys, string as_text, integer ai_index)Insère une entrée à la position ai_index dans sa section (première position = 1). Renvoie 0 une fois ajoutée, -5 si la section n'a pas été ajoutée par cette barre, si l'adresse est déjà prise ou si la clé contient `, -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 ajoutée, -5 si la section n'a pas été ajoutée par cette barre, si l'adresse est déjà prise ou si la clé contient `, -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 pour une adresse que cette barre n'a jamais ajoutée, -2 si le composant n'est pas créé
of_remove_item (string as_keys)Retire une entrée désignée par son adresse. Si c'était la sélection, ue_selection_changed annonce qu'il n'y en a plus. Renvoie 0 une fois appliqué, -5 pour une adresse que cette barre n'a jamais ajoutée, -2 si le composant n'est pas créé
of_clear ( )Vide la barre : toutes les sections et toutes les entrées. Si une entrée était sélectionnée, ue_selection_changed annonce qu'il n'y en a plus (adresse vide) ; ue_layout_changed n'est pas levé, vous reconstruisez. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé
of_select_item (string as_keys)Sélectionne une entrée, comme un clic sur elle : avec ib_veto_selection actif, ue_selection_changing est posée d'abord ; puis ue_selection_changed suit, comme pour un clic (juste après votre script, depuis la file d'événements), et of_selected_key() lu juste après rend déjà la nouvelle adresse. Entrée déjà sélectionnée : rien n'est demandé ni levé. Renvoie 0 une fois sélectionnée (ou déjà sélectionnée), -4 si votre ue_selection_changing a refusé (rien ne bouge), -5 pour une adresse que cette barre n'a jamais ajoutée, une entrée masquée, une entrée grisée ou une entrée que le plafond de démonstration ne dessine pas — lu AVANT que la question ne soit posée —, -2 si le composant n'est pas créé. ue_item_invoked n'est pas levé : il répond à un geste de l'utilisateur
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 lève ue_layout_changed une fois quand elle change quelque chose, jamais ue_section_toggled : un pli restauré est un état rendu, pas un pli. Renvoie 0 une fois appliqué, -5 sur un texte vide ou qui n'est pas un objet JSON (un fichier tronqué) : rien n'est envoyé ; le pli d'une section absente est ignoré, -2 si le composant n'est pas créé
of_clear_selection ( )Ne laisse aucune entrée sélectionnée, comme tout déplacement : avec ib_veto_selection actif, ue_selection_changing est posée d'abord, puis ue_selection_changed suit avec une adresse vide. Rien de sélectionné déjà : rien n'est demandé ni levé. Renvoie 0 une fois appliqué, -4 si votre ue_selection_changing a refusé (l'entrée reste sélectionnée), -2 si le composant n'est pas créé
of_from_datastore (datastore ads)Construit la barre depuis les lignes d'un DataStore — ou d'un DataWindow, d'un DataWindowChild, même appel : une ligne = une entrée, le menu d'une application lu dans sa table de droits. Une colonne joue un rôle quand elle en porte le nom (section, section_text, key, text, image, badge, enabled) ou quand of_map le dit ; ROLE_SECTION est obligatoire. Le chargement remplace les entrées : les sections que vous avez déclarées gardent titre, icône, pli et épingle, et une section que les lignes nomment sans que la barre la tienne s'ajoute à la fin, dans l'ordre des lignes, titrée par ROLE_SECTION_TEXT (sinon par sa clé). Sans ROLE_KEY, la clé d'une entrée est son numéro de ligne. ROLE_ENABLED grise une entrée sur 0, N, F, false, no ou off. Une ligne dont la section ou la clé est vide, contient / ou `, ou répète une adresse est écartée : l'appel rend quand même 0 et of_get_last_error la nomme. Une sélection dont l'entrée ne revient pas part, avec ue_selection_changed. Renvoie 0 une fois chargé, -5 si le DataStore n'est pas valide ou n'a aucune colonne, -2` si le composant n'est pas créé
of_map (string as_role, string as_column)Donne un rôle à une colonne du DataStore quand son nom ne le dit pas : of_map(u_pbt_listbar.ROLE_SECTION, "menu_group"). Rôles : ROLE_SECTION, ROLE_SECTION_TEXT (le titre d'une section que les lignes créent), ROLE_KEY, ROLE_TEXT, ROLE_IMAGE, ROLE_BADGE, ROLE_ENABLED. Avant ou après of_from_datastore : après, les lignes sont relues. Une colonne vide rend le rôle à la colonne qui en porte le nom. Renvoie 0 une fois posé, -5 si le rôle n'est pas une des constantes ROLE_ ou si la colonne n'est pas une colonne du DataStore du dernier chargement, -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, lue dans le composant : après un clic, et juste après of_select_item aussi
of_reset ( )Vide la barre puis ramène le composant à son état neuf. Si une entrée était sélectionnée, ue_selection_changed part avec une adresse vide ; ue_layout_changed n'est pas levé. 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
of_count ( )Nombre d'entrées de la section, masquées comprises
of_keys_at (long al_index)Adresse de l'entrée de rang al_index (à partir de 1) — "nav/docs", réinjectable telle quelle dans of_item
of_has (string as_key)La section contient-elle cette entrée ?

Événements #

ÉvénementDéclenché quand
ue_selection_changed (string as_from_keys, string as_keys)La sélection a bougé : l'utilisateur a choisi une entrée (clic, Entrée, Espace), votre code l'a déplacée (of_select_item, of_clear_selection — un ordre le lève aussi, comme SelectItem lève SelectionChanged), ou l'entrée sélectionnée est partie (of_remove_item, of_remove_section, of_clear, of_reset — as_keys est alors vide). 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 : clic sur son titre, Entrée sur le titre, ou les flèches Gauche / Droite (inversées de droite à gauche), ou votre code qui pose ib_collapsed d'une section
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, comme of_move_item. Conservez cet ordre pour rendre à l'utilisateur sa barre telle qu'il l'a laissée
ue_layout_changed (string as_layout_json)La disposition à conserver a changé : une entrée ou une section a bougé, une section a été pliée ou dépliée, quelque chose a été retiré, une disposition a été restaurée — par l'utilisateur ou par votre code. Levé une fois par vrai changement : un déplacement vers le rang déjà tenu ne lève rien ; of_set_layout le lève une fois quand la disposition appliquée change quelque chose. Porte la disposition entière, pas seulement ce qui a bougé : la conserver tient en une affectation. Les ajouts, le rail, of_clear et of_reset ne le lèvent pas : c'est de la construction, pas de l'arrangement
ue_item_rclicked (string as_keys, long al_x, long al_y)L'utilisateur a fait un clic droit sur une entrée — ou pressé la touche Menu, Maj+F10 sur elle : son adresse, "nav/docs", et al_x, al_y en pixels d'écran, ceux que prend of_show d'un contextmenu. Un événement par clic droit, et l'entrée n'est pas sélectionnée. Un menu PowerBuilder s'ouvre au pointeur de votre fenêtre : m_menu.PopMenu(parent.PointerX(), parent.PointerY()). Une entrée grisée ne lève rien
ue_item_invoked (string as_keys)L'utilisateur a invoqué une entrée — un clic, Entrée, Espace, Entrée dans le champ de recherche —, l'entrée déjà sélectionnée comprise : ouvrez (ou ramenez) sa page ici, et une feuille fermée par sa croix se rouvre depuis la barre. Un geste seulement : of_select_item ne le lève jamais. Après ue_selection_changed quand la sélection a bougé ; jamais pour une entrée grisée, ni pour un déplacement que ue_selection_changing a refusé
ue_filter_changed (string as_text)L'utilisateur a tapé dans le champ de recherche (ib_search) : as_text filtre désormais la barre ; Échap le vide. is_filter posé par votre code s'applique sans cet événement
ue_selection_changing (string as_from_keys, string as_keys) → booleanAnnulable, posé avant que la sélection ne bouge — un geste de l'utilisateur, of_select_item ou of_clear_selection —, et seulement quand ib_veto_selection = true (désactivé par défaut). Renvoyez false pour rester où vous êtes : rien ne bouge, et l'ordre de votre code renvoie -4
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 #

// Toute la barre en un seul rendu
uo_nav.of_set_redraw(/*on*/ false)

// Premiere section et ses trois entrees
uo_nav.of_add_section(/*key*/ "folders", /*text*/ "Folders")
uo_nav.of_add_item(/*keys*/ "folders/recent",    /*text*/ "Recent",    /*image*/ "mono:img\clock.svg")
uo_nav.of_add_item(/*keys*/ "folders/customers", /*text*/ "Customers", /*image*/ "mono:img\user.svg")
uo_nav.of_add_item(/*keys*/ "folders/archives",  /*text*/ "Archives",  /*image*/ "mono:img\box.svg")

// Deuxieme section et ses deux entrees
uo_nav.of_add_section(/*key*/ "tools", /*text*/ "Tools")
uo_nav.of_add_item(/*keys*/ "tools/import", /*text*/ "Import", /*image*/ "mono:img\import.svg")
uo_nav.of_add_item(/*keys*/ "tools/export", /*text*/ "Export", /*image*/ "mono:img\export.svg")

// Un seul rendu pour tout, puis la premiere entree est selectionnee
uo_nav.of_set_redraw(/*on*/ true)
uo_nav.of_select_item(/*keys*/ "folders/recent")

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_content.x     = uo_nav.x + al_width
uo_content.width = parent.width - uo_content.x

Accordéon : replier une section #

// Replier la section des dossiers, rarement utilisee
uo_nav.of_section(/*key*/ "folders").ib_collapsed = true
// event ue_section_toggled de uo_nav : (string as_key, boolean ab_collapsed)
// Retenir le pli choisi par l'utilisateur
of_save_preference("section_" + as_key, String(ab_collapsed))

Paramètres et Aide épinglés en bas #

Une section sans titre et épinglée : aucune ligne d'en-tête, deux entrées qui restent au pied de la barre même quand la navigation, plus longue que la fenêtre, défile. Un clic y sélectionne comme ailleurs : ue_selection_changed reçoit foot/settings.

// Une section SANS titre (aucune ligne d'en-tete), epinglee en bas de la barre :
// elle reste visible pendant que les entrees du dessus defilent
uo_nav.of_add_section(/*key*/ "foot", /*text*/ "")
uo_nav.of_add_item(/*keys*/ "foot/settings", /*text*/ "Settings", /*image*/ "mono:img\gear.svg")
uo_nav.of_add_item(/*keys*/ "foot/help",     /*text*/ "Help",     /*image*/ "mono:img\help.svg")
uo_nav.of_section(/*key*/ "foot").ib_pinned = true

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 "list".
// Local variables
n_pbt_utils lnv_utils   // autoinstantiate : rien a creer, rien a detruire
string ls_keys[]

// Decoupe l'adresse : [1] = la section, [2] = l'entree
if lnv_utils.of_split_path(/*keys*/ as_keys, /*out*/ ls_keys) < 2 then return
choose case ls_keys[1]
    case "folders" ; of_open_folder(ls_keys[2])
    case "tools"   ; of_run_tool(ls_keys[2])
end choose

Rouvrir la page de l'entrée courante #

ue_selection_changed ne dit que les déplacements : recliquer l'entrée déjà sélectionnée ne la déplace pas. Dans une application MDI dont l'utilisateur a fermé la feuille, c'est pourtant le geste qui doit la rouvrir — ue_item_invoked répond à chaque clic, l'entrée courante comprise.

// event ue_item_invoked de uo_nav : (string as_keys)
// Chaque clic ouvre la page de l'entree, meme deja selectionnee :
// une feuille fermee par sa croix se rouvre depuis la barre
of_open_sheet(as_keys)

Votre menu au clic droit d'une entrée #

// event ue_item_rclicked de uo_nav : (string as_keys, long al_x, long al_y)
// Local variables
m_entry lm_menu

// Un menu PowerBuilder s'ouvre au pointeur de la FENETRE ; al_x, al_y (pixels
// d'ecran) servent un menu de la bibliotheque : uo_menu.of_show(al_x, al_y)
lm_menu = create m_entry
lm_menu.m_root.PopMenu(parent.PointerX(), parent.PointerY())
destroy lm_menu

Rechercher dans la barre #

// Un champ de recherche en haut de la barre : Ctrl+F l'atteint, Echap le vide,
// Entree choisit la premiere correspondance
uo_nav.ib_search = true

// Le code filtre aussi : seules les entrees qui contiennent le texte restent
uo_nav.is_filter = "inv"

Construire le menu depuis une table de droits #

// Local variables
datastore lds_rights

// La table des droits de l'utilisateur : une ligne = une entree du menu
lds_rights = create datastore
lds_rights.DataObject = "d_menu_rights"
lds_rights.SetTransObject(SQLCA)
lds_rights.Retrieve()

// Les colonnes qui ne portent pas le nom d'un role sont nommees par of_map
uo_nav.of_map(/*role*/ u_pbt_listbar.ROLE_SECTION, /*column*/ "menu_group")
uo_nav.of_map(/*role*/ u_pbt_listbar.ROLE_SECTION_TEXT, /*column*/ "group_title")
uo_nav.of_map(/*role*/ u_pbt_listbar.ROLE_KEY, /*column*/ "menu_code")
uo_nav.of_map(/*role*/ u_pbt_listbar.ROLE_ENABLED, /*column*/ "allowed")

// Les entrees sont remplacees ; une ligne ecartee est dite par of_get_last_error
uo_nav.of_from_datastore(/*ads*/ lds_rights)
destroy lds_rights

Refuser un changement de sélection #

// La question est desactivee par DEFAUT : l'armer pour pouvoir refuser un deplacement
uo_nav.ib_veto_selection = true
// 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_has_unsaved_changes(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 #

// Local variables
n_pbt_listbar_item lnv_entry

// L'entree se designe par son adresse : la section, puis l'entree
lnv_entry = uo_nav.of_item(/*keys*/ "folders/recent")
lnv_entry.is_text  = "Recent (12)"
lnv_entry.is_image = "mono:img\clock_full.svg"
// Griser ou masquer selon les droits, sans reconstruire la barre
uo_nav.of_item(/*keys*/ "tools/import").ib_enabled = of_is_allowed("import")
uo_nav.of_item(/*keys*/ "tools/export").ib_visible = gb_expert_mode

Sélection pilotée depuis le code #

// Poser la selection ailleurs : le bandeau d'accent suit, et
// ue_selection_changed part comme pour un clic
uo_nav.of_select_item(/*keys*/ "folders/customers")

// 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_build_menu_for_profile()

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
of_set_property · of_get_property · of_component_namePiloter une propriété par son nom3.1 Le moteur de propriétés
is_accessible_name · is_accessible_descriptionLe nom et la description que dit un lecteur d'écran3.4 Propriétés et events optionnels

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