PBToolboxAI v1 ← Site

tab — u_pbt_tab #

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

Onglets modernes hébergeant de vrais contrôles PowerBuilder : bandeau repositionnable, icônes par onglet, onglets fermables, réordonnancement à la souris.

Le voir en vrai — Application de démonstration, tuile Tab : l'aperçu, le code qui le produit et cette page, côte à côte.


En bref #

Userobjectu_pbt_tab
Classe d'itemsn_pbt_tab_page (une page = un onglet)
Sert àRemplacer un tab PowerBuilder par un bandeau thémé, tout en conservant vos écrans existants comme pages
Options opt-inib_reorderable

L'argument clé : une page n'est pas une maquette HTML, c'est un dragobject PowerBuilder — un userobject, une DataWindow, un groupe de contrôles, voire un autre composant PBToolboxAI. Le composant se charge du positionnement, du redimensionnement et de l'affichage/masquage au changement d'onglet. Voir Héberger de vrais contrôles PowerBuilder.


Démarrage rapide #

// event open de la fenetre : chaque page est un controle PB deja pose sur la fenetre
uo_onglets.of_add_page("clients",  "Clients",  uo_page_clients)
uo_onglets.of_add_page("factures", "Factures", uo_page_factures, /*fermable*/ true)

// Une icone par onglet, posee sur le handle de la page
uo_onglets.of_item("clients").is_icon  = "mono:img\clients.svg"
uo_onglets.of_item("factures").is_icon = "mono:img\invoice.svg"

uo_onglets.of_select_page("clients")
// event ue_selection_changed de uo_onglets : (string as_from_id, string as_id)
of_charger_page(as_id)

Propriétés #

PropriétéTypeDéfautRôle
is_positionstring"top"Placement du bandeau : top, bottom (bande horizontale), start, end (bande verticale). Constantes POSITION_TOP, POSITION_BOTTOM, POSITION_START, POSITION_END. START/END sont logiques et suivent le sens d'écriture
is_overflow_modestring"menu"Ce que fait une bande trop petite pour ses onglets. menu (défaut) garde chaque onglet lisible : ceux qui ne tiennent plus sortent de la bande et le bouton ··· les liste tous, l'onglet actif restant toujours affiché. compact les garde tous dans la bande et les laisse se réduire, jusqu'à la place que demande un texte tronqué. Constantes OVERFLOW_MENU, OVERFLOW_COMPACT
ib_reorderablebooleanfalseOpt-in : l'utilisateur peut réordonner les onglets en faisant glisser leur en-tête à la souris (déclenche ue_tab_reordered)
ib_veto_selectionbooleantrueDemander avant de changer d'onglet actif (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
ib_veto_closebooleantrueDemander avant de fermer un onglet fermable (déclenche ue_tab_closing, qui peut refuser). Actif par défaut, même règle
ib_context_menubooleantrueMenu contextuel intégré sur un en-tête d'onglet : Fermer, Fermer les autres, Fermer à droite, Fermer tout, grisés quand ils n'ont pas de cible. Actif par défaut. Le clic droit sélectionne d'abord l'onglet visé : si l'application refuse le changement, aucun menu ne s'ouvre. Chaque fermeture passe par ue_tab_closing, une question par page : celle qui détient du travail non enregistré refuse seule et reste ouverte pendant que ses voisines partent. À false pour afficher votre propre menu depuis ue_rclicked
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 page — n_pbt_tab_page #

Obtenues par of_item(id), elles se modifient à chaud, sans reconstruire le bandeau.

PropriétéTypeDéfautRôle
is_titlestring""Libellé de l'onglet. Accepte le balisage riche
is_iconstring""Icône de l'onglet (formes acceptées : chemin, mono:, tint:, ressource de DLL). Vide = aucune icône
ib_enabledbooleantruefalse grise l'onglet et bloque sa sélection par l'utilisateur
ib_visiblebooleantruefalse masque l'onglet sans supprimer la page ; masquer l'onglet actif en active un voisin
ib_closablebooleanfalseCroix de fermeture sur cet onglet. Rarement connu au moment de l ajout : il passe a true des que le document tenu par la page est enregistre, a false pendant qu un traitement y tourne
is_shortcutstring""Raccourci clavier qui active cet onglet : "Ctrl+2", "Alt+F", "F6"… Il répond où que soit l'utilisateur dans la fenêtre, page hébergée comprise — le raccourci est tenu par la DLL, pas par la barre d'onglets. Sélectionner ainsi est un clic : ue_selection_changing est posée, ue_selection_changed suit. "" le retire
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 #

MéthodeRôle
of_add_page (string as_id, string as_title, dragobject ado_page)Ajoute un onglet non fermable, sans icône, et héberge le contrôle
of_add_page (string as_id, string as_title, dragobject ado_page, boolean ab_closable)Idem, avec croix de fermeture si ab_closable
of_add_page (string as_id, string as_title, dragobject ado_page, boolean ab_closable, string as_icon)Idem, avec l'icône posée dans la foulée (l'onglet s'affiche d'emblée complet)
of_insert_page (string as_id, string as_title, dragobject ado_page, integer ai_index)Ajoute la page puis la déplace à la position ai_index
of_insert_page (string as_id, string as_title, dragobject ado_page, boolean ab_closable, string as_icon, integer ai_index)Idem, en disant ce que dit of_add_page : si l’onglet se ferme, et son icône
of_move_page (string as_id, integer ai_index)Déplace un onglet existant ; sa page hébergée et la sélection sont conservées
of_select_page (string as_id)Active un onglet — strictement équivalent à un clic utilisateur (passe par ue_selection_changing puis ue_selection_changed)
of_remove_page (string as_id)Retire l'onglet et rend le contrôle à sa fenêtre d'origine, masqué. Le contrôle reste utilisable et peut être hébergé ailleurs
of_selected_key ( )Identifiant de l'onglet actif, "" si aucun
of_get_layout ( )Relit la disposition courante en JSON : l'ordre des onglets et la visibilité de chacun. À 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_item (string as_id)Handle n_pbt_tab_page de la page (créé au premier accès)
of_refresh_page (string as_id)Rafraîchit le rendu d'une page construite hors écran, sans scintillement
of_relayout ( )Republie la zone de page pour que le contrôle hébergé soit repositionné (utile après un affichage différé)
of_preload_icons (string as_icons[])Préchauffe un lot d'icônes au démarrage : un onglet ouvert plus tard affiche son icône instantanément
of_reset ( )Vide le bandeau : chaque page hébergée est rendue à sa fenêtre d'origine, puis le composant revient à son état neuf
of_set_redraw (boolean)Regroupe une rafale de modifications en un seul rendu
of_save_as_png (string) · of_save_as_jpg (string)Exporte le rendu en image

of_add_page renvoie un code négatif si l'identifiant est vide, déjà utilisé, ou si le contrôle passé n'est pas valide.

Quand il y a trop d'onglets — ils se réduisent pour tenir dans la bande, mais pas en dessous d'une largeur lisible : l'icône et la croix de fermeture prennent leur place en plus du titre, jamais à sa place. Ceux qui ne tiennent plus sortent de la bande, et un bouton ··· apparaît à son extrémité : il ouvre la liste de tous les onglets visibles, l'actif coché, et le choix bascule dessus. L'onglet actif reste toujours affiché. La bande ne défile pas — ce bouton est le chemin d'accès aux onglets sortis du cadre. Rien à coder, le comportement est automatique.


Événements #

ÉvénementDéclenché quand
ue_selection_changed (string as_from_id, string as_id)L'onglet actif a changé — par clic ou par of_select_page. Mêmes arguments que ue_selection_changing : la question et son issue se lisent pareil, et as_from_id est la page quittée
ue_tab_closed (string as_id)L'utilisateur clique la croix d'un onglet fermable. L'onglet est déjà retiré et la page rendue à sa fenêtre
ue_tab_reordered (string as_id, integer ai_index)L'utilisateur a fini de faire glisser un en-tête. ai_index est la nouvelle position, à partir de 1
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_id, string as_id) → booleanAnnulable, posé avant que l'onglet actif ne change. Levé par défaut ; ib_veto_selection = false le supprime. Renvoyez false pour garder l'utilisateur sur sa page
ue_tab_closing (string as_id) → booleanAnnulable, posé avant la fermeture d'un onglet fermable. Levé par défaut ; ib_veto_close = false le supprime. Nommé pour faire la paire avec ue_tab_closed : closing / closed. Renvoyez false pour garder l'onglet (et sa page hébergée) ouvert
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 #

Un classeur de pages métier #

// event open : les userobjects de page sont deja poses sur la fenetre
uo_onglets.of_set_redraw(false)

uo_onglets.of_add_page(/*id*/ "identite", /*titre*/ "Identite",  /*page*/ uo_identite)
uo_onglets.of_add_page(/*id*/ "adresses", /*titre*/ "Adresses",  /*page*/ uo_adresses)
uo_onglets.of_add_page(/*id*/ "compta",   /*titre*/ "Comptabilite", /*page*/ uo_compta)

uo_onglets.of_item("identite").is_icon = "mono:img\user.svg"
uo_onglets.of_item("adresses").is_icon = "mono:img\map.svg"
uo_onglets.of_item("compta").is_icon   = "mono:img\euro.svg"

uo_onglets.of_set_redraw(true)
uo_onglets.of_select_page("identite")

Documents fermables, ouverts à la demande #

// Ouvrir un document dans un nouvel onglet fermable
uo_onglets.of_add_page(/*id*/ ls_cle, /*titre*/ ls_libelle, /*page*/ uo_editeur, &
                       /*fermable*/ true, /*icone*/ "mono:img\doc.svg")
uo_onglets.of_select_page(ls_cle)
// event ue_tab_closed de uo_onglets : (string as_id)
// L'onglet est deja retire ; il reste a liberer vos donnees metier.
of_liberer_document(as_id)

Réordonnancement à la souris #

uo_onglets.ib_reorderable = true
// event ue_tab_reordered de uo_onglets : (string as_id, integer ai_index)
// ai_index = nouvelle position, a partir de 1 : on memorise l'ordre choisi.
of_enregistrer_ordre(as_id, ai_index)

Bandeau vertical #

// Bande d'onglets sur le cote gauche, utile quand les libelles sont longs
uo_onglets.is_position = uo_onglets.POSITION_START

Griser ou masquer un onglet selon les droits #

// Le chemin passe toujours par le handle de la page
uo_onglets.of_item("compta").ib_enabled = of_a_le_droit("compta")
uo_onglets.of_item("audit").ib_visible  = gb_mode_expert

Réagir à la sélection #

// event ue_selection_changed de uo_onglets : (string as_from_id, string as_id)
choose case as_id
    case "identite" ; uo_identite.of_rafraichir()
    case "adresses" ; uo_adresses.of_rafraichir()
    case "compta"   ; uo_compta.of_rafraichir()
end choose

Refuser un changement d'onglet ou une fermeture #

// Les deux questions sont posees par DEFAUT : rien a activer. Ces lignes font
// l'inverse, elles les suppriment quand l'arbitrage ne sert pas.
uo_onglets.ib_veto_selection = false
uo_onglets.ib_veto_close     = false
// event ue_selection_changing de uo_onglets : (string as_from_id, string as_id)
// Renvoyer FALSE garde l'utilisateur sur la page qu'il quitte.
if of_page_modifiee(as_from_id) then
    if MessageBox("Modifications", "Quitter sans enregistrer ?", Question!, YesNo!) = 2 then
        return false
    end if
end if
return true
// event ue_tab_closing de uo_onglets : (string as_id)
// Renvoyer FALSE garde l'onglet et sa page hebergee ouverts.
return not of_page_modifiee(as_id)

Repartir d'un bandeau vide #

// of_reset rend CHAQUE page hebergee a sa fenetre d'origine avant de vider
uo_onglets.of_reset()
uo_onglets.of_add_page("accueil", "Accueil", uo_accueil)

Bonnes pratiques #


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