PBToolboxAI v5 ← Site

commandpalette — n_pbt_commandpalette #

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

Palette de commandes : l'utilisateur presse un raccourci, tape trois lettres, et atteint n'importe quelle action de votre application — sans la chercher dans les menus.

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


En bref #

Objetn_pbt_commandpalette — non visuel : rien à poser dans la fenêtre
Sert àRendre toutes les actions de l'application atteignables au clavier, en trois lettres
RetourNon bloquant : of_open() rend la main aussitôt ; le choix revient par événement

La palette est une fenêtre détachée, à elle : elle flotte au-dessus de votre application, prend le focus le temps que l'utilisateur tape, et le rend en se refermant.


Démarrage rapide #

Posez n_pbt_commandpalette sur votre fenêtre comme objet non visuel (nommé ici inv_palette) : ses événements se scriptent sur lui, comme ceux d'un contrôle.

// Une fois, au demarrage : les actions de votre application
inv_palette.ipo_owner = this
inv_palette.of_add_command(/*key*/ "new",  /*label*/ "New project", /*group*/ "File")
inv_palette.of_add_command(/*key*/ "open", /*label*/ "Open file...", /*group*/ "File")
inv_palette.of_add_command(/*key*/ "save", /*label*/ "Save", /*group*/ "File")
inv_palette.of_register_shortcut()
// event ue_command_selected of inv_palette : (string as_key)
// parent is the window : the palette runs nothing by itself
choose case as_key
	case "new";  parent.wf_new()
	case "open"; parent.wf_open()
	case "save"; parent.wf_save()
end choose

Le branchement : la fenêtre hôte #

La palette est un objet non visuel, mais vous n'avez aucun receveur ni message à câbler : elle draine elle-même ses événements et les lève sur elle-même — ue_command_selected, ue_shortcut, ue_opened et ue_closed se scriptent sur l'objet palette posé dans la fenêtre (ou sur un descendant). ipo_owner dit à quelle fenêtre elle appartient.

Deux lignes, une fois, à l'ouverture de la fenêtre :

// La fenetre a laquelle la palette appartient
inv_palette.ipo_owner = this

// La palette doit repondre a sa touche
inv_palette.of_register_shortcut()

C'est tout ce qu'il y a à brancher. Le choix de l'utilisateur, l'ouverture et la fermeture vous reviennent ensuite par de simples événements de l'objet palette (et non de ipo_owner) — sans receveur, sans message à mapper, sans timer. Un événement peut ouvrir une MessageBox ou fermer la fenêtre (« Quitter ») : les suivants attendent qu'il soit fini, et une palette détruite avec sa fenêtre s'arrête proprement.

Où écrire les événements #

PowerBuilder n'offre les événements d'un objet non visuel qu'à deux endroits : la palette posée dans la fenêtre (dans le peintre, Insert > Object, puis n_pbt_commandpalette, nommée inv_palette : ses événements se scriptent comme ceux d'un contrôle — c'est ce que supposent les exemples de cette page), ou un descendant de n_pbt_commandpalette (n_my_palette), dont les événements portent vos scripts et que la fenêtre crée par create n_my_palette. Une variable n_pbt_commandpalette créée par create n'a aucun script : la palette s'ouvre, mais le choix de l'utilisateur n'arrive à personne.


Le raccourci : c'est la DLL qui l'entend #

Le raccourci qui ouvre la palette n'est pas écouté par la page : il est enregistré auprès de la DLL, qui seule voit les frappes pendant que le focus est sur un autre contrôle. C'est toute la différence entre une palette qu'on trouve et une palette qui ne répond que si on a déjà cliqué dessus.

La DLL entend l'accord, mais elle n'ouvre rien d'elle-même : elle vous prévient par ue_shortcut, et c'est vous qui décidez. Ouvrir une palette par-dessus un dialogue modal n'arrangerait personne.

// event ue_shortcut : la touche est tombee
if not ib_dialog_open then inv_palette.of_open()

is_shortcut choisit l'accord ; of_register_shortcut() le pose. Appelez-le une fois à l'ouverture de la fenêtre — sans quoi la palette ne répond à sa touche qu'après avoir déjà été ouverte une fois. of_open le repose au passage, donc un accord changé plus tard n'a besoin de rien de plus.

// Le raccourci de l'habitude, celui des editeurs de code
inv_palette.is_shortcut = inv_palette.SHORTCUT_DEFAULT

// Ou le votre
inv_palette.is_shortcut = "ctrl+shift+p"

// Ou aucun : la palette ne s'ouvre plus que par of_open()
inv_palette.is_shortcut = inv_palette.SHORTCUT_NONE

L'accord de la palette n'est consulté qu'après les raccourcis des autres composants de la fenêtre, focus ou non : un bouton de barre d'outils posé sur le même accord l'emporte. L'accord de cette fenêtre passe avant un accord posé sans ipo_owner (toute l'application). Seules les touches que le crochet sait nommer sont acceptées — lettres, chiffres, F1 à F24, Entrée, Échap, Suppr, Inser, Début, Fin, Pg préc., Pg suiv. et, avec Ctrl ou Alt, les flèches, Espace, Tab, Retour arrière, + - , . ; toute autre rend -5. Le chapitre clavier le détaille.


Où la palette s'affiche #

is_position dit où la fenêtre se pose. Elle est toujours ramenée dans l'écran : une palette ancrée sous un champ en bas de fenêtre ne disparaît pas sous la barre des tâches.

ConstanteOù
POSITION_WINDOW_CENTERCentrée sur ipo_owner — le défaut, et ce qu'attend l'œil
POSITION_SCREEN_CENTERCentrée sur l'écran, quelle que soit la fenêtre
POSITION_ABSOLUTEÀ il_x / il_y, en pixels écran

PowerBuilder travaille en PBU, et la position d'un contrôle est relative à sa fenêtre : pour ancrer la palette sous un contrôle, of_anchor_under(contrôle) fait la conversion et pose les trois propriétés. Sur deux écrans, elle s'ouvre sur l'écran du point demandé.

Sa hauteur suit le nombre de commandes affichées, et se réduit à mesure que l'on filtre — sans que son coin haut bouge, sinon la zone de saisie se déroberait sous les doigts. Elle est plafonnée à la moitié de l'écran : au-delà, la liste défile à l'intérieur et la zone de saisie reste en haut.

Un clic ailleurs dans l'application referme la palette, et ce clic atteint quand même sa cible — comme un menu qu'on quitte. Rien à faire pour cela.


Propriétés #

PropriétéTypeDéfautRôle
ipo_ownerpowerobject—La fenêtre à laquelle la palette appartient : elle possède la fenêtre popup et lui sert d'ancre, et son accord répond dans cette fenêtre. À poser avant of_open. Laissée vide, l'accord répond dans toutes les fenêtres de l'application. Les événements ne sont pas levés sur elle mais sur l'objet palette lui-même. Deux objets palette posés sur la même fenêtre gardent chacun leur accord et leurs événements : aucun ne reçoit ceux de l'autre
ipo_receiverpowerobject—Optionnel, hérité : une fenêtre dont le pbm_custom02 est sonné à chaque événement, pour le code d'avant qui y appelait of_process_events. Laissez-le vide — la palette livre ses événements toute seule, sur elle-même
is_shortcutstring"ctrl+k"Accord de touches qui ouvre la palette, depuis n'importe où dans la fenêtre. Constantes SHORTCUT_DEFAULT (ctrl+k) et SHORTCUT_NONE (aucun). Prend effet à of_register_shortcut
is_positionstringwindow-centerOù la fenêtre se pose (constantes POSITION_*)
il_x · il_ylong0Position en pixels écran, lue par POSITION_ABSOLUTE seulement
is_placeholderstring""Texte gris affiché dans la zone de saisie tant que rien n'est tapé
is_recentstring""Mémoire d'usage : les ids lancés le plus récemment, le plus récent d'abord, séparés par des virgules. La palette les fait remonter en tête ; quand on filtre, la récence ne fait que départager des résultats qui correspondent à peu près aussi bien — elle ne fait jamais passer une correspondance plus faible devant une meilleure, quel que soit il_max_recent. Les espaces autour des ids et les doublons sont nettoyés, et la liste propre revient ici. Relisez-la après usage et persistez-la ; reposez-la au démarrage. Une palette qui repart de zéro chaque matin n'apprend rien
il_max_recentlong8Combien le bloc « Récemment utilisées » en garde. 8 par défaut. Une limite abaissée coupe is_recent à l'ouverture suivante. 0 l'éteint : une application dont les utilisateurs préfèrent leurs groupes intacts peut le dire — is_recent est alors gardé tel quel, inutilisé. Une entrée du bloc reste dans son groupe et porte le nom de ce groupe — un raccourci ne déplace pas ce qu'il raccourcit

Méthodes #

MéthodeRôle
of_add_command (string as_key, string as_label, string as_group)Déclare une action : son identifiant, son libellé, et le groupe sous lequel elle apparaît. Renvoie 0 une fois ajoutée, -5 si la clé est vide, contient /, ` ou une virgule (is_recent est une liste séparée par des virgules), ou est déjà prise. Des dizaines de milliers de commandes restent fluides : la palette ne dessine que les lignes visibles. Une commande au groupe vide vient **en tête**, sans en-tête ; of_get_last_error` dit pourquoi une clé a été refusée
of_add_command (string as_key, string as_label, string as_group, string as_hint, string as_shortcut, string as_keywords)Même chose, avec l'explication à droite, le raccourci à afficher, qui lance sa commande tant que la palette est ouverte — c'est ainsi qu'on l'apprend ; en dehors, votre application garde ses propres accélérateurs, et pendant la frappe Ctrl+C, Ctrl+V, Ctrl+Z et Ctrl+A restent à la zone de recherche — et des mots-clés que la recherche prend en compte sans qu'ils soient visibles. Renvoie 0 une fois ajoutée, -5 si la clé est vide, contient /, ` ou une virgule (is_recent est une liste séparée par des virgules), ou est déjà prise. Une commande au groupe vide vient **en tête**, sans en-tête ; of_get_last_error` dit pourquoi une clé a été refusée
of_insert_command (string as_key, string as_label, string as_group, long al_index)Déclare une action à un rang choisi (1 = en tête) plutôt qu'à la fin : un module partagé range ses commandes où elles vont. 0 ou moins, ou au-delà de la fin, ajoute au bout. Indication, raccourci, mots-clés et icône se posent ensuite par of_command. Renvoie 0 une fois ajoutée, -5 pour les mêmes clés que of_add_command
of_insert_command (string as_key, string as_label, string as_group, string as_hint, string as_shortcut, string as_keywords, long al_index)La forme complète, comme of_add_command : l'indication, le raccourci à afficher et les mots-clés viennent avec la commande, à son rang. Mêmes retours
of_remove_command (string as_key)Retire une action ; les autres restent. Renvoie 0 une fois retirée, -5 si aucune commande ne porte cette clé
of_command (string as_key) → n_pbt_commandpalette_commandLa poignée d'une commande, pour la renommer, changer son raccourci, la griser ou la masquer par ses propriétés. Griser plutôt que retirer : retirer ce que l'utilisateur ne peut pas faire lui retire aussi toute chance de découvrir que ça existe. L'état voyage avec les commandes : un changement fait palette ouverte se voit à l'ouverture suivante. Une clé qu'aucune commande ne porte donne une poignée qui ne désigne rien : ses booléens se relisent FALSE, ses textes "", et une écriture est perdue — of_get_last_error le dit
of_key ( ) → stringSur la poignée que rend of_command : la clé de la commande qu'elle désigne — ce qu'of_command a reçu pour l'obtenir, et ce qu'on garde quand la poignée passe de main en main
of_clear_commands ( )Vide la palette, commandes lues d'un menu (of_load_menu) comprises. Rend 0
of_count ( ) → longRend le nombre de commandes que la palette porte
of_keys_at ( long al_index ) → stringL'identifiant de la commande de rang al_index (à partir de 1), ou "" au-delà de l'un ou l'autre bout. Avec of_count, c'est ce qui permet de parcourir une palette qu'on n'a pas remplie soi-même — un module partagé y ajoute les siennes
of_has ( string as_key ) → booleanUne commande existe-t-elle sous cet identifiant ? Demander vaut mieux que deviner : of_add_command refuse (-5) un identifiant déjà pris
of_anchor_under ( dragobject ado_control )Ancre la palette sous un contrôle — un champ, un bouton : pose is_position à POSITION_ABSOLUTE et il_x / il_y sur le coin bas gauche du contrôle, en pixels écran. À appeler avant of_open ; la palette reste ramenée dans l'écran. Renvoie 0, ou -5 si le contrôle n'est pas valide. Un contrôle (ou une fenêtre) qui se lit de droite à gauche donne son coin bas-droit : la palette s'aligne sur ce bord et s'ouvre vers la gauche
of_open ( )Ouvre la palette : une fenêtre à elle, possédée par ipo_owner, placée par is_position. Elle prend le focus, et le rend en se refermant. Renvoie 0 une fois demandée — ue_opened (à l'écran) ou ue_closed (avec la raison pour laquelle elle n'a pas paru) suit toujours —, -6 si le runtime WebView2 manque, -4 si sa fenêtre n'a pas pu être créée. Les commandes lues d'un menu (of_load_menu) prennent l'état de leur item à ce moment
of_is_open ( )VRAI tant que la palette est à l'écran. C'est ce qui permet à l'accord de basculer : pressé une seconde fois, une palette se ferme — rappeler of_open détruirait la fenêtre pour la reconstruire à l'identique, ce qui se voit comme un clignotement, pas comme une fermeture. La DLL ne décide toujours rien : elle informe. Une fois ouverte, la palette tient le focus dans sa propre fenêtre : l'accord pressé là la referme d'elle-même. Il répond pour la palette de cet objet : quand un autre objet palette ouvre la sienne, elle remplace celle-ci et of_is_open répond FAUX ici
of_close ( )Referme la palette que cet objet a ouverte — jamais celle qu'un autre objet palette a ouverte depuis. Perdre le focus la referme aussi, comme un menu. Renvoie 0
of_register_shortcut ( )Confie l'accord de is_shortcut à la DLL. À appeler une fois à l'ouverture de la fenêtre. Un seul accord par objet palette : le rappeler après avoir changé is_shortcut remplace le précédent, qui cesse aussitôt de répondre — il n'y a jamais rien à retirer d'abord. Rend 0 s'il est posé, 1 s'il en a remplacé un, 2 si un is_shortcut vide ne laisse aucun accord (retiré, ou il n'y en avait pas), -5 si la touche est de celles que le crochet ne voit pas (voir plus haut) — l'accord précédent est alors gardé. Sans ipo_owner, l'accord répond dans toutes les fenêtres de l'application. Deux objets palette d'une même fenêtre gardent chacun le leur ; le même accord posé par un second objet lui revient (1). Détruire l'objet retire son accord — jamais celui qu'un autre objet palette tient. L'accord repris par un second objet revient au premier quand le second est détruit. Tant qu'une fenêtre est active, l'accord de la palette passe avant les accélérateurs de son menu PowerBuilder : un item de menu sur la même touche ne l'entend plus
of_process_events ( )Draine les événements en attente et les lève sur l'objet palette lui-même. Le composant l'appelle tout seul tant que la palette vit : vous n'avez pas à le faire. Un événement qui ouvre une MessageBox ne voit pas les suivants levés en son milieu, et un événement qui ferme la fenêtre de la palette arrête le drainage proprement
of_reset ( ) → longVide les commandes et la mémoire d'usage (is_recent), remet les propriétés à leur défaut, referme une palette ouverte et ramène un accord posé à SHORTCUT_DEFAULT. ipo_owner et ipo_receiver sont laissés tels quels : c'est le câblage, pas le contenu. Les commandes lues d'un menu partent aussi Rend 0 une fois fait.
of_load_menu ( menu am_menu )Remplit la palette depuis un menu PowerBuilder : chaque item sans sous-items devient une commande, sans déclarer vos actions deux fois — passez this.MenuID ou l'un de ses items. Clé = le ClassName de l'item, libellé = son texte sans & ni le raccourci écrit après une tabulation, groupe = les textes des items au-dessus, raccourci = celui qu'il affiche, mots-clés = son MicroHelp. Le menu reste le maître : relu à chaque of_open, un item grisé, masqué ou renommé s'affiche tel qu'il est (un parent emporte ses items). Choisir une commande lève ue_command_selected et ne lance rien. Un second appel remplace les commandes du premier ; celles d'of_add_command restent. Rend 0, -5 quand le menu n'est pas valide
of_loaded_item ( string as_key ) → menuL'item de menu PowerBuilder d'où vient une commande (of_load_menu) : dans ue_command_selected, of_loaded_item(as_key).TriggerEvent(Clicked!) lance ce que le menu lance. Une clé qui ne vient pas d'un menu donne une référence invalide : testez-la par IsValid
of_get_last_error ( ) → stringPourquoi le dernier appel a rendu -5 (une clé refusée, un menu non valide, un accord que le clavier ne sait pas rapporter), ou la dernière écriture d'une poignée de commande qui n'a atteint aucune commande. "" quand rien n'a échoué : chaque appel qui agit la vide d'abord

Propriétés d'une commande — n_pbt_commandpalette_command #

Obtenue par of_command(clé). La palette rebâtit sa fenêtre depuis sa liste à chaque of_open : une propriété changée pendant qu'elle est ouverte se voit à l'ouverture suivante.

PropriétéTypeDéfautRôle
is_labelstring—Le texte de la ligne
is_shortcutstring""L'accord affiché à droite de la ligne, et honoré tant que la palette est ouverte (Ctrl+Shift+S)
is_groupstring—Le groupe sous lequel la commande est rangée ; le changer la déplace sans la retirer (elle garde son rang parmi les commandes)
is_hintstring""La petite ligne sous le libellé
is_keywordsstring""Les mots que la recherche lit sans les montrer — les mots de l'utilisateur
is_iconstring""Une icône à gauche de la ligne : un fichier, une image de bibliothèque, ou mono: / tint: pour une icône qui suit le thème
ib_enabledbooleantrueCommande grisée : visible, cherchable, et inerte — ni clic, ni Entrée, ni son accord
ib_visiblebooleantrueCommande masquée : hors de la liste et des accords, sans être retirée ; elle revient telle quelle

Événements #

ÉvénementDéclenché quand
ue_command_selected (string as_key)L'utilisateur a choisi une action. La palette s'est déjà refermée : à vous de faire ce qu'elle annonce. Le bouton gauche, Entrée ou le raccourci affiché sur une ligne choisissent ; un clic droit ou du milieu ne fait rien. L'événement peut ouvrir une MessageBox ou fermer la fenêtre
ue_shortcut ( )L'accord a été pressé. La DLL relaie, PB décide. Une palette bascule sur sa propre touche : if of_is_open() then of_close() else of_open() — pressé dans la palette ouverte, l'accord la referme de lui-même. Vous pouvez aussi refuser
ue_opened ( )La palette est à l'écran — par of_open
ue_closed (string as_reason)Elle vient de se refermer, choix fait ou non. Il suit chaque of_open qui a rendu 0 : as_reason est vide pour une palette qui était à l'écran, cancelled si elle a été fermée — ou remplacée par une autre palette — avant de paraître, failed si sa fenêtre n'a pas pu naître, blocked sous débogage distant sans licence

La palette ne fait rien d'elle-même. Elle rapporte l'identifiant choisi, et referme. C'est votre application qui agit — la même action, déclenchée depuis un menu ou depuis la palette, passe donc par le même code.


Au clavier #

ToucheEffet
L'accord de is_shortcutPrévient votre code par ue_shortcut ; c'est lui qui ouvre
Frappe au clavierFiltre au fil de la saisie : les lettres tapées n'ont pas à se suivre, nvf trouve « Nouveau fichier », et les accents ne comptent pas (preferences trouve « Préférences »)
Flèches haut / basDéplacent la sélection dans la liste
EntréeChoisit l'action sélectionnée (ue_command_selected)
Le raccourci affiché sur une ligneLance cette commande, sans avoir à la sélectionner
ÉchapReferme sans rien choisir
Page préc. / Page suiv.Déplacent la sélection d'un écran
Début / FinAvec du texte tapé : au début / à la fin de la requête. Champ vide : à la première / dernière commande. Ctrl+Début / Ctrl+Fin : toujours la première / dernière commande ; Maj+… sélectionne dans le champ
TabReste dans le champ de recherche (la palette est un dialogue modal)
Un clic droit ou du milieu sur une ligneNe fait rien : seul le bouton gauche choisit

Pendant qu'une méthode de saisie (japonais, chinois, coréen) compose, Entrée et les flèches lui appartiennent : valider une conversion ne lance jamais une commande.


Exemples #

Alimenter la palette depuis votre menu #

// Every action of your menu becomes a command : nothing declared twice
inv_palette.of_load_menu(/*menu*/ this.MenuID)

// The palette answers its key from the window's opening
inv_palette.of_register_shortcut()
// Local variables
menu lm_item

// event ue_command_selected of inv_palette : run what the menu item runs
lm_item = inv_palette.of_loaded_item(/*key*/ as_key)
if IsValid(lm_item) then lm_item.TriggerEvent(Clicked!)

Les mots que la recherche lit #

// Les mots-cles ne s'affichent pas, mais la recherche les lit :
// taper "pdf" trouvera l'export meme si le libelle ne le dit pas
inv_palette.of_add_command(/*key*/ "export", /*label*/ "Export", /*group*/ "File", /*hint*/ "PDF, CSV or xlsx", /*shortcut*/ "Ctrl+E", /*keywords*/ "pdf csv xlsx")

Choisir un autre raccourci #

// Ctrl+K est deja pris par votre application ? Choisissez-en un autre.
// of_register_shortcut le pose, et l'ancien s'en va tout seul.
inv_palette.is_shortcut = "ctrl+shift+p"
inv_palette.of_register_shortcut()

L'ancrer sous un champ #

// Ancree sous un champ de saisie, en pixels ecran
// La palette est ramenee dans l'ecran si elle depassait
inv_palette.of_anchor_under(/*control*/ sle_1)
inv_palette.is_placeholder = "Type a command..."
inv_palette.of_open()
// Remove one command, empty the list, close the palette
inv_palette.of_remove_command(/*key*/ "print")
inv_palette.of_clear_commands()
inv_palette.of_close()

Bonnes pratiques #


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