PBToolboxAI v4 ← Site

11. Migrer de la 3.0 à la 4.0 #

← Migrer de la 2.0 à la 3.0 · Sommaire · Notes de version →


La 4.0 retire deux méthodes des trente-deux composants de la 3.0 — of_set_data du tableau croisé, renommée of_from_datastore (11.33), et of_transform de n_pbt_xml, qui part avec XSLT (11.31) — et change des signatures que le compilateur vous montre ligne par ligne : trois propriétés renommées (id_minimum et id_maximum de la barre de progression, 11.6 ; il_doc_line de l'éditeur de code, 11.28), des arguments d'événement ajoutés ou renommés (ue_tile_moved, 11.6 ; ue_failed du client REST, 11.6, et de la vidéo, 11.26 ; ue_error de l'image, 11.25 ; ue_cell_double_clicked, 11.33 ; ue_closed de la palette de commandes, 11.36 ; ue_toast_clicked, ue_toast_action et ue_toast_dismissed du toaster, 11.38), of_count et of_keys_at en long (11.34) et des méthodes qui rendent désormais un code (of_refresh, of_select, of_show, of_scroll_to_end, of_set_header…). La 11.6 aligne aussi deux comptes, un événement et le chemin de l'arbre JSON sur le reste de la bibliothèque : c'est là, avec les sections citées, que du code qui compilait est à retoucher. Ce qui change est concentré sur le ruban (ribbon), qui a fait l'objet d'une revue complète. Deux changements demandent de relire votre code : les questions posées avant une vignette de galerie du ruban et avant une sélection de la barre latérale (listbar) (11.1) et les poignées libérées par un retrait (11.2). Les autres corrigent des comportements que vous avez pu contourner (11.3) — dont le clic droit sur un item, qui ne produit plus qu'un seul événement dans tous les composants, et le fil d'Ariane (breadcrumb), dont les adresses et les refus ont été revus. Viennent ensuite le générateur n_pbt_menu2ribbon (11.4) et ce qui a été ajouté (11.5). Les onglets (tab) suivent la même règle : leurs deux questions, avant un changement d'onglet et avant une fermeture, sont désormais facultatives (11.1). Enfin, les thèmes suivent l'application (11.7) : l'accent de l'application survit à un changement de thème, et un axe de thème laissé vide suit celui de l'application. La revue de sécurité de crypto (11.8) ferme une confusion d'algorithme des jetons JWT, remplace plusieurs silences par un refus qui dit sa raison et fixe la règle des chemins relatifs des fichiers.

La revue complète du 28/09/2026 a relu chaque composant livré ; ce qu'elle change a une section par composant : restclient (11.9), speechout (11.10), statictext et le texte riche (11.11), breadcrumb (11.12), buttonbar et le clavier de fenêtre (11.13), button (11.14), menubar (11.15), ribbon (11.16), toolbar (11.17), statusbar (11.18), dockcontainer (11.19), tab (11.20), listbar (11.21), tilesbox (11.22), stepbar (11.23), progressbar (11.24), picture (11.25), video (11.26), pdfviewer (11.27), codeeditor (11.28), jsontree et xmltree (11.29, 11.30), xml (11.31), json (11.32), crosstab (11.33), shellexplorer (11.35), commandpalette (11.36), radialmenu (11.37), toaster (11.38) et messagebox (11.39) ; le socle a deux sections, 11.34 et 11.40. Une règle les traverse, celle de PowerBuilder (SelectTab lève SelectionChanged) : un changement demandé par votre code lève le même événement qu'un geste de l'utilisateur, et pose la question du veto si vous l'avez activé ; la méthode rend -4 si vous refusez. Cela vaut pour une sélection (of_select_*), une ouverture ou un repli (of_expand, of_collapse, of_open), un zoom, un plein écran, un chapitre ; rien n'est levé quand rien ne change, et of_reset reste silencieux. Poser une VALEUR (une coche, un texte, un volume, un filtre) reste silencieux, comme SetItem. ue_layout_changed est levé dans les deux cas : il dit qu'une disposition à enregistrer a changé.

11.1 Les questions avant un changement sont désormais facultatives #

En 3.0, le ruban posait d'office la question ue_gallery_selection_changing avant de retenir une vignette : ib_veto_gallery valait true. En 4.0 il vaut false, comme tout événement annulable de la bibliothèque : chaque question coûte un aller-retour vers PowerBuilder, et seule une application qui y répond doit le payer. Une application qui ne scriptait pas l'événement ne voit aucune différence. Nouveau : of_select_gallery_item lève ue_gallery_selection_changed comme un clic et, la question armée, la pose aussi ; un refus lui fait rendre -4, la vignette ne change pas.

// 4.0 : the question is only asked on request. If your ue_gallery_selection_changing
// returns false for some tiles, switch it on where the ribbon is built.
uo_ribbon.ib_veto_gallery = true

La recette : cherchez ue_gallery_selection_changing dans vos descendants du ruban ; là où il est scripté, ajoutez ib_veto_gallery = true à la construction. Là où vous écriviez ib_veto_gallery = false pour couper la question, la ligne ne sert plus à rien et peut partir.

La barre latérale (listbar) : ib_veto_selection #

Même règle : en 3.0 la listbar posait d'office ue_selection_changing avant chaque changement de sélection (ib_veto_selection valait true). En 4.0 il vaut false. Si vous scriptiez ue_selection_changing pour refuser un déplacement, posez ib_veto_selection = true : sans cela, l'événement n'est plus levé et la sélection passe sans vous demander. Armée, la question est posée aussi pour une sélection demandée par votre code (of_select_item, of_clear_selection), comme en 3.0 ; un refus leur fait désormais rendre -4, et la sélection ne bouge pas. ue_selection_changed part comme avant.

// 4.0 : the listbar only asks on request. If your ue_selection_changing
// returns false (unsaved changes), switch the question on where the bar is built.
uo_nav.ib_veto_selection = true

La recette : cherchez ue_selection_changing dans vos descendants de u_pbt_listbar ; là où il renvoie false, ajoutez ib_veto_selection = true à la construction. Là où vous écriviez ib_veto_selection = false pour couper la question, la ligne ne sert plus à rien et peut partir.

Les onglets (tab) : ib_veto_selection et ib_veto_close #

Même règle, deux questions : en 3.0 le composant tab posait d'office ue_selection_changing avant chaque changement d'onglet et ue_tab_closing avant chaque fermeture (ib_veto_selection et ib_veto_close valaient true). En 4.0 les deux valent false. Si vous scriptiez ue_selection_changing ou ue_tab_closing pour refuser, posez ib_veto_selection = true ou ib_veto_close = true : sans cela, l'événement n'est plus levé et l'onglet change ou se ferme sans vous demander. Armée, la question est posée aussi pour of_select_page, comme en 3.0, mais avant que l'onglet ne change : un refus lui fait rendre -4 et rien ne bouge ; un accord change l'onglet tout de suite, ue_selection_changed part comme avant, et of_selected_key() relu juste après rend déjà la nouvelle clé.

// 4.0 : the tab only asks on request. If your ue_selection_changing or
// ue_tab_closing returns false (unsaved changes), switch the questions on.
uo_tabs.ib_veto_selection = true
uo_tabs.ib_veto_close     = true

La recette : cherchez ue_selection_changing et ue_tab_closing dans vos descendants de u_pbt_tab ; là où l'un renvoie false, ajoutez la ligne correspondante à la construction. Là où vous écriviez = false pour couper une question, la ligne ne sert plus à rien et peut partir.

11.2 Les ajouts disent ce qu'ils refusent, les retraits libèrent leurs poignées #

En 3.0, un ajout que le ruban ignorait — une clé déjà prise, une entrée de menu sous un simple bouton — rendait quand même 0, et rien n'apparaissait. En 4.0 il rend -5, et le code de l'envoi (-2 quand le composant n'est pas créé) au lieu d'un 0 fixe. Et un retrait libère les poignées de ce qui part : une variable qui tenait la poignée d'un contrôle retiré n'est plus valide.

Quoi3.04.0
Ajout d'une clé déjà prise (onglet, groupe, contrôle)0, ignoré-5
Entrée de menu, choix de combo ou vignette sous un contrôle d'une autre nature0, ignoré-5
of_add_tab, of_insert_tab, of_add_group, of_add_contextual_*, of_add_qat sur un composant non créé0-2
Une poignée tenue après of_remove_tab, of_remove_group, of_remove_item ou of_clearrestait en mémoire jusqu'à la destruction du rubanlibérée : IsValid() rend false
// 4.0 : after a removal or of_clear, ask the component for the handle again
uo_ribbon.of_clear()
uo_ribbon.of_add_tab(/*key*/ "home", /*title*/ "Home")
uo_ribbon.of_add_group(/*keys*/ "home/clip", /*title*/ "Clipboard")
uo_ribbon.of_add_button(/*keys*/ "home/clip/paste", /*label*/ "Paste", /*image*/ "")
uo_ribbon.of_item(/*keys*/ "home/clip/paste").ib_enabled = false

La recette : ne gardez pas une poignée au-delà d'un retrait ou d'un of_clear — redemandez-la par of_tab, of_group, of_item ou of_menu_item, ce qui ne coûte rien. Là où une erreur de construction vous importe, testez le code rendu par l'ajout.

11.3 Autres comportements que vous pouvez voir #

Quand la fenêtre est étroite, le ruban replie ses groupes en un bouton qui ouvre un panneau. C'est de ce panneau que viennent les écarts les plus visibles :

Quoi3.04.0
Bouton, ou partie principale d'un split, cliqué dans le panneau d'un groupe repliéue_menu_selected("", false)ue_clicked(adresse)
Entrée de menu choisie dans ce panneauadresse incomplèteadresse complète, cascade comprise
Contrôle grisé, ou entrée masquée, dans ce panneaurépondait / était affichéene répond pas / n'est pas affichée
Grand split réduit faute de placeun clic ouvrait seulement le menudeux parties : la commande et la flèche du menu
Entrée de menu qui porte la clé de son contrôle (home/clip/paste/paste)ue_clicked("home/clip/paste")ue_menu_selected("home/clip/paste/paste", …)
of_menu_item("…/exp/pdf") quand une cascade porte aussi pdfpouvait viser …/exp/more/pdfvise l'entrée que l'adresse nomme
as_from_keys de ue_gallery_selection_changed sans vignette précédentel'adresse de la galerie""
Relire une poignée de barre d'accès rapide, il_color d'un sélecteur de couleur, ii_visible_items, is_keytip d'un onglet, il_color d'un groupe contextuel, of_count() d'une galerievide, -1 ou 0la valeur à l'écran
of_keys_at d'un combo"home/font/cb/cb:Arial""home/font/cb/Arial" : la clé d'un choix est son libellé
of_ctx_group(k).il_color quand un onglet porte aussi la clé kcolorait l'ongletcolore la seule bannière
Couleurs d'item (il_back_color…) et is_tooltip d'un onglet ou d'un groupesans effetappliquées ; l'infobulle d'un groupe s'affiche sur son titre
of_remove_item("save") sur un bouton de barre d'accès rapide-5le bouton est retiré
of_add_app_menu_separator("saveas/s1")une ligne à la racine du menula ligne dans le sous-menu de saveas ; une clé sans / ne change pas
of_clear() alors qu'un onglet était actifaucun événementue_selection_changed("")
Spinner au pas décimal (0.1)0.300000000000000040.3
Raccourci Alt (keytip) sur un contrôle grisé, ruban réduitle ruban restait ouvertil se referme, rien ne s'exécute
toolbar : combo, spinner ou galerie grisés dans le panneau du chevronrépondaientne répondent pas
Tous : clic droit sur un item (ue_item_rclicked, ue_panel_rclicked, ue_row_rclicked…)la page envoyait aussi l'événement du composant, qu'aucun composant à items ne relayait à PowerBuilderun seul événement, celui de l'item ; un ue_rclicked de composant, là où il existe, ne part que hors des items
Tous : un dépôt de fichiers (ib_allow_drop)ue_drag_leave puis ue_drop_files ; chemins coupés à 260 caractèresue_drop_files seul, chemins entiers ; of_reset retire la cible de dépôt
breadcrumb : of_path() avec un segment masqué, ou en version de démonstrationles clés affichées : le masqué sauté, les premiers segments coupésl'adresse du lieu courant, complète : of_truncate(of_path()) tombe juste ; le champ de saisie part de la même
breadcrumb : of_keys_at(n) ; of_has("computer/C:")la clé nue ; cherchait parmi les branches du menul'adresse du segment ; cherche parmi les segments
breadcrumb : lire une poignée d'adresse profonde, of_item("a/b/c").is_textlisait le dernier niveau seul : vide sur une clé répétéele segment de cette adresse
breadcrumb : of_truncate, of_remove_item, of_clear_children, of_remove_child sur une adresse inconnue ou une clé nue répétée ; of_add_child sous un segment absent ou sur une branche déjà prise ; of_add_item d'une adresse qui atterrirait ailleurs0, ignoré (ou la seule dernière clé retenue)-5
breadcrumb : une poignée tenue après of_clear, of_remove_item, of_truncate, of_clear_children ou of_remove_childrestait en mémoirelibérée : IsValid() rend false
breadcrumb : champ de saisie quitté sans rien changer, ou fenêtre changée (Alt+Tab) en cours de frappeue_path_entered levérien ; la saisie reste en changeant de fenêtre
breadcrumb : segment grisé ; Entrée sur un segmentson chevron s'ouvrait et il recevait un dépôt ; Entrée pressait aussi le bouton par défaut de la fenêtreinerte en entier ; Entrée ne clique que le segment
buttonbar : Entrée quand un autre bouton de la barre a le focus clavierdéclenchait le bouton par défaut (is_default)déclenche le bouton qui a le focus, comme Windows ; le défaut part quand aucun bouton de la barre n'a le focus
buttonbar : bouton par défaut ou annuler grisé ou masqué ; raccourci is_shortcut d'un bouton grisé ou masquéEntrée, Échap ou Alt+lettre avalés sans effet, même dans un contrôle PowerBuilder de la fenêtrela touche reste à la fenêtre
buttonbar : is_shortcut de plusieurs lettres ("Save")Alt+S ne marchait que si la barre avait le focusAlt+S marche de partout dans la fenêtre (la première lettre, comme documenté)
buttonbar : of_add_button / of_insert_button sur une clé déjà prise ou qui contient / ou une barre verticale ; of_remove_button / of_move_button sur une clé inconnue0, ignoré-5
buttonbar : of_remove_button, of_clear_buttonsle raccourci Alt+lettre, les couleurs et l'info-bulle du bouton restaient (un bouton recréé sous la même clé les reprenait) ; la poignée restait en mémoireils partent avec le bouton ; la poignée est libérée : IsValid() rend false
codeeditor : relire is_text d'un texte en CRLFen LF (en CRLF seulement si l'éditeur était replié) : is_text = ls_original était fauxavec les fins de ligne reçues, replié ou non
codeeditor : relire is_syntax après SYNTAX_CSHARP, SYNTAX_CPP, SYNTAX_JAVA, SYNTAX_XMLla grammaire utilisée ("c", "html")la valeur écrite
codeeditor : of_insert_text en lecture seule ou repliéinséré en lecture seule ; refusé replié, mais 0-4, rien n'est inséré
codeeditor : ii_doc_lineune bande seule, souvent hors de la vue, absente en retour à la ligne ; un integerla ligne vient au milieu de la vue (une région repliée qui la cache s'ouvre), bande aussi en retour à la ligne ; curseur et sélection intacts ; un long — renommé il_doc_line en 4.0 (section 11.28)
codeeditor : #regionopen avec ib_foldingréécrit #region dans le texte (is_text, et après le repli)jamais touché ; seul l'affichage replié montre #region
codeeditor : ue_find_resultdeux fois par of_find, à chaque frappe, et (0, 0) à la fermeture de la barre ; levé même avec ib_search_enabled = falseune fois par recherche ou par pas ; à la frappe si le compte change ; jamais à la fermeture ; of_find sans effet quand la recherche est désactivée
codeeditor : ue_caret_changedmuet pendant la frappe ; replié, la ligne AFFICHÉElevé aussi à la frappe ; replié, la ligne de la gouttière
codeeditor : Ctrl+Z après Entrée ou Tab ; Entrée / Tab en mode repliél'historique d'annulation était vidé ; replié, la touche modifiait l'affichage et se perdait ensuitechaque frappe s'annule ; replié, la touche est sans effet
codeeditor : ib_folding = true avec ib_line_numbers = falseles régions restaient fermées, sans marqueur pour les ouvrirune gouttière étroite garde les marqueurs
commandpalette : of_add_command sur une clé déjà prise ou qui contient / ou une barre verticale ; of_remove_command sur une clé inconnue0 (une clé prise donnait deux commandes jumelles)-5
commandpalette : of_open / of_register_shortcut sans ipo_owner ni ipo_receiver0, et aucun événement n'arrivait jamais-5
commandpalette : l'accord pressé pendant que la palette est ouvertesans effetreferme la palette
commandpalette : un objet palette détruit (page ou fenêtre fermée)son accord restait posé et avalait la touche dans la fenêtre, sans aucun événementl'accord part avec l'objet, et une palette qu'il avait ouverte se referme
commandpalette : raccourci affiché sur une ligne, sur un clavier non latin, avec un chiffre et Maj, Ctrl+Space, Ctrl+Up, Ctrl+Del, ou une touche F seulene répondait pas ; Win + la lettre lançait la commande au raccourci d'une seule lettrerépond : la touche physique, lue comme la DLL la lit ; Win n'est jamais un modificateur
commandpalette : une commande dont le raccourci est Ctrl+C, Ctrl+V, Ctrl+Z ou Ctrl+A, pendant la frappela commande partait à la place de la copie, du collage…la zone de recherche garde ces quatre touches
commandpalette : of_resetgardait is_recent, une palette ouverte et l'accord déjà poséles vide, la referme, et ramène l'accord posé à SHORTCUT_DEFAULT
commandpalette : pbm_custom02 de la fenêtre ipo_ownerdéclenché à chaque événement de la palettejamais : seul un ipo_receiver posé le reçoit encore
Tous : relire une longue valeur texte (is_text d'un gros script)de plus en plus lent avec la taille (plusieurs secondes) ; coupé sans prévenir au-delà d'un million de caractèresproportionnel à la taille ; entier
n_pbt_utils.of_dir_has_subfolderscomptait les dossiers cachés, système et les jonctions ; illisible au-delà de 260 caractèresles ignore, comme l'Explorateur (la surcharge ab_include_hidden les compte) ; lit les chemins longs
crosstab : séparateur de milliers de of_set_value_formatvalait pour TOUTES les mesures ; "," non reconnu ($1 234 en français)réglage de CETTE mesure ; ",", ".", " " reconnus ; "" = défaut du menu Options
crosstab : of_set_member_filter(champ, "")aucun membre gardé : tableau videretire le filtre, comme of_set_member_order("")
crosstab : is_show, is_conditional_formatting, of_set_value_format avant of_add_value_fieldperdus sans rien diregardés, relus tels quels, appliqués quand le champ entre en Valeurs
crosstab : tri d'une colonne ou repli d'un groupe à la sourisaucun événementue_layout_changed, comme tout ce que of_get_layout enregistre
crosstab : dates d'un DataStore sur un poste non français (3/15/2025, 15.03.2025)groupées dans un mois faux ou vide ; les dates triées sur l'année seulele bon mois ; la colonne relue en aaaa-mm-jj, triée dans l'ordre du temps
crosstab : nombres affichés en allemand, italien, espagnol, portugaisà l'américaine (1,234.5)dans la langue d'affichage (1.234,5 en allemand)
crosstab : of_export_csvnombres à point (1436.5), lus comme du texte par un Excel français ; un libellé =… s'exécutait à l'ouvertureséparateur décimal de la langue d'affichage ; une apostrophe devant = + - @
crosstab : of_export_xlsxtotaux et sous-totaux masqués exportés quand même ; total en tête ignoré ; symbole « avant » passé aprèsle tableau tel qu'à l'écran
crosstab : « Ajouter aux valeurs » du menu d'un champ déjà en Valeursremplaçait ses valeursajoute une valeur, comme le glisser
crosstab : « Retirer » du menu d'un champ filtréle filtre restait actif, invisiblele filtre part avec le champ
crosstab : AGG_DISTINCT_COUNT sur une colonne à cellules videsle vide comptait pour une valeurignoré, comme dans Excel
crosstab : formule qui cite une mesure calculéeacceptée, valait 0refusée par ue_calc_field_error ; ses messages sont en anglais
crosstab : ue_layout_changed avec une accolade dans un membre ; ad_value de ue_cell_double_clickeddisposition tronquée ; valeur 0 si un champ en lignes s'appelle value, exposant perdulues entières
crosstab : ib_enabled = false, au clavierEntrée ouvrait le menu d'un chip, Ctrl+C copiaitmuet
crosstab : clavierle focus retombait en haut de page après chaque action ; aucun moyen de déplacer un chample focus reste sur l'élément actionné ; le menu d'un chip le déplace (autre zone, à gauche, à droite)
crosstab : thème sombrenégatifs et flèches d'icônes peu lisibles ; cellule d'échelle de couleurs sélectionnée illisibleune palette propre au mode sombre
crypto : of_jwt_sign avec JWT_EDDSAl'en-tête disait "alg":"EDDSA", que les autres bibliothèques (jose, PyJWT, jjwt) refusent"alg":"EdDSA", le nom enregistré ; un jeton 3.0 se vérifie toujours
crypto : of_generate_keypair d'une sorte ou d'une taille inconnue ("ec_p256", 1024)0 et une paire RSA 2048, sans un mot-5, les deux PEM vides, is_last_error nomme les KEY_* admises
crypto : of_hash_file("SHA-256", …) ; algorithme inconnuvide, et is_last_error disait « fichier illisible » d'un fichier parfaitle nom se lit comme of_hash le lit (SHA-256 = HASH_SHA256) ; un algorithme inconnu est dit tel quel, distinct d'un fichier illisible
crypto : of_base64_encode_file d'un fichier trop gros (plus de 64 Mo en 32 bits, 512 Mo en 64 bits) ; d'un fichier absent en démo« fichier illisible » ; « limite de la démo »« trop gros pour ce processus » ; « fichier illisible » — is_last_error dit la vraie raison
crypto : is_last_error après un appel natif réussi (of_crc32, of_hash en MD5, of_hash_file…)gardait l'erreur de l'appel précédentvide
crypto : clé HMAC vide ; exp/nbf non numérique d'un JWT ; of_password_verify d'une valeur à plus de 10 000 000 tours ; of_random_password d'un jeu inconnuerreur obscure du moteur ; jeton valable pour toujours ; calcul de plusieurs minutes ; jeu CHARSET_ALL pris sans un motrefusés tout de suite, is_last_error dit pourquoi
crypto : of_base64_decode_to_file("", chemin)-50, un fichier vide
dockcontainer : of_add_panel avec un as_relative_to inconnu, un contrôle déjà hébergé, une clé contenant / ou une barre verticale, ou POSITION_STACK sur le panneau principal0 : le panneau se dockait contre la racine, le contrôle était hébergé deux fois, ou le panneau empilé sur le principal restait invisible-5, et le contrôle n'est pas touché
dockcontainer : of_move_panel vers une cible inconnue, ou POSITION_STACK sur le panneau principal0 : le panneau partait contre la racine, ou rien ne bougeait-5
dockcontainer : of_remove_panel, of_resetle contrôle revenait dans sa fenêtre masqué, à la position et à la taille du dockil revient à sa place, à sa taille et avec la visibilité qu'il avait avant of_add_panel
dockcontainer : is_main posé avant of_add_panel ; is_main = "" ; is_main d'un panneau empiléignoré en silence ; rien n'était transmis ; ses voisins de pile devenaient invisiblesretenu et appliqué à l'ajout du panneau ; le panneau principal est retiré ; il sort de sa pile, les autres restent visibles
dockcontainer : of_set_layout d'une disposition qui ne connaît aucun des panneaux, ou d'un texte qui n'est pas une dispositionle dock se vidait, ou le message entier était rejeté ; 0les panneaux restent, rangés à côté des autres (jamais sur le principal) ; -5 pour un texte qui n'est pas une disposition
dockcontainer : ue_layout_changedlevé au glisser, au redimensionnement et au docking seulement : une disposition enregistrée à cet événement oubliait un panneau fermé ou l'onglet actiflevé aussi quand un panneau est fermé, masqué, sélectionné ou renommé, et quand le panneau principal change
dockcontainer : clic sur l'onglet (ou l'en-tête) du panneau déjà actifue_panel_selected à chaque clicrien : l'événement dit un CHANGEMENT de panneau actif
dockcontainer : panneau désépinglé (ib_pinned = false)sa languette ne s'ouvrait qu'au clic (la doc disait « au survol »)elle s'ouvre au survol (400 ms) ou au clic ; ouverte au survol, elle se replie quand la souris la quitte
dockcontainer : contrôle PB standard (MultiLineEdit, bouton…) dans un panneau flottantses notifications (modified, clicked, couleurs) n'arrivaient pluselles arrivent comme lorsqu'il est ancré
dockcontainer : masquer un panneau flottant (ib_visible = false)sa fenêtre restait ouverteelle se ferme ; réaffiché, le panneau revient ancré à sa place
dockcontainer : fenêtre flottantesa zone utile était plus petite que le panneau (barre de titre prise dessus), elle pouvait sortir de l'écran, et un titre à balises les montraitla zone utile a la taille du panneau, la fenêtre reste dans l'écran, le titre est du texte
dockcontainer : séparateur au clavierla première flèche le faisait sauter à 50 %il part de sa position affichée
json : valeur nulle donnée à of_set_number, of_add_number, of_set_boolean, of_add_boolean, ou valeur nulle ou vide donnée à of_set_raw / of_add_rawtout le document devenait nul (of_text rendait null) ou cessait d'être du JSON ; un booléen nul s'écrivait falsenull est écrit, le reste du document est intact
json : écrire dans un document CHARGÉ dont une clé s'écrit "k" : v ou avec un caractère échappé, suivi d'un saut de ligne, ou dont la racine est un tableau ; of_set_members sur un tel documentla clé était ajoutée en double (la relecture rendait l'ancienne valeur), l'écriture rendait -4 à tort, ou le document était remplacé par le fragmentla valeur est remplacée ou ajoutée comme sur un document bâti ; of_set_members rend -4 si la racine n'est pas un objet
json : of_set_*("items/1/qty", …) — une clé NEUVE dans un objet placé dans un tableau-40 : la clé est ajoutée au premier élément ; un tableau se traverse par un index qui existe, seule une clé d'objet est créée
json : chemin à segment vide (/name, a//b, a/)des clés nommées "" étaient créées ; of_remove pouvait retirer une autre valeur-5, rien n'est écrit ; un lecteur répond « absent »
json : of_load d'un nombre mal écrit (-, 01, +1, .5, 1., 1e)0, et of_is_valid vrai-4, comme tout JSON invalide
json : of_get_number d'un nombre à exposant (1e-7, 2.5E+3) ou à plus de 9 décimalesexposant ignoré (2.5E+3 lu 2,5), décimales coupées à 9exposant résolu, 17 chiffres significatifs gardés
json : lire ou modifier un gros document (une réponse d'API de 80 Ko, 2000 lignes)des secondes par appel (20 s pour of_count), l'application semblait figéeun temps proportionnel à la taille ; lire les lignes une à une (rows/1, rows/2…) ou parcourir les clés par of_name ne repart plus du début
listbar : of_add_section / of_insert_section sur une clé prise ou qui contient / ou une barre verticale ; of_add_item / of_insert_item sur une adresse prise ou sous une section que la barre n'a pas ajoutée ; of_remove_item, of_move_item, of_select_item, of_remove_section, of_move_section sur une adresse inconnue0, ignoré ; une entrée sous une section inconnue s'affichait sous la dernière section-5 ; of_add_section rend aussi -2 quand le composant n'est pas créé
listbar : une poignée tenue après of_remove_item, of_remove_section ou of_clearrestait en mémoirelibérée : IsValid() rend false
listbar : retirer ou vider ce qui porte la sélection (of_remove_item, of_remove_section, of_clear)la sélection partait sans événement ; après of_clear, of_selected_key rendait encore l'ancienneue_selection_changed(ancienne, "")
listbar : ue_layout_changedmuet au pli d'une section et au retrait d'une entrée ; levé à l'entrée dans le raillevé au pli (clic ou ib_collapsed d'une section) et au retrait ; plus au rail, qui n'est pas dans la disposition
listbar : rail (ib_collapsed = true)les entrées d'une section repliée disparaissaient ; une entrée sans icône montrait une case vide ; of_reset laissait la barre étroitetoutes les entrées, un filet entre les sections, l'initiale d'une entrée sans icône, le libellé au survol ; of_reset rend sa largeur à la barre
listbar : is_image d'une section ; couleur posée sur la section k quand une entrée a aussi la clé ksans effet ; l'entrée prenait la couleur aussil'icône est dessinée devant le titre ; seule la section prend la couleur
listbar : clavieraprès un changement de libellé ou une sélection, les flèches ne répondaient plus ; sans sélection, la barre était hors de la tabulation ; les titres de section ne se pliaient qu'à la sourisle focus reste sur l'entrée ; un arrêt de tabulation ; les titres se rejoignent aux flèches et se plient par Entrée ou Espace
listbar : entrée désactivée (ib_enabled = false) ; ib_auto_width sur une barre dépliéelibellé estompé, peu lisible en thème clair ; rapportait la largeur déjà donnéela couleur « désactivé » du thème ; la largeur que demande la plus longue ligne
listbar : glisser une entrée (ib_reorderable)bouton relâché hors de la fenêtre : l'entrée suivait encore la souris ; le clic de fin pouvait sélectionner l'entrée déposéele geste s'arrête au retour de la souris ; la fin d'un glisser ne sélectionne rien
menubar : ue_menu_openinglevé à côté du déroulant : ce qu'il changeait (griser Coller…) ne se voyait qu'à l'ouverture suivantele déroulant attend la fin de l'événement : le changement se voit à cette ouverture
menubar : of_item, of_remove_item sur une entrée dont la clé existe aussi dans une autre cascade (file/export/pdf, file/print/pdf)pouvaient viser l'autre entrée (la première trouvée) ; le raccourci affiché sur l'une déclenchait l'autrevisent l'entrée que l'adresse nomme ; une clé seule ne descend plus dans les cascades
menubar : of_add_menu, of_add_item, of_add_separator sur une clé prise, qui contient / ou une barre verticale, ou sous un menu ou un parent inconnu ; of_remove_item / of_remove_menu d'une adresse inconnue0 ; une entrée au parent mal tapé se rangeait à la racine du menu, une clé prise donnait deux entrées jumelles-5
menubar : une poignée ou un raccourci après of_remove_item, of_remove_menu ou of_clearla poignée restait en mémoire ; le raccourci restait armé et avalait la touche, qui n'arrivait plus à l'applicationpoignée libérée : IsValid() rend false ; raccourci désarmé
menubar : entrée grisée, masquée ou retirée pendant que son déroulant est ouvert ; raccourci d'une entrée sous une cascade griséele clic ou la touche levait encore ue_item_selectedrien
menubar : couleurs d'item (il_back_color…) d'un menu ou d'une entrée ; is_tooltip d'un menusans effet ; une couleur se relisait -1appliquées : sur le titre du menu, sur l'entrée dans le déroulant ; l'info-bulle d'un menu s'affiche sur son titre, une entrée du déroulant n'en affiche aucune
menubar : clavierles flèches restaient bloquées sur un menu grisé ; en RTL, gauche et droite inversées ; Alt+lettre d'un menu masqué cachait la même lettre d'un autre menu ; après Alt+lettre et un choix, l'Alt suivant éteignaitles menus grisés sont sautés ; les flèches suivent le sens d'écriture ; seul un menu affiché répond à sa lettre ; l'Alt suivant rallume la barre
menubar : une cascade dont toutes les entrées sont masquées ; of_count("file"), of_keys_atse choisissait comme une commande (file/export) ; les séparateurs étaient comptés (__sep0)grisée ; seules les entrées sont comptées
menubar : of_item("file") — une adresse d'un seul niveaurelisait le menu, et écrivait sur une entrée « file » qui n'existe pasne désigne rien : passez par of_menu("file")
Tout texte lu d'un composant ou d'un JSON : échappements \b et \frestaient écrits tels quelsdécodés (retour arrière, saut de page)
messagebox : une boîte qui n'a pas pu s'ouvrir (runtime WebView2 absent, moteur pas prêt)of_show et les raccourcis (of_info…) rendaient 0, comme une fermeture : of_info laissait croire qu'une boîte s'était montrée-4 (-6 si le runtime manque), la raison par of_get_last_error() ; of_choose et of_prompt rendent "" et of_get_last_error le dit. Un test = 1 pour « confirmé » reste juste
messagebox : Échap ou Alt+F4 pendant qu'un bouton d'annulation compte encore à rebours (of_add_button_timed)fermaient la boîte (0)ne font rien jusqu'à la fin du délai : il est là pour faire lire
messagebox : le texte du message et de l'instructionne se sélectionnait pas ; un appui dessus déplaçait la boîtese sélectionne et se copie (Ctrl+C copie la sélection, ou toute la boîte sans sélection) ; la boîte se déplace par son titre, son icône, ses marges
messagebox : une saisie de plus d'environ 900 caractères (of_prompt, ib_input)revenait vide, comme une annulationrevient entière
messagebox : al_hwnd = 0, une boîte ouverte depuis une autre, une boîte déplacée puis agrandiele bureau entier était désactivé ; la fenêtre se réactivait pendant que la première boîte attendait ; la boîte revenait au centrerien n'est désactivé sans propriétaire ; la fenêtre reste désactivée tant qu'une boîte l'attend ; la boîte garde sa place
progressbar : plage vide ou inversée (id_maximum = 0 puis id_value = 0)0 % quelle que soit la valeur100 % dès que la valeur atteint le maximum (un lot vide est terminé), 0 % avant
progressbar : le pourcentage affiché, l'anneauarrondi au plus proche (99,5 % affichait « 100% ») ; anneau figé à 128 px ; en attente, l'anneau tournait avec l'arc de la valeur (vide à 0 : rien ne bougeait)arrondi vers le bas : 100 % veut dire terminé ; l'anneau suit la taille du contrôle ; en attente, un arc fixe tourne ; moins d'animations demandé par Windows : l'attente pulse
Toute propriété double relue (id_value…) sur un poste à virgule décimalela partie décimale était mal lue (0,5 ne se relisait pas 0,5)relue exactement, quel que soit le séparateur du poste
speechout : un nouvel of_speak (ou of_close) pendant une lecturela lecture coupée ne levait aucun ue_stoppedtoute lecture commencée finit sur un ue_stopped
speechout : il_timeout_ms = 0coupait la lecture synchrone au bout de 5 ssans limite (24 heures au plus)
speechout : une voix qui n'a pas pu naître (runtime WebView2 absent, page refusée)of_speak, of_speak_from, of_pause, of_resume, of_enqueue, of_clear_queue rendaient -1, of_open le code brut de la DLL-2 (composant non créé, comme partout), is_last_error dit pourquoi ; -4 si la page n'a pas répondu
speechout : of_speak_sync appelé depuis un event levé pendant un autre of_speak_synccoupait la lecture de l'appel extérieur, qui rendait quand même 0refusé : -4, is_last_error = "already speaking synchronously"
speechout : of_speak_from au-delà de la dernière phrase0, rien n'était lu-5
speechout : of_is_speaking() juste après of_speakfalse tant que la liste des voix n'était pas arrivéetrue dès of_speak
speechout : of_pick_voice("", genre), ou liste des voix illisiblechoisissait dans la langue de la page ; un échec vidait is_voice"" = is_lang ; un échec garde is_voice et remplit is_last_error
speechout : of_voice_used, of_duration, of_spoken_text juste après avoir changé is_lang ou le dictionnairepouvaient répondre sur les réglages précédentsrépondent sur les réglages posés à l'instant
speechout : erreur de script dans la page de la voixsilencieuseue_error("script error: …")
statictext : il_back_color avec ii_corner_radiusle fond remplissait tout le rectangle, seul le trait s'arrondissaitle fond suit l'arrondi ; hors des coins, la couleur de l'objet sur lequel le bloc est posé, que le userobject prend aussi
statictext : is_marquee_direction en lecture de droite à gauchesens inversé : MARQUEE_START défilait vers la fin, "left" vers la droiteMARQUEE_START défile vers le début de lecture ; "left" / "right" restent physiques
statictext : relire il_back_color, ii_marquee_speed, is_marquee_direction, ib_marquee_overflow_only, ib_marquee_pause_on_hover, is_font_family-1, 0, "", false quoi qu'on ait posé ; une famille à espace entre guillemetsla valeur posée
statictext : ii_marquee_speed = 0gardait la vitesse précédentevitesse par défaut (60)
statictext : of_reset après une bordurecouleur et épaisseur gardées : la bordure suivante en héritaiteffacées
statictext : ib_track_mouse, composant désactivé pendant le survolue_mouse_leave jamais levéue_mouse_leave levé à la sortie
statictext : défilement (ib_marquee)un [foldarea] ne se repliait plus après ; avec ib_marquee_overflow_only, un changement de HAUTEUR repartait du début ; avec ib_wrap = false, ue_text_overflow(true) à tortcorrigé : le texte n'est plus recopié, seule une vraie LARGEUR neuve se remesure, et le défilement montre tout le texte
statictext : ib_hover_effect et liens survolés sur un thème sombreassombris (contraste réduit)éclaircis
Texte riche : [symbol=clock]affiché tel quelun glyphe monochrome ; un nom inconnu reste du texte
statusbar : of_add_panel / of_insert_panel sur une clé prise ou qui contient / ou une barre verticale ; of_move_panel, of_remove_panel, of_clear_menu, of_add_menu_separator sur un panneau inconnu ; of_add_menu_item / of_insert_menu_item sous un panneau inconnu ou sur une entrée prise ; of_remove_menu_item, of_move_menu_item sur une adresse inconnue0, ignoré-5
statusbar : of_insert_panel(…, 0)ajouté en fin de barreen tête, comme toute position (0 ou moins = en premier)
statusbar : un séparateur (of_add_sep) dans of_count, of_keys_at et les positions de of_insert_panel / of_move_panelcompté comme un panneau à clé videignoré : une position compte les panneaux
statusbar : un séparateur entre deux panneaux ALIGN_ENDdessiné à la fin du groupe de débutentre les deux : il ouvre le groupe du panneau qui le suit
statusbar : clic droit sur un panneau non cliquableaucun événementue_panel_rclicked (un panneau désactivé reste muet)
statusbar : of_panel(k).ii_progress relu sur un panneau sans barre0, comme une barre à 0 %-1
statusbar : of_menu_item("k"), une adresse d'un seul niveauécrivait sur le panneau k (ib_enabled le grisait)ne désigne rien : n'écrit nulle part, se relit vide
statusbar : couleurs et info-bulle d'un panneau après of_clear, puis un panneau ajouté sous la même clérepris par le nouveau panneauoubliés : le panneau part d'une base propre
statusbar : is_state en thème sombre ; panneau désactivécouleurs du thème clair, peu lisibles ; grisé par transparence, fond perdu au survolune palette sombre lisible ; grisé par la couleur du thème, fond gardé
statusbar : un panneau dont toutes les entrées de liste sont masquéesmain et chevron, clic sans effetun panneau ordinaire, cliquable ou non selon ib_clickable
statusbar, toolbar : flèches Gauche / Droite en lecture de droite à gauche (RTL)à contresens : Droite allait vers la gauche de l'écrandans le sens de l'écran, comme l'onglet et le ruban
stepbar : poser ii_currentrien n'était levéue_step_changed quand la barre bouge, comme la doc le promettait
stepbar : retirer, insérer ou déplacer une étape avant l'étape en coursl'étape en cours changeait sans rien dire (c'était un rang)la même étape reste en cours ; si c'est elle qu'on retire, la barre passe à la suivante atteignable et lève ue_step_changed
stepbar : ii_current posé avant les étapes ; of_clear_stepsramené à la première étape ; l'étape en cours survivait au vidagegardé et appliqué dès que l'étape existe ; le vidage repart sur la première étape
stepbar : of_add_step / of_insert_step sur une clé prise ou qui contient / ou une barre verticale ; of_move_step, of_remove_step sur une clé inconnue0, ignoré-5
stepbar : of_insert_step(…, 0)ajouté en fin de barreinséré en tête, comme toute position de la bibliothèque (of_add_step ajoute en fin)
stepbar : flèches gauche / droite en écriture de droite à gauchela flèche droite allait à l'étape suivante, dessinée à gaucheinversées : la flèche gauche va à l'étape suivante
tab : of_add_page / of_insert_page avec une clé qui contient / ou une barre verticale ; un envoi en échec0 ; la page restait hébergée et sa clé prise-5 ; un envoi en échec rend son code, la page revient à sa fenêtre et la clé reste libre
tab : of_select_page d'une page masquée, désactivée ou au-delà du plafond de démonstration0, et la page s'affichait sous une bande sans onglet actif-5, rien ne bouge
tab : croix, raccourci (is_shortcut), « Fermer tout / les autres / à droite » sur un onglet désactivé ou masquél'onglet s'activait ou se fermait, et PB libérait sa pagesans effet : un onglet qu'on ne peut ni voir ni atteindre ne s'active ni ne se ferme
tab : l'onglet actif est fermé, retiré ou masquéle suivant ou le premier prenait la main, même masqué ou désactivé ; as_from_key de ue_selection_changed était videle voisin sélectionnable prend la main (droite, sinon gauche) ; as_from_key nomme l'onglet réellement quitté, même disparu
tab : plus aucun onglet visible (tous masqués, ou une disposition qui les masque)la page de l'ancien onglet restait affichée, sans événementla page est cachée et ue_selection_changed(ancien, "") est levé ; ré-afficher un onglet le sélectionne
tab : une poignée tenue après of_remove_page ou une fermeture ; son raccourcirestaient ; une page rouverte sous la même clé reprenait couleur, infobulle et ancien raccourcilibérés : IsValid() rend false, la page revient neuve
tab : of_set_layout avec un texte qui n'est pas du JSON0, et le message partait cassé-5, rien n'est envoyé
tab : clavier dans la bande d'ongletsEntrée perdait le focus ; les flèches s'arrêtaient sur les onglets désactivés ou débordés ; ni Haut/Bas en bande verticale ni inversion en écriture de droite à gauchele focus reste sur l'onglet ; les flèches suivent l'axe de la bande et sautent ce qui ne répond pas ; Suppr ferme un onglet fermable
tab : texte d'un onglet désactivé ; infobulle d'un onglet au titre tronquéestompé en bloc (illisible au survol en office2007 sombre) ; le nom complet natif masquait votre infobulletexte dans la couleur désactivée du thème, lisible ; votre infobulle passe devant
tilesbox : of_get_layoutrendait toujours "" : une disposition sauvegardée ne se restaurait jamaisla disposition entière, le même texte que ue_layout_changed ; elle garde aussi la taille et la visibilité de chaque tuile et la visibilité de chaque groupe
tilesbox : of_set_layout qui nomme une tuile sous un autre groupe que le sien ; un texte qui n'est pas du JSONla première tuile de même clé, dans n'importe quel groupe, y était déplacée ; 0une tuile se retrouve par son groupe et sa clé : l'entrée est ignorée ; -5 sur un texte qui n'est pas du JSON
tilesbox : of_add_group sur une clé déjà prise ; of_add_tile / of_insert_tile sur une clé prise ou sous un groupe jamais ajouté ; une clé vide, avec / ou ``0 ; un groupe repris était renommé, une tuile sous un groupe inconnu le créait sous sa clé-5, rien n'est ajouté : ajoutez d'abord le groupe par of_add_group
tilesbox : of_move_tile, of_remove_tile, of_add_live_item, of_clear_live_items sur une tuile inexistante ; of_remove_group sur un groupe inexistant0-5
tilesbox : une poignée tenue après of_remove_tile, of_remove_group, of_clear, ou une tuile glissée dans un autre grouperestait en mémoire ; une tuile recréée sous la même adresse reprenait couleurs et infobulle de l'ancienne, une tuile glissée les perdaitla poignée est libérée (redemandez-la par of_tile / of_group) ; couleurs et infobulle suivent la tuile glissée et partent avec ce qui est retiré
statusbar, stepbar, crosstab : une poignée tenue après of_remove_panel, of_remove_menu_item, of_clear_menu, of_clear (statusbar), of_remove_step, of_clear_steps (stepbar), of_remove_calc_field ou of_remove_calc_measure (crosstab)restait en mémoire jusqu'à la destruction du composantlibérée : IsValid() rend false ; redemandez-la par of_panel, of_menu_item, of_step ou of_field
Tous les composants à items : relire il_back_color_hover / il_text_color_hover d'un item jamais coloré0, le noir-1, « la couleur du thème », comme les trois autres couleurs d'item
tilesbox : relire ib_enabled / ib_visible d'un groupe, ou ii_badge_sizefalse, false, 0 quoi qu'on ait poséla valeur en vigueur
tilesbox : groupe désactivé (ib_enabled = false)son entête le repliait encore (clic, Entrée) et levait ue_group_toggled ; une tuile glissée y tombaitinerte : ni repli, ni événement, ni dépôt
tilesbox : couleurs d'item (il_back_color, il_text_color, il_accent…) posées sur un groupesans effet ; une couleur de groupe a pouvait peindre une tuile a d'un autre groupeelles peignent l'entête du groupe (fond, titre, survol, filet d'accent), jamais ses tuiles
tilesbox : of_tile(""), ou une adresse à un ou trois niveauxposer une propriété arrêtait l'application (« Array boundary exceeded ») ou écrivait sur le groupeun handle inerte : il n'écrit rien et se lit vide
tilesbox : clavier et lecteur d'écranle focus se perdait à chaque mise à jour venue de PB (un badge) et le menu de taille se fermait ; menu de taille à la souris seulement ; en RTL, les flèches à contresens ; libellés lus avec leurs balisesfocus et menu gardés ; menu de taille au clavier (flèches, Entrée, Échap) ; flèches dans le sens de lecture ; texte nu
toaster : il_max_visibledéfaut 5, envoyé par CHAQUE toaster : un toaster qui avait posé 10 retombait à 5 dès qu'un autre affichait un toastdéfaut 0 = rien n'est envoyé ; le plafond est COMMUN à l'application et la dernière valeur posée l'emporte (5 tant que personne ne l'a posé)
toaster : of_show d'un toast qui attend sa placerendait 0 : le toast ne pouvait pas être fermé par of_close, et ses événements portaient un id jamais reçu ; file pleine (200) : 0 aussi, toast perdu sans un motun vrai identifiant, tout de suite ; of_close le retire de la file ; file pleine : -4
toaster : deux toasts sans is_key qui portent un bouton de même cléle second REMPLAÇAIT le premier (la clé du bouton était prise pour celle du toast) et of_show rendait l'id du premierdeux toasts, deux identifiants ; seul is_key met à jour en place
toaster : événements de plusieurs toastersrangés par FENÊTRE : deux toasters ancrés à la même fenêtre se volaient leurs événements, et ceux d'un toaster détruit étaient livrés au suivantchaque toaster reçoit ceux de SES toasts ; un toaster détruit ne reçoit plus rien, ses toasts restent à l'écran, muets
toaster : pbm_custom02 de la fenêtre ipo_ownerla fenêtre d'ancrage recevait un pbm_custom02 à chaque événement de toast, même sans ipo_receiverseule une fenêtre posée dans ipo_receiver le reçoit ; si vous aviez mappé pbm_custom02 de votre fenêtre pour les toasts, posez ipo_receiver, ou mieux, retirez ce code : les événements arrivent seuls
toaster : affichageun toast restait sur place quand sa fenêtre bougeait ; un toast de plus de 800 px (une longue trace d'erreur) n'apparaissait JAMAIS ; largeur non mise à l'échelle (180 px à 200 %) ; mettre à jour un toast survolé relançait toute la pileil suit sa fenêtre ; le texte défile dans le toast, plafonné ; largeur à l'échelle de l'écran ; la pile reste en pause sous la souris
toolbar : ajouts, of_add_separator, of_move_item, of_remove_* sur une clé prise, avec / ou ``, une barre inconnue ou une adresse inconnue0, ignoré — une faute de frappe dans le nom d'une barre créait une barre fantôme-5 ; seule main n'a pas besoin d'of_add_bar
toolbar : of_clear, of_remove_bar, of_remove_itemles poignées restaient, les raccourcis restaient armés, et un outil recréé sous la même clé retrouvait les couleurs de l'ancienpoignées libérées, raccourcis désarmés, couleurs et info-bulles oubliées ; redemandez une poignée après un retrait
toolbar : of_item d'une adresse à trois niveaux (une entrée de menu)agissait sur l'OUTIL de la barre qui portait le même nom que l'entréene désigne rien ; une entrée se pilote par of_menu_item(adresse)
toolbar : entrée choisie dans un déroulant replié dans le chevronue_menu_selected sans le parent de la cascade, sous un autre déroulant, ou videl'adresse complète, comme dans la barre
toolbar : ii_index d'une barrene déplaçait jamais une barre vers la droitela barre prend le rang demandé
toolbar : of_add_bar(clé, bande, rang) sur un rang déjà pris, ou une bande au-delà des autresordre indéfini ; la bande se relisait telle quelle (5 pour la deuxième rangée)elle s'insère devant la barre qui tenait le rang ; les bandes se resserrent
toolbar : of_count, of_keys_at d'une barre, rang d'of_move_itemcomptaient les séparateurs, sous une clé videles outils seulement : un séparateur n'a ni clé ni rang
toolbar : Entrée dans une zone de textevalidait le champ ET pressait le bouton par défaut de la fenêtrevalide le champ seulement ; Échap lui rend son texte validé
toolbar : is_shortcut relu ; ii_band / ii_index d'une barre inconnuectrl+s (normalisé) ; 1Ctrl+S, tel qu'écrit ; 0
toolbar : couleur ou info-bulle posée sur une BARRE (of_bar)sans effet, ou peignait l'outil qui portait le même nomappliquée à la barre, et à elle seule
toolbar : raccourci d'un outil masqué ou au-delà du plafond de démonstrationavalait la touchela touche va à l'outil suivant qui porte le même accord
webbrowser : une page qui ne se charge pas (hôte inconnu, réseau, certificat, of_stop)levait ue_load_completed, comme un succèslève ue_load_failed(as_url, al_status) à la place
webbrowser : des mots dans is_address (« facture 2026 »)partaient en https://facture 2026 et plus aucune navigation ne se faisait ensuiterefusés avec ue_error, la suite se charge ; recherche si is_search_url est posé
webbrowser : un chemin disque (C:\temp\x.html) ou //hôte/x dans is_addressprécédé de https://, donc introuvablefile:///C:/temp/x.html ; https://hôte/x ; javascript: refusé
webbrowser : is_address relu après un lien suivi ou Précédentla dernière adresse poséela page affichée
webbrowser : of_go_back, of_go_forward, of_stop juste après is_addresspouvaient passer AVANT l'adresse ; of_stop laissait repartir les pages en attentejouent dans l'ordre écrit ; of_stop abandonne aussi les pages en attente
webbrowser : of_save_as_png, of_save_as_jpg, of_print_to_pdf, of_printcapturaient ou imprimaient la barre d'adressele site affiché
webbrowser : lien target=_blank, window.open après un clicrien ne se passaitla page s'ouvre dans la vue, ue_new_window le dit
webbrowser : réponse de of_execute_javascript de plus de 4 095 caractèrescoupée sans le direentière
webbrowser : F5, Ctrl+R, Ctrl+molette dans la barre d'adresserechargeaient ou zoomaient la barre elle-mêmesans effet dans la barre ; actifs dans le site
webbrowser : clic droit dans un champ de saisie avec ib_context_menuPrécédent / Suivant / ActualiserCouper / Copier / Coller
webbrowser : Tab ou of_focus_webview sans barre d'adresse ; fichier déposé sur le site avec ib_allow_dropfocus perdu dans une barre de 0 px ; fichier ouvert par le navigateurle focus va au site, Tab en ressort vers votre fenêtre ; ue_drop_files
pdfviewer : is_source relu, et as_source de ue_load_completedl'adresse interne /_file/?p=…ce que vous avez écrit (doc\notice.pdf)
pdfviewer : fichier absent, pas un PDF, site injoignable ou qui refuse le cadreue_load_completed sur une page d'erreur, ou aucun événementue_load_failed(as_source, as_reason) (constantes REASON_*), la visionneuse reste vide
pdfviewer : http://, data: d'un autre type que PDF, page web en https://affichés (ou cadre vide pour http://)refusés : ue_load_failed avec REASON_INSECURE ou REASON_NOT_PDF
pdfviewer : un # dans is_sourcecoupait le chemin (Devis #12.pdf introuvable) ; le fragment d'une URL se mêlait à ii_page / ii_zoomun # fait partie du nom du fichier ; le fragment d'une URL est ignoré, page et zoom passent par les propriétés
pdfviewer : ii_page posé avant is_sourceperdu : le document s'ouvrait à la page 1gardé pour ce document ; sans page posée depuis le dernier is_source, un nouveau document s'ouvre à la page 1
pdfviewer : PDF régénéré au même chemin puis of_refresh ; PDF de 32 Mo et plus ; chemin de plus de 260 caractèresl'ancienne version pendant 5 minutes ; rien ; introuvablele fichier tel qu'il est sur le disque ; affiché (servi par morceaux) ; affiché
pdfviewer : lien suivi dans le document ; of_printle site remplaçait le document, sans retour ; imprimait la page qui encadre le documentle document reste, ue_link_clicked(as_url) vous donne l'adresse ; of_print imprime le document (-4 sans document)
picture, button, tilesbox : il_badge_color0 = la couleur du thème ; le noir était inatteignable ; non posée, se relisait 0-1 = non posée (la couleur du thème), comme toute autre couleur ; 0 est le noir. Remplacez il_badge_color = 0 par -1
picture : id_zoom posé avant ib_zoomablese relisait à la valeur posée, l'image restait au cadrageignoré : id_zoom reste 1.0 tant que ib_zoomable est faux ; posez ib_zoomable d'abord
picture : ib_mirror sur une image tournée d'un quart de tour ; is_align / is_valign avec une rotationretournement vertical à l'écran ; le placement tournait avec l'imagemiroir et placement se lisent à l'écran, quelle que soit la rotation
picture : glisser l'image zoomée ; molette ; image désactivée (statictext désactivé aussi)ue_clicked à chaque déplacement ; zoom vers le centre, l'image pouvait sortir du cadre ; les dépôts de fichiers restaient acceptésaucun clic après un déplacement ; zoom vers le pointeur, l'image couvre toujours son cadre ; désactivée, elle refuse tout dépôt ; ue_error nomme la source
xml : une lecture (of_get_value, of_count, of_is_valid…) ou une modification après une constructionagissait sur le dernier document CHARGÉ, ou sur rienle document bâti est chargé et devient LE document ; le of_start_element suivant en commence un nouveau
xml : of_load en échec (vide, mal formé), of_start_element après un chargementl'ancien document restait lisible et modifiable (of_is_valid vrai) ; un document à moitié bâti restait dans of_xmlrien ne reste
xml : of_xml, of_pretty, of_get_values d'un gros documentcoupé sans le dire au-delà de quelques Moentier
xml : of_get_value d'un XPath de valeur (count(//line), sum(//@qty))videla valeur en texte (3, true)
xml : XPath dont le préfixe est déclaré plus bas que la racine (réponse SOAP)vide sans of_register_namespacerésolu
xml : is_last_error après un XPath invalide, une page qui ne répond pas, un refus ; codes de of_register_namespace / of_clear_namespacesvide, ou « no node matched » quelle que soit la cause ; les modifications rendaient -4 quand la page manquait ; 0 toujours ; une page sans réponse rendait le texte nullla vraie raison ; -2 quand la page ne répond pas ; une URI vide est refusée (-5) ; vide plutôt que null
xml : of_prettyperdait CDATA, commentaires, instructions de traitement et déclaration XML, et remaniait le texte mixtetout est gardé ; un élément qui contient du texte reste sur une ligne
xml : construction — saut de ligne ou tabulation dans un attribut, CR dans un texte, caractère de contrôle, nom invaliderelus altérés ; document mal formé ; nom écrit tel quelrelus identiques ; caractère de contrôle retiré ; nom refusé (is_last_error), l'élément laissé de côté
xml : un document qui contient un élément <parsererror> ; message d'un XML mal formérefusé comme mal formé ; message encadré de « This page contains the following errors »chargé ; la ligne d'erreur seule
xml : of_remove de nœuds imbriqués, de la racine, d'un attribut ; of_set_value("/") ; of_add_child sous un attributcomptait deux fois ; vidait le document ; l'attribut restait ; 0 sans effet ; « parent not found »le compte réel ; la racine reste (0 et is_last_error) ; l'attribut est retiré ; -4 ; « the node cannot have children »
xml : of_close puis une lecture ; ipo_owner posé après la première lecturele document chargé était perdu ; ignoré jusqu'à of_closele document est gardé et rechargé ; transmis à la lecture suivante
thèmes metro-light et metro-dark : texte sur l'accentblanc sur le bleu #25a0da dans les deux thèmes (en-têtes de volet, onglet actif, bouton de l'application du ruban, tuiles) : peu lisiblemetro-light : l'accent devient le bleu plus profond #1b76a1, texte toujours blanc ; metro-dark : l'accent reste #25a0da, le texte posé dessus devient presque noir (#1b1b1b)
thèmes office-dark, office2003-dark, office2003-light, office2007-light : couleurs d'accent et d'en-têteen mode sombre, l'accent se lisait mal sur la page (puce d'étape, pastille), et le texte blanc sur le survol de l'accent et les en-têtes de colonnes du crosstab ; en mode clair, le haut des dégradés du bouton de l'application et des en-têtes de volet était trop pâle pour le texte blancoffice-dark : accent #1178d1, survol #0f6cbd ; office2003-dark : accent #4574cb, survol #2f5aa8 ; en-têtes du crosstab plus foncés au survol et sur les totaux ; office2003-light et office2007-light : haut du dégradé plus profond (#3e73cf, #4275c5), en-têtes de volet d'office2007-light plus opaques. Texte toujours blanc, au moins 4,5:1
texte posé sur une couleur choisie par l'application (il_accent, couleur d'un item, en-tête de volet, pastille)blanc jusqu'à une couleur assez claire : un bleu moyen comme #25a0da recevait du blanc à 2,95:1blanc ou presque noir (#1b1b1b), celui des deux qui se lit le mieux (rapport de contraste WCAG) : #25a0da reçoit désormais du texte sombre
jsontree : of_clearvidait l'arbre ET remettait ib_wrap et ib_search_enabled à leurs défautsvide l'arbre seulement ; les réglages restent (c'est of_reset qui remet tout)
jsontree : is_json = ""levait ue_error « Invalid JSON »vide l'arbre sans erreur, comme la doc le promettait
jsontree : nombres et clés affichés, is_json reluréécrits par le moteur : 12345678901234567890 affiché 12345678901234567000, 1.10 → 1.1, la première de deux clés identiques perdue ; is_json se relisait compacté, et vide après un JSON invalidetels que reçus, les deux clés comprises ; is_json se relit tel qu'il a été posé
jsontree : of_match_count, al_count de ue_search_resultcomptaient les LIGNES ; deux occurrences sur une ligne étaient toutes deux « courantes »comptent les OCCURRENCES, une seule est courante et of_search_next passe de l'une à l'autre
jsontree : blocs ouverts par une rechercheTOUS ceux qui contenaient une correspondance, pour de bon : chercher « e » ouvrait tout le documentseulement ceux qui cachent l'occurrence COURANTE ; of_clear_search rend les plis d'avant la recherche
jsontree : of_select_pathune ligne cachée dans un bloc replié restait invisible ; un chemin inconnu rendait 0les blocs qui la cachent s'ouvrent ; un chemin inconnu rend -5 et la sélection ne bouge pas
jsontree : replier le bloc qui contient la sélectionla sélection devenait invisible, et la flèche suivante repartait du hautla sélection passe sur le bloc replié ; au geste de l'utilisateur, ue_selection_changed le dit
xmltree : of_clearvidait l'arbre ET remettait ib_wrap et ib_search_enabled à leurs défautsvide l'arbre seulement ; les réglages restent (c'est of_reset qui remet tout)
xmltree : is_xml = ""levait ue_error « Invalid XML » et affichait une erreur rougevide l'arbre sans erreur, comme la doc le promettait
xmltree : is_xml relure-sérialisé par le moteur : guillemets changés, retours à la ligne perdus, vide après un XML invalidese relit tel qu'il a été posé, un texte invalide compris
xmltree : ce qui s'afficheun CDATA était invisible (l'élément s'affichait vide), commentaires, instructions de traitement et déclaration absents, le texte d'un contenu mixte recollé avant les enfants, un texte rogné de ses blancs, une valeur d'attribut à guillemet affichée telle quellechaque nœud à sa place, dans l'ordre du document ; la ligne reste du XML (guillemet choisi ou &quot;, &#10;, &amp;, &lt;) ; les blancs significatifs restent
xmltree : of_match_count, al_count de ue_search_resultcomptaient les LIGNES ; une correspondance à cheval sur deux morceaux (id="4152") était comptée sans être surlignéecomptent les OCCURRENCES, chacune surlignée, une seule est courante
xmltree : éléments ouverts par une rechercheTOUS ceux qui contenaient une correspondance, pour de bonseulement ceux qui cachent l'occurrence COURANTE ; of_clear_search rend les plis d'avant la recherche
xmltree : of_select_pathune ligne cachée dans un élément replié restait invisible ; un chemin inconnu rendait 0les éléments qui la cachent s'ouvrent ; un chemin inconnu rend -5 et la sélection ne bouge pas
xmltree : ue_selection_changedlevé aussi sans changement (Fin sur la dernière ligne) ; replier l'élément qui contenait la sélection la rendait invisible, sans rien direlevé seulement quand la sélection change ; au pli, la sélection passe sur l'élément replié et l'événement le dit
xmltree : ue_errorle texte brut de la page d'erreur du moteur ; un élément <parsererror> du document passait pour une erreurla seule ligne de l'erreur (« error on line N at column M: … ») ; un <parsererror> du document est un élément comme un autre
restclient : cookies d'une requête synchroneaucun gardé : chaque of_get / of_post ouvrait sa propre session ; ib_keep_cookies ne valait que pour l'asynchroneune session par objet, commune au synchrone et à l'asynchrone : une connexion synchrone vous garde connecté pour les appels suivants
restclient : ib_keep_cookies changé après la première requêtesans effet jusqu'à of_closeappliqué tout de suite ; à false, les cookies déjà gardés sont oubliés
restclient : redirection vers un autre hôte ou portseuls Authorization, Cookie et l'authentification Basic tombaient : une clé d'API (X-Api-Key…) partait chez le tiersaucun en-tête posé par of_set_header ne suit, seul Content-Type reste
restclient : of_set_bearer("") après of_set_basic ; of_set_basic puis of_set_bearer ; of_set_basic("", "")le mot de passe Basic continuait de partir ; deux Authorization à la fois ; Basic Og== envoyéune seule authentification à la fois : chacune remplace l'autre, un jeton ou un utilisateur vide la retire
restclient : HEAD, ou réponse 204 / 304 qui annonce une taille-4 « connection lost », et rejouée en asynchronele statut (200, 304…)
restclient : corps avec un octet invalide ; charset=iso-8859-1 ou utf-16tout le corps relu en Windows-1252 ; charset ignorél'octet invalide seul devient un caractère de remplacement ; le charset annoncé est lu
restclient : corps en texte de plusieurs centaines de Mogardé trois fois en mémoire : un processus 32 bits pouvait mourir-4 « body too large : use of_download » au-delà de 64 Mo
restclient : cent requêtes asynchrones lancées d'un coupcent fils en parallèlesix au plus en même temps, les suivantes attendent leur tour
restclient : une requête asynchrone envoyée plus souvent que toutes les 50 ms (un timer de télémétrie)aucune réponse livrée tant que le flux duraitles réponses arrivent au fil de l'eau
restclient : of_cancel d'un id inconnu ; d'une requête dont la réponse est arrivée-1 ; 0 (mais c'est ue_response qui arrivait)-5 ; -4, trop tard
restclient : of_response_text() après of_download ; après un of_download(url, "")le nombre d'octets écrits ; la réponse d'avantvide : ce corps-là est dans le fichier ; vide
restclient : lire une réponse asynchrone pendant ue_progressune mémoire en cours d'écriture : plantage possiblevide, of_status(id) = 0 tant que la requête court
video : changer de film (is_source, of_play(source))le segment, les sous-titres, les marqueurs et les chapitres de l'ancien film restaientils partent avec lui (posés avant tout film, ils attendent le premier) ; un film de la liste de lecture garde ses sous-titres. Posez-les après is_source
video : of_go_chapter, of_next_chapter, of_previous_chapterlevaient ue_seeked ; of_go_chapter au-delà du nombre de chapitres rendait 0 sans rien faireue_seeked et ue_chapter_changed, comme un clic sur la barre ; -5
video : of_add_source alors qu'un is_source est poséla liste ne démarrait jamais, of_next allait au premier filmla première entrée se charge tout de suite (sauf si le film posé JOUE : la liste le suit à sa fin)
video : ue_started après of_stop ou la fin du film, puis of_playjamais : une fois par sourceà chaque nouvelle lecture (pas à la reprise d'une pause)
video : of_play sur un film en erreur ; of_reset ; ii_rate au film suivant« en cours » pour toujours, sans événement ; l'ancien film restait chargé (of_duration, of_capture) ; retour à la vitesse normaleue_failed de nouveau ; le film est déchargé ; la vitesse tient
video : of_capture vers un fichier impossible à écrire ; vers « \x » ou « C:x »-4 (la doc disait -5) ; écrits selon le dossier courant-4, et aucun fichier tronqué ne reste ; -5 : donnez un chemin complet
video : plein écran puis Alt+Tab vers une autre applicationle film restait au-dessus de toutl'autre application passe devant ; revenir à la vôtre ramène le film au-dessus de tout
pdfviewer : un clic simple sur un lien du PDFrien : seul Ctrl+clic levait ue_link_clickedue_link_clicked(url), le document reste affiché
webbrowser : une page data: (is_address = "data:text/html,…")affichée, mais aucun ue_load_completedue_load_completed avec l'adresse demandée
webbrowser : une nouvelle fenêtre demandée par le site vers file:, data: ou mailto:ouverte dans la vue, ue_new_window levérefusée : ue_error, pas de ue_new_window ; seuls http et https s'ouvrent
webbrowser : un site qui demande la caméra, le micro, la position, les notificationsinvite du navigateur à l'utilisateur, réponse retenuerefusé sauf si ue_permission_requested renvoie true ; rien n'est retenu
webbrowser : cookies, sessions et stockage des sitesdans le profil commun des composantsdans un profil de navigation à part : une session ouverte en 3.0 n'est pas reprise (se reconnecter une fois) ; of_clear_browsing_data l'efface
webbrowser : is_search_url sans %s, sans http(s):// ou en javascript:accepté : chaque recherche échouait ou perdait le texte tapérefusé : ue_error, le moteur en place reste
webbrowser : gestion/ ou [::1]/x dans is_address« pas une adresse » (ou une recherche)https://gestion/, https://[::1]/x ; le mot seul reste un texte
webbrowser : clic droit sur une sélection, un lien, une image avec ib_context_menuPrécédent / Suivant / Actualiser seulementen plus : Copier, Ouvrir le lien, Copier l'adresse du lien, Copier l'image
tab : onglet fermable désactivé (ib_enabled = false)la croix disparaissait mais sa place restait videni croix ni place vide : l'onglet a la largeur d'un onglet non fermable
video : of_chapters sur un titre qui contient `` ou une tabulationcoupé en deux chapitreslu tel quel
video : un .srt en Windows-1252 ou en UTF-16accents illisibles ; aucun sous-titrelu correctement
commandpalette : of_open sans runtime WebView2 ; toaster : of_show sans runtime-1-6, comme la boîte de message
crypto, xml, restclient : of_open quand la page ou le client ne peut pas naîtrele code brut de la DLL (-1, -3…)-2, et is_last_error dit pourquoi

Si vous aviez contourné l'un de ces défauts — par exemple en traitant ue_menu_selected avec une adresse vide pour rattraper les clics d'un groupe replié —, retirez le contournement : l'événement documenté arrive désormais.

11.4 Le générateur n_pbt_menu2ribbon #

En 3.0, le code écrit par n_pbt_menu2ribbon employait des méthodes de poignée qui n'existaient plus : il ne compilait pas sans retouches. En 4.0 il écrit l'API actuelle — chaque ajout par son adresse depuis le composant —, reprend les sous-menus à toute profondeur, reporte les items grisés et cochés, et son routeur couvre ue_clicked, ue_toggled et ue_menu_selected. Les clés changent : chacune est désormais le ClassName de l'item de menu (m_fichier/g1/m_ouvrir) au lieu du chemin pointé (m_principal.m_fichier.m_ouvrir).

La recette : un ruban déjà construit à la main, ou à partir d'un code généré puis corrigé, n'a rien à changer. Pour repartir du générateur, relancez-le et collez aussi le nouveau routeur : l'ancien lisait des clés pointées.

11.5 Ce qui a été ajouté #

Rien de ce qui suit ne demande de modifier votre code. Les nouveaux composants de la 4.0 sont présentés dans les notes de version.

ObjetAjouté
ribbonof_add_menu_separator accepte l'adresse d'une entrée : la ligne va dans la cascade placée sous elle
ribbonof_add_menu_item et of_add_menu_check acceptent une cascade de toute profondeur, et chaque niveau se pilote par of_menu_item(adresse)
menubarof_add_separator accepte l'adresse d'une entrée (file/export) : la ligne va dans sa cascade ; of_menu(...) porte les couleurs (il_accent, il_back_color…) et l'info-bulle du titre
crosstabof_set_label_filter(as_field, as_type, as_a, as_b) en texte (LABEL_CONTAINS, LABEL_BEGINS, LABEL_ENDS) et les constantes LABEL_GT, LABEL_LT, LABEL_BETWEEN : la forme à deux double ne pouvait passer qu'un nombre
cryptoKEYFORMAT_TEXT, KEYFORMAT_HEX, KEYFORMAT_BASE64 et une surcharge d'of_hmac, d'of_jwt_sign et d'of_jwt_verify qui les prend (une clé en OCTETS : secret fourni encodé, AWS SigV4) ; une entropie facultative pour of_protect et of_unprotect
cryptoof_hmac_verify (un HMAC reçu — webhook — comparé en temps constant) ; of_jwt_header et une surcharge d'of_jwt_sign qui ajoute des membres à l'en-tête (kid) ; of_totp_verify(…, ref al_step), le pas accepté, pour refuser un code déjà servi ; il_password_hash_rounds
messageboxof_get_last_error() : pourquoi la dernière boîte n'a pas pu s'ouvrir (chaîne vide si elle s'est ouverte)
n_pbt_utilsof_dir_has_subfolders(as_dir, ab_include_hidden) : la même question en comptant aussi les dossiers cachés, système et les jonctions
n_pbt_utilsof_dw_date_order() : l'ordre dans lequel un DataWindow écrit une date sur ce poste (dmy, mdy, ymd)
speechoutof_is_paused() : vrai tant que la lecture est en pause
Texte richela balise [symbol=nom] : dix-huit glyphes monochromes qui suivent la couleur du texte (chapitre 4)
toolbarof_menu_item(adresse) → n_pbt_toolbar_menu_item : chaque entrée de menu déroulant a son état (ib_enabled, ib_visible, ib_checked, is_text, is_shortcut), désignée par son adresse complète
toolbaris_date sur un sélecteur de date ; of_clear_menu ; of_remove_item d'une entrée de menu ; of_add_menu_separator sur une entrée (cascade) ; cascades de toute profondeur
pdfviewerue_load_failed(as_source, as_reason) et les constantes REASON_* ; ue_link_clicked(as_url) ; les adresses file:/// ; ib_allow_save et ib_allow_print : les commandes Enregistrer et Imprimer de la barre du lecteur
pictureis_alt_text (texte de remplacement lu par un lecteur d'écran) ; un clavier pour le zoom : +, -, 0, et les flèches pour se déplacer ; n_pbt_utils.of_json_get_str_array
webbrowseris_search_url (moteur de recherche des mots qui ne sont pas une adresse) ; ib_veto_new_window et ue_new_window ; ib_veto_downloads et ue_download_starting ; ue_load_failed ; ue_error ; of_show_html ; of_clear_browsing_data et ib_private ; ib_veto_navigation et ue_navigating ; is_title et ue_title_changed ; ue_permission_requested et les constantes PERMISSION_* ; les constantes LOADSTATUS_* de ue_load_failed ; F5, Ctrl+R, Alt+flèches et Échap dans la barre d'adresse
jsontreeof_selected_text rend la valeur DÉCODÉE de la feuille sélectionnée (une chaîne sans guillemets ni échappements) ; of_has_selection distingue la racine, dont le chemin est "", de « rien de sélectionné » ; le clavier saute les accolades fermantes (elles ne se sélectionnent plus)
xmltreechaque attribut est une cible : un clic donne son chemin (/order/@id), of_select_path le sélectionne, of_selected_value rend sa valeur ; un gros document ne dessine que les lignes à l'écran (8 000 éléments frères : 12 s → 0,15 s, une flèche en quelques ms)
videoue_muted_changed(ab_on) : l'utilisateur a coupé ou rendu le son (le haut-parleur de la barre, la touche M), comme le volume et la vitesse avaient déjà leur événement
ribbonof_remove_menu_item, of_clear_menu, of_remove_combo_item, of_clear_combo, of_remove_gallery_item, of_remove_app_menu_item, of_remove_contextual_group : les retraits sous un contrôle — une liste « Fichiers récents » se met à jour sans recréer le contrôle
ribbonof_app_menu_item(adresse) : la poignée d'une entrée du menu applicatif (is_label, is_image, ib_enabled, ib_checked, ib_visible) ; of_app_menu_item("") parcourt le menu
ribbontouches d'accès rapide de plusieurs lettres (is_keytip = "FP"), tapées l'une après l'autre ; noms accessibles (barre d'accès rapide, vignettes) pour les lecteurs d'écran
toolbarof_add_split_button : un bouton partagé (action + menu) ; is_group : des bascules exclusives (alignement) ; is_image sur un outil et sur une entrée de menu ; ue_item_rclicked(adresse) : le clic droit d'un outil

11.6 Des noms et des comptes alignés sur le reste de la bibliothèque #

Sept endroits parlaient autrement que le reste de la bibliothèque. La 4.0 les aligne plutôt que de garder l'écart : deux noms changent — le compilateur vous montre chaque ligne à reprendre —, deux comptes partent désormais de 1, comme toute position du produit, le chemin rendu par l'arbre JSON devient celui de n_pbt_json, celui de l'arbre XML sous un espace de noms par défaut un XPath qui marche, et un événement ambiant devient facultatif. Ce sont les seuls changements de la 4.0 qui demandent de retoucher du code qui compilait.

Quoi3.04.0
progressbar : bornes de l'échelleil_minimum, il_maximum, des longid_minimum, id_maximum, des double : une échelle 0..1 ou un nombre d'octets au-delà de 2 Go est valide ; le préfixe dit le type
json : index de tableau dans un cheminà partir de 0 : lines/0 est la première ligneà partir de 1 : lines/1 est la première ligne ; lines/0 ne désigne rien — une lecture le dit absent, une écriture rend -5
jsontree : chemin d'un nœud (ue_node_clicked, ue_selection_changed, of_selected_path, of_select_path)niveaux joints par un point, index de tableau à partir de 0 : lines.0.sku — un dialecte que n_pbt_json ne lisait pasle chemin de n_pbt_json : niveaux joints par /, index à partir de 1 (lines/1/sku), "" pour la racine — à passer tel quel à of_get_string sur le même texte
xmltree : chemin d'un élément sous un espace de noms PAR DÉFAUT (xmlns="urn:…")/Envelope/Body — un XPath qui ne trouve rien/*[local-name()='Envelope']/*[local-name()='Body'] — à passer tel quel à n_pbt_xml.of_get_value ; un élément sans espace de noms ou préfixé garde son chemin
toolbar : band et index de la disposition (of_get_layout, of_set_layout, ue_layout_changed)à partir de 0, une chaîne dite « opaque » alors que ii_band, ii_index et ue_bar_reordered comptaient à partir de 1à partir de 1, comme ii_band, ii_index et ue_bar_reordered ; un aller-retour lecture → restauration rend la même chaîne
statictext : ue_cyclelevé à chaque boucle du défilement, sans abonnement — et aussi par une animation à l'intérieur du texteévénement ambiant, donc facultatif : levé seulement quand ib_track_cycle = true, comme ue_mouse_enter avec ib_track_mouse ; seulement à chaque passage complet du texte
tilesbox : 2ᵉ argument de ue_tile_movedas_to_keys, alors qu'il porte UNE clé : le groupe d'arrivéeas_to_key : le nom dit ce qu'il porte, comme partout ailleurs (as_key = un niveau, as_keys = une adresse)
restclient : ue_failedue_failed (long al_id, string as_error)ue_failed (long al_id, long al_code, string as_error) : -4 échec, -5 URL ou fichier — plus besoin de lire le texte
restclient : of_json_valueune clé, première occurrence à n'importe quelle profondeur ; une valeur texte seulement — un nombre rendait le nom de la clé suivanteun chemin n_pbt_json ("json/customer", "items/1/qty"), toute valeur : "4152", "true". Une clé imbriquée se nomme avec ses parents

La recette : (1) recompilez — le compilateur signale il_minimum, il_maximum et as_to_keys : renommez-les id_minimum, id_maximum et as_to_key ; (2) cherchez les chemins json qui visent un tableau et ajoutez 1 à chaque index — une boucle for i = 0 to n - 1 sur "lines/" + String(i) devient for i = 1 to n ; (3) une disposition de toolbar enregistrée par la 3.0 compte à partir de 0 : ajoutez 1 à band et à index de chaque barre avant de la rendre à of_set_layout, ou laissez l'utilisateur réorganiser une fois — relue telle quelle, elle rangerait ses deux premières bandes ensemble ; (4) là où ue_cycle est scripté, posez ib_track_cycle = true à la construction ; (5) là où vous lisiez un chemin de l'arbre JSON (ue_node_clicked, of_selected_path) ou en donniez un (of_select_path), remplacez les points par / et ajoutez 1 à chaque index de tableau — lines.0.sku devient lines/1/sku, qui se donne tel quel à n_pbt_json.of_get_string.


11.7 Les thèmes suivent l'application #

La revue des thèmes a fait tenir à chaque composant la règle qu'annonçait déjà le chapitre 4 : l'application décide du thème et de l'accent, un composant ne s'en écarte que pour ce qu'on lui demande. Aucune méthode n'est renommée ; ce qui change se voit à l'écran, à la relecture des propriétés et dans deux codes retour.

Quoi3.04.0
PBT_SetDefaultThemechanger de thème effaçait l'accent posé par PBT_SetDefaultThemeAccent — même en reposant le même thème — et aplatissait le fond dégradé d'office2007 et d'office2003l'accent de l'application reste d'un thème à l'autre ; chaque thème garde son fond
PBT_GetDefaultThemeAccentl'accent du thème quand l'application n'en avait posé aucun-1 tant que l'application n'a pas posé d'accent
codes retour natifsPBT_SetDefaultTheme d'un nom inconnu rendait 0 et laissait les composants suivants sans thème ; PBT_SetDefaultThemeAccent d'une couleur système PowerBuilder la peignait en noir-5 dans les deux cas ; le thème ou l'accent précédent reste
un axe de thème posé seulfigeait l'autre axe sur le thème de l'application du momentl'axe vide suit le thème de l'application à chacun de ses changements ; les deux axes vides = le thème de l'application, entièrement
is_theme_style · is_theme_mode · il_theme_accentse relisaient "", "" et -1, quoi qu'on ait poséle style et le mode affichés, et l'accent propre du composant (-1 s'il n'en a pas)
une valeur d'axe inconnue ("office2010") ou mal écrite (" Metro ")le composant perdait son thème et n'écoutait plus celui de l'application jusqu'au of_reset()espaces et majuscules ignorés ; une valeur inconnue est ignorée et l'axe garde sa valeur
accent d'un composant à thème localil gardait l'accent de son thème, même quand l'application en posait unil suit l'accent de l'application tant qu'il n'a pas le sien
un accent personnaliséseul l'accent changeait : le survol et l'appui des boutons à l'accent, les sélections teintées, les boutons cochés du ruban gardaient l'accent du thèmetout ce qui dérive de l'accent le suit
tilesbox : il_badge_color0 et -1 = la couleur du thème ; relu 0 sans couleur posée ; le noir était inatteignable-1 = la couleur du thème (relu -1) ; 0 est le noir, comme pour toutes les couleurs
une couleur système PowerBuilder (ButtonFace…) dans il_theme_accentpeinte en noircomptée comme -1 : l'accent de l'application
webbrowser · pdfviewerle contenu tiers suivait le mode clair/sombre de Windows, et un rectangle blanc précédait son premier affichageil suit le thème par défaut de l'application, sur le fond du thème (4.11)
accent d'office-dark et d'office2003-darkun bleu foncé, lu à 3:1 quand il colorait un texte (liens, [accent])un bleu plus clair (#479ef5, #7ea1e8), avec un texte sombre posé dessus
datagrid : filets entre les lignesabsents dans huit thèmes sur dixprésents dans les dix thèmes, à la couleur de la grille du thème
contraste élevé de Windowsles icônes monochromes et les anneaux dessinés en ombre disparaissaientpris en charge (4.10)

La recette : (1) si vous reposiez l'accent après chaque PBT_SetDefaultTheme, ce n'est plus nécessaire — et si vous comptiez sur un changement de thème pour effacer l'accent, appelez PBT_SetDefaultThemeAccent(-1) ; (2) testez le code retour de PBT_SetDefaultTheme quand le nom vient d'une saisie ou d'un fichier ; (3) là où vous posiez les deux axes sur chaque composant pour suivre l'application, laissez-les vides ; (4) une tuile dont la pastille revenait « au thème » par il_badge_color = 0 s'écrit désormais -1.


11.8 crypto : ce que la sécurité refuse, et où vont les chemins relatifs #

La revue de sécurité de crypto ferme une porte réelle — un jeton JWT forgé avec la clé PUBLIQUE passait quand l'algorithme manquait — et remplace plusieurs silences par un refus qui dit sa raison. Aucune méthode n'est retirée ; une signature ECDSA change de forme, et les chemins relatifs des fichiers suivent une seule règle.

Quoi3.04.0
of_jwt_verify, of_jwt_signun algorithme VIDE valait JWT_HS256, et une clé PEM était acceptée comme secret HS256 : vérifié avec la clé PUBLIQUE comme secret, un jeton forgé passait ; l'algorithme de l'en-tête se comparait sans casse, un en-tête crit était ignorél'algorithme est OBLIGATOIRE et comparé EXACTEMENT ; une clé PEM n'est jamais un secret HMAC (of_hmac aussi) ; crit est refusé — chaîne vide et is_last_error
of_jwt_signun exp donné dans les claims était remplacé en silence par la durée al_expires_secondsles deux à la fois sont refusés : gardez l'un ou l'autre
of_encrypt, of_decryptun mot de passe VIDE chiffrait — n'importe qui relisait la valeurrefusé, comme of_encrypt_file le faisait déjà ; of_password_hash("") reste permis
il_pbkdf2_roundsune valeur hors de 1 000 à 10 000 000 retombait en silence sur 100 000l'appel est REFUSÉ : chaîne vide pour un texte, -5 pour un fichier, et is_last_error dit les bornes
of_password_hashil_pbkdf2_rounds (100 000 tours)il_password_hash_rounds, 600 000 par défaut (chiffre de l'OWASP) ; les valeurs déjà stockées portent leurs tours et se vérifient toujours
of_base64_decode, of_base64url_decode, of_hex_decode, of_decrypt…des octets qui ne sont pas un texte (un PDF, une image) revenaient en caractères de remplacement, sans erreurchaîne vide et is_last_error, qui renvoie à of_base64_decode_to_file ou of_decrypt_file
of_sign (clé EC)signature IEEE-P1363 (64 octets), qu'openssl dgst et Java refusentsignature DER ; of_verify lit les deux formes, une signature déjà stockée se vérifie toujours ; le JWT ES256 reste en P1363
of_totp_code, of_totp_verifyun caractère hors base32 dans le secret (un 0 tapé pour un O) était retiré en silence : un AUTRE secret, des codes qui ne correspondaient jamaisrefusé (espaces et = tolérés)
of_encrypt_file« quelle que soit sa taille »jusqu'à 64 Go, la limite d'un conteneur AES-GCM : au-delà, -7
chemins relatifs : n_pbt_crypto, u_pbt_zip, of_capture du lecteur vidéolus dans le dossier COURANT (qui bouge après un DirList ou une boîte de fichiers), écrits à côté de l'EXE (dans l'IDE : le dossier de PowerBuilder)LUS dans le dossier courant, puis dans le dossier où l'application a démarré, puis à côté de l'EXE ; ÉCRITS dans le dossier où l'application a démarré — le même dans l'IDE et compilé

La recette : (1) passez TOUJOURS l'algorithme d'un JWT en constante (n_pbt_crypto.JWT_RS256), jamais lu dans le jeton ni dans un INI qui peut manquer ; (2) si un serveur vérifiait vos signatures EC en P1363 (.NET VerifyData par défaut), convertissez-les ou vérifiez-les en DER (DSASignatureFormat.Rfc3279DerSequence) ; (3) un il_pbkdf2_rounds réglé hors bornes doit revenir entre 1 000 et 10 000 000 ; (4) un fichier qu'un chemin relatif écrivait à côté de l'EXE se trouve désormais dans le dossier de démarrage de l'application — donnez un chemin complet si vous en voulez un autre.


11.9 restclient : des en-têtes qui disent leur refus, des redirections qui gardent la requête #

La revue de restclient remplace deux pertes silencieuses — une modification jamais faite derrière une redirection, une authentification jamais envoyée derrière un en-tête mal formé — par un comportement juste ou un refus qui dit sa raison. Aucune méthode n'est retirée ; trois deviennent des fonctions, deux propriétés arrivent, et l'authentification Windows ne part plus que si vous la demandez. Un point vaut pour les cinq composants non visuels qui lèvent des événements : une erreur dans votre code d'événement se voit désormais.

Quoi3.04.0
of_set_header, of_set_bearer, of_set_basicdes subroutines : rien n'était rendu, une valeur mal formée était gardée telle quelledes fonctions long : 0, ou -5 et rien ne change — nom vide, nom avec une espace, un deux-points ou un caractère de contrôle, valeur avec un saut de ligne ; une valeur vide retire l'en-tête
une requête dont un en-tête est mal formépartait SANS AUCUN en-tête — l'Authorization comprise —, sans erreur-5, et is_last_error = « invalid header: <nom> » ; rien ne part
redirection 301 / 302 d'un PUT, PATCH ou DELETErepartait en GET sans corps : la modification n'était jamais faite, et l'appel rendait 200méthode et corps gardés ; seul un POST devient GET ; une 303 repart en GET sans corps (sauf HEAD)
une connexion réutilisée (celle d'une redirection) que le serveur ferme au même instant-4 et « request failed: 12152 », par momentsla requête est renvoyée UNE fois, corps compris, sur une connexion neuve : le serveur n'y avait rien répondu
of_response_text ( ), of_response_headers ( ), of_response_header, of_json_valuela dernière réponse synchrone du PROCESSUS : un second n_pbt_restclient l'écrasaitcelle de L'OBJET ; of_close l'oublie
corps lu en texte, application 32 bitsplafonné à 64 Moplafonné à 16 Mo (64 Mo en 64 bits) : au-delà, -4 « body too large » — lisez-le avec of_download
of_get_async, of_request_async… sur une URL ou un en-tête invalideun id de requête, puis un ue_failed-5 tout de suite, aucun événement ne suit ; is_last_error dit pourquoi (« invalid URL: … »)
authentification Windows (Negotiate / NTLM)le système répondait de lui-même au défi d'un serveur de l'intranet avec les identifiants de la sessiondésactivée par défaut : les identifiants ne partent vers aucun serveur sans ib_windows_auth = true (propriété neuve) ; is_client_certificate (neuve) pose un certificat client
of_cancel (long al_id), of_status (long al_id), of_response_text (long al_id)…l'id d'une requête d'un AUTRE objet atteignait cette requêteseules les requêtes de l'objet : of_cancel rend -5 et n'annule rien, les lecteurs rendent 0 / ""
of_status (long al_id) dans ue_failedpouvait rendre 200 : le statut d'une réponse reçue puis perdue0 pour toute requête échouée
ue_failed-4 échec, -5 URL ou fichier-4 échec, -5 fichier ou certificat client, -6 requête de plage refusée en démo
erreur d'exécution dans un événement de l'application — restclient, speechout, soundplayer, toaster, commandpaletteavalé sans un mot, et les événements suivants n'étaient plus livrésremonte à l'événement SystemError de l'application comme toute erreur de script ; les événements suivants sont livrés
il_max_retriesrejouait aussi un échec qui se reproduit à l'identique (trop de redirections, redirection invalide ou HTTPS → HTTP, TLS, fichier impossible à écrire)ces échecs-là ne sont plus rejoués ; 429, 503 et une panne réseau le sont toujours
URL et cheminsle fragment #… partait au serveur ; une Location relative ?page=2 perdait le dernier segment ; un chemin relatif d'of_download suivait le dossier courant du momentle fragment n'est plus envoyé ; Location résolue comme un navigateur (RFC 3986) ; un chemin relatif est résolu à l'appel, dans le dossier courant de l'application au chargement de la bibliothèque

La recette : (1) testez le retour de of_set_header, of_set_bearer et of_set_basic quand la valeur vient d'une saisie, d'un INI ou d'une base — un appel qui ignore le retour compile toujours, mais le -5 est désormais la seule trace d'un en-tête refusé ; (2) une API d'intranet en authentification Windows qui répondait 200 répond maintenant 401 : posez ib_windows_auth = true sur CE client ; (3) une application 32 bits qui lit un corps de plus de 16 Mo en texte passe à of_download ; (4) si vous partagiez un id de requête entre deux objets, lisez la réponse sur l'objet qui l'a envoyée ; (5) une erreur qui apparaît maintenant dans SystemError depuis ue_response ou ue_failed existait déjà : elle était avalée.

11.10 speechout : des réglages vivants, une destruction silencieuse #

La revue de speechout tient deux promesses que la doc faisait sans que le code les tienne — un réglage changé en cours de lecture vaut pour la phrase suivante, of_speak_from hors du texte rend -5 — et retire un événement levé au mauvais moment. Aucune méthode n'est retirée. Ajoutés : of_add_abbreviation, of_clear_abbreviations, l'événement ue_mark et deux balises, [mark=nom] et [rate=150]…[/rate].

Quoi3.04.0
of_speak_from (al_index)au-delà du texte, la lecture en cours était COUPÉE, rien ne repartait, et le retour valait 0-5, et la lecture en cours continue
ii_rate, ii_pitch, ii_volume, is_lang, is_voicechangés pendant une lecture, pris seulement à la lecture SUIVANTE (la doc promettait la phrase suivante)propriétés vivantes : la phrase suivante les prend
ue_voice_fallbackmuet quand seule la RÉGION manquait (fr-CA demandé, voix fr-FR)levé ; les balises de langue se comparent sans casse, et fr_FR vaut fr-FR
destroy (n_pbt_speechout)pendant une lecture, levait ue_stopped — sur une fenêtre déjà à moitié détruiteaucun événement ; of_close() lève toujours ue_stopped
of_sentence_count, of_countle compte du texte lu la fois PRÉCÉDENTE (0 avant toute lecture)le compte de is_text tel qu'il est
of_pause, of_resume, of_clear_queuecréaient la voix quand elle n'existait pas ; une pause pendant l'attente des voix était perdue0 sans rien créer, -4 si la page n'a pas répondu ; la pause tient jusqu'à of_resume
ue_sentence (al_index)une abréviation (Mr., Dr., e.g.), une adresse épelée ou une version coupaient la phrase ; un texte sans point était une seule phraseelles ne coupent plus ; une phrase de plus de 250 caractères est coupée : les numéros de phrase peuvent changer
[pause=ms]ignorée en FIN de texteun silence après la dernière phrase, avant ue_stopped

La recette : (1) testez le -5 de of_speak_from quand l'index vient d'un clic ; (2) si votre ue_stopped faisait quelque chose à la fermeture de la fenêtre, appelez of_close() vous-même dans son close — la destruction ne le lève plus ; (3) ne gardez pas de numéros de phrase d'une version à l'autre : prenez-les de ue_sentence, comme la doc l'a toujours dit.

11.11 statictext et texte riche : un balisage lu de gauche à droite #

La revue de statictext a surtout corrigé le texte à balises commun (4.7) : ces lignes valent pour le libellé de tout composant — titre d'onglet, panneau de barre d'état, toast, boîte de dialogue. Aucune méthode n'est retirée. Ajouté : of_refresh_parent_color(), et les zones [action], [hyperlink] et les en-têtes de [foldarea] d'un statictext s'atteignent au clavier (Tab, puis Entrée ou Espace).

Quoi3.04.0
of_escape_markup (une donnée collée à une balise)un ] échappé juste après une balise formait une paire avec le ] de la balise : "[b]" + of_escape_markup("] fin") + "[/b]" affichait [b]] fin sans grasla donnée s'affiche telle quelle, et la mise en forme autour tient
[/b], [/i]…une fermante fermait la DERNIÈRE balise ouverte, quelle qu'elle soit : [b]A[i]B[/b]C laissait C en gras ; [/br] fermait aussi quelque choseune fermante ne ferme que sa balise (les styles ouverts dedans continuent) ; une fermante sans ouvrante, ou celle d'une balise auto-fermante, est ignorée
[picture=…]coupée à la première virgule : une data URI (ce que rend of_icon()) ou un nom de fichier à virgule ne s'affichait pasles dimensions se lisent en fin de valeur : les deux s'affichent
[picture=\\server\share\x.png]l'image était lue sur le partage réseaurefusée : une image du balisage ne va jamais chercher un partage réseau. Passez par of_icon(), qui l'embarque, ou par un picture
[hyperlink=HTTPS://…]un schéma en majuscules n'était pas ouvertouvert : le schéma se lit sans casse ; la liste reste http, https, mailto
ii_padding0 = la marge du thème : un libellé ne pouvait jamais s'aligner sur le bord d'un champ voisin-1 = la marge du thème (nouveau défaut), 0 = aucune marge
ue_clicked, ue_double_clickedlevés en repliant un [foldarea] (trois événements pour un double-clic), et en relâchant la souris après une sélection de texteplus levés : replier est une affaire de lecture
[foldarea:… [action=…]]levait ue_action ET repliait le blocue_action seul, le bloc ne bouge pas
ii_line_spacing, is_marquee_directionune valeur hors de 50-400 était ignorée et relue 0 ; un sens inconnu ("UP") défilait vers le début mais se relisait tel quelramenée à la borne la plus proche, relue telle qu'appliquée ; un sens inconnu vaut et se relit MARQUEE_START
of_scroll_to_endne rendait rienrend 0, ou -2 si le composant n'est pas créé

La recette : (1) un ii_padding = 0 écrit pour dire « la marge du thème » devient -1 — ou disparaît ; (2) une image de balisage posée sur un partage réseau passe par of_icon() ; (3) un ue_clicked qui réagissait au repli d'une section ne sera plus appelé : le repli ne se scripte pas.

11.12 breadcrumb : ce qui cède quand le chemin ne tient pas, et quitter le champ #

La seconde revue du fil d'Ariane (breadcrumb) a corrigé le repli par la largeur, le mode OVERFLOW_SHRINK et ce qu'un segment emporte avec lui. Aucune méthode n'est retirée. Une ligne vaut pour tous les menus natifs de la bibliothèque : la recherche par frappe.

Quoi3.04.0
of_edit() sans / without ib_editablerend 0, rien ne s'ouvrerend -4
quitter le champ de saisie du chemin pour un autre contrôle de l'applicationle champ restait ouvert, texte à moitié tapé, et rien n'était rapportéun texte modifié est validé : ue_path_entered ; passer à une autre application garde toujours la saisie
OVERFLOW_SHRINKtout libellé plafonné à 12 caractères, même avec la place ; le lieu courant coupé net au bord de la barrerien n'est coupé tant qu'il y a la place ; le milieu cède d'abord, jusqu'à une lettre et …, le premier segment et le lieu courant en dernier
OVERFLOW_COLLAPSEle libellé du lieu courant pouvait s'élider avant que le milieu ne se repliele milieu se replie d'abord ; le lieu courant ne s'élide qu'en dernier recours
of_insert_item(…, ai_index)les poignées des segments décalés désignaient un autre segment, leurs couleurs et infobulles restaient à l'ancienne adresseleurs poignées sont libérées, leurs couleurs et infobulles les suivent ; un segment retiré (of_clear, of_truncate, of_remove_item) emporte les siennes
of_item("b").il_back_color / of_item("a/b").il_back_colordeux valeurs pour le même segmentune seule : la clé nue unique et l'adresse désignent le même segment
OVERFLOW_SCROLL, molettesans effetfait glisser la bande
les menus natifs (branches du fil, ruban, barre de menus, barre d'outils, menu contextuel) : une lettre tapéene faisait rien, hors mnémoniqueles lettres tapées dans la seconde sautent à la première entrée qui commence ainsi (« Win »), comme dans l'explorateur ; un menu de plus de 500 entrées ne dessine que ce qui se voit

La recette : (1) un of_edit() dont vous testiez le 0 sans avoir posé ib_editable rend désormais -4 ; (2) un ue_path_entered peut arriver quand l'utilisateur clique ailleurs dans la fenêtre — c'est le même texte qu'avec Entrée ; (3) après un of_insert_item au milieu du fil, redemandez les poignées des segments qui suivent.

11.13 buttonbar et clavier de fenêtre : la touche va au composant du focus #

La seconde revue de la barre de boutons (buttonbar) a touché le clavier de fenêtre, que partagent tous les composants qui répondent à Entrée, Échap, une lettre Alt ou un raccourci enregistré (button, buttonbar, et les raccourcis de of_register_shortcut de tous les composants). Aucune méthode n'est retirée ; une est ajoutée, of_focus_button.

Quoi3.04.0
deux composants d'une même fenêtre répondent à Entrée, Échap ou au même raccourci (deux feuilles MDI, deux panneaux)le premier créé la recevait, même dans l'autre feuillele plus proche du focus (même feuille, même panneau) ; à égalité, personne : la touche reste à la fenêtre
Entrée sur un CommandButton PB qui a le focus, ou dans une DropDownListBox ouverte ; Échap dans une liste ouvertedéclenchait le bouton par défaut / annuler du composantreste au contrôle, comme dans une boîte de dialogue Windows
of_register_shortcut(chord, key) sur un bouton de la barre, puis le bouton grisé et réactivé, ou sa lettre is_shortcut changéele raccourci était effacégardé : la lettre Alt et le raccourci de l'application ne se touchent plus
une lettre Alt d'un bouton face à un raccourci explicite de la même touchele premier enregistré gagnaitle raccourci explicite gagne ; les lettres ne sont consultées qu'après lui
of_clear_shortcuts()effaçait aussi le raccourci is_shortcut d'un buttonn'efface que les raccourcis de l'application
buttonbar : of_register_shortcut(chord) sans clé, ou avec une clé qui ne nomme aucun boutonrendait 0 et avalait la touche sans rien déclencherrend -5
buttonbar : retirer le bouton de is_default / is_cancel, ou vider la barrela propriété gardait la clé ; un bouton rajouté sous cette clé redevenait défautvidée : le rôle part avec son bouton
buttonbar : un autre bouton de la barre a le focusl'accent restait sur is_default alors qu'Entrée déclenchait le bouton focaliséle bouton focalisé porte l'apparence par défaut ; is_default relu est inchangé
buttonbar : ii_padding_x négatifrevenait à 12le retrait du thème, comme ii_padding_y et ii_gap
buttonbar : le trait de séparation entre boutonsdessiné au milieu de l'espace, même quand les boutons ne se touchaient passeulement entre boutons accolés (ii_gap = 0), et du bon côté en lecture de droite à gauche

La recette : (1) sur une barre, donnez un raccourci à UN bouton — of_register_shortcut("Ctrl+S", "save") — la forme sans clé rend -5 ; (2) après avoir retiré puis rajouté le bouton par défaut, reposez is_default ; (3) pour mettre le focus sur un bouton précis (« Non » plutôt que « Oui »), appelez of_focus_button("no").

11.14 button : un bouton grisé rend la main, et Alt+lettre répond #

La revue du bouton (button, déprécié au profit de buttonbar mais toujours livré et corrigé) change ce qu'il fait au clavier et ce que relisent ses propriétés. Aucune méthode n'est retirée ni ajoutée.

Quoi3.04.0
un bouton ib_default, ib_cancel ou is_shortcut grisé (ib_enabled = false)retenait Entrée, Échap ou son raccourci dans toute la fenêtre : la touche était perduerend la touche à la fenêtre (un CommandButton PB par défaut, un SingleLineEdit la reçoivent) ; réactivé, il la reprend
le & de is_text (&Enregistrer)soulignait la lettre, sans plusAlt + la lettre déclenche le bouton où que soit le focus dans la fenêtre, après les raccourcis explicites, jamais grisé ; une barre de menus PB qui utilise la même lettre la perd
Entrée ou Espace tenus sur le bouton qui a le focusune rafale de ue_clicked ; Espace partait à l'appuiun seul ue_clicked ; Espace part au relâchement, comme sous Windows
un is_shortcut que la fenêtre ne sait pas déclencher ("Win+S", "Ctrl+Entrée", "Ctrl+Pause")se relisait tel quel ; "Win+S" faisait partir le bouton sur un S seulrefusé : il se relit "". Les noms de touches s'écrivent en anglais (Enter, Esc, Del)
is_shortcut avec une info-bullel'accord n'apparaissait nulle partajouté à l'info-bulle (au titre d'une info-bulle enrichie) : « Enregistrer (Ctrl+S) »
of_register_shortcut("F5") sur le bouton, puis ib_default, ib_cancel ou is_shortcut changésF5 était effacéF5 et is_shortcut répondent tous les deux
is_text, is_image, is_style, ii_badge, il_badge_color, ii_badge_size, ii_image_size lus après of_reset()l'ancienne valeur, alors que l'écran était remis à zéroleur défaut ("", "standard", 0, -1)
un bouton grisé et la touche Tabrecevait le focusest sauté
un libellé fait d'une seule image ([picture=…]), ou un & dans une balisele libellé disparaissait, ou la balise était casséeaffichés tels qu'écrits

La recette : écrivez les noms de touches de is_shortcut en anglais ("Ctrl+Enter", pas "Ctrl+Entrée") et relisez la propriété si vous doutez : "" veut dire refusé. Si vous grisiez un bouton par défaut pour « désactiver Entrée », rien à changer : c'est désormais ce qui se passe.

11.15 menubar : une barre de menus qui rend le focus, et Alt+lettre de partout #

La revue de la barre de menus (menubar) change ce qu'elle fait du focus et du clavier, et ce que font tous les menus natifs en écriture de droite à gauche. Aucune méthode n'est retirée ni ne change de signature.

Quoi3.04.0
un clic dans la barre, puis un choix (Edition > Coller)la barre gardait le focus : GetFocus() dans ue_item_selected ne nommait plus le champ, le collage partait dans le videle focus revient au contrôle d'avant avant que ue_item_selected parte ; même chose sur Échap et sur un clic dehors
Alt+F maintenu, ou F10, le focus dans un champrien : seul Alt tapé puis F ouvrait FileAlt+F ouvre File depuis n'importe quel contrôle, F10 fait comme Alt ; un Alt+F que votre application a enregistré garde la priorité, et un menu PowerBuilder natif sur la même lettre la perd
Ctrl++, Ctrl+-, Ctrl+,, Alt+Left, Ctrl+Space, Ctrl+Tab, Ctrl+Backspace (tous les composants à raccourcis)affichés, mais rien ne partait depuis un contrôle PB ; le button les refusait ("")déclenchés où que soit le focus ; ces touches exigent Ctrl ou Alt (seules, elles restent la navigation)
en RTL, les déroulants de tous les menus natifs (barre de menus, ruban, barre d'outils, fil d'Ariane, menu contextuel…)calés à gauche, cascades à droite, chevron ›, Gauche refermaitle déroulant pend bord droit sous son titre, une cascade s'ouvre à gauche (chevron ‹) : Gauche ouvre, Droite referme
un clic sur le titre d'un menu déjà ouvertle refermait puis le rouvrait (un second ue_menu_opening)le referme, comme sous Windows
un is_shortcut posé sur une entrée qui ouvre une cascadeaffiché, et levait ue_item_selected("file/export"), une adresse qu'aucun clic ne produitni affiché ni déclenché : un raccourci se pose sur une feuille
une barre dont tous les menus sont masqués ou grisés, à côté d'un rubanprenait Alt pour rien : les keytips du ruban ne sortaient plusrend Alt au ruban tant qu'aucun titre n'est atteignable
deux titres sur la même lettre (&Fichier, &Favoris)Alt+F ouvrait toujours le premierdans la barre, la bande passe de l'un à l'autre, Entrée ouvre
une entrée retirée puis rajoutée à la même adresse (une liste de fichiers récents)reprenait les couleurs et l'info-bulle de la disparuenaît sans couleur (il_back_color relu -1) ; même chose après of_remove_menu et of_clear
une lettre accentuée ou non latine dans un déroulant (&Édition)soulignée, mais aucune touche ne l'atteignaitse tape comme sur le clavier
la touche Tab sur la barreun arrêt par titreun seul arrêt pour toute la barre ; les flèches passent d'un titre à l'autre
nouveau—is_image (l'icône d'une entrée, changée à chaud), is_group (des entrées radio), ue_menu_closed(as_key) (un déroulant fermé sans choix)

La recette : dans ue_item_selected, travaillez sur GetFocus() ou sur le DataWindow en saisie comme avec un menu PowerBuilder ; écrivez un & dans chaque titre ; si votre application utilisait Alt+lettre pour autre chose, enregistrez-le (of_register_shortcut) : il garde la priorité.

11.16 ribbon : un choix qui tient, des menus qui restent ouverts, des refus qui se disent #

La seconde revue du ruban (ribbon) corrige ce que l'utilisateur voyait — un choix de police défait, un menu qui se fermait sous le pointeur — et applique au ruban la règle de la bibliothèque : un ajout ou un retrait qui ne peut pas se faire rend -5. Aucune méthode n'est retirée ni ne change de signature.

Quoi3.04.0
ribbon : un choix dans la liste d'une zone de liste, puis la sortie du champue_combo_changed deux fois — le choix, puis le texte tapé avant lui, qui l'écrasait ; is_text relisait le texte tapéun seul ue_combo_changed, le choix ; le champ le montre aussitôt, même d'une zone non modifiable
ribbon : Entrée ou Échap dans une zone de liste, un compteur, ou sur un bouton du ruban qui a le focuspartaient aussi au bouton par défaut ou d'annulation de la fenêtrerestent au ruban ; Échap dans un champ rend le texte d'avant la frappe
ribbon : un menu ouvert pendant que l'application met le ruban à jour (un autre contrôle masqué, un onglet renommé, une vignette ajoutée)se fermait, et le choix fait dedans ne levait aucun événementreste ouvert ; il ne se ferme que si son propre contrôle disparaît, est masqué ou grisé
ribbon : is_app_button réécrit (« File » → « Fichier ») ; is_app_button = ""le menu applicatif était vidé ; une chaîne vide affichait « File »le menu reste ; une chaîne vide retire le bouton et son menu
ribbon : of_select_tab d'un onglet inconnu ou masqué0-5, rien ne change
ribbon : ajout d'une entrée de menu, d'une vignette, d'un choix de zone de liste, d'un bouton d'accès rapide, d'une entrée du menu applicatif ou d'un groupe contextuel sur une clé déjà prise ; clé qui contient une barre verticale ou commence par __ ; parent inconnu (séparateur, en-tête, choix, entrée sans bouton applicatif, onglet sous un groupe contextuel absent)0 : un doublon, ou rien du tout (un onglet contextuel sans bandeau)-5
ribbon : of_remove_tab, of_remove_group, of_remove_item, of_select_gallery_item sur une adresse inconnue ; of_open sur un bouton d'accès rapide0, sans effet-5. of_open("onglet/groupe") ouvre le panneau d'un groupe replié
ribbon : une poignée of_qat_item tenue après of_remove_item de son boutonrestait valide et désignait un bouton disparulibérée : IsValid() rend false
ribbon : touches d'accès rapide (keytips) — deux contrôles de la même lettre dont l'un est masqué, un contrôle d'un groupe repliéle masqué volait la lettre, rien ne partait ; la lettre d'un groupe replié ne faisait rien ; une touche de deux lettres ne répondait jamaisseul un contrôle visible et actif répond ; la lettre ouvre le panneau du groupe replié ; "FP" se tape lettre après lettre
ribbon : flèches du clavier sur un bouton scindé, un sélecteur de couleur, une zone de liste ou une galerie griséss'y arrêtaient, sans rien pouvoir y faireles sautent ; Bas sur un bouton déroulant ou scindé ouvre son menu

La recette : (1) ue_selection_changed et ue_minimized sont levés aussi quand votre code appelle of_select_tab ou pose ib_minimized, comme pour un clic : si vous appeliez vous-même votre traitement juste derrière, retirez cet appel, il passerait deux fois ; (2) testez le -5 des ajouts si votre construction peut répéter une clé ; (3) un is_app_button = "" qui voulait dire « File » s'écrit désormais is_app_button = "File". Les retraits sous un contrôle et la poignée d'une entrée du menu applicatif sont dans le tableau 11.5.

11.17 toolbar : une règle de raccourci, une seule info-bulle, des refus qui se disent #

La seconde revue de la barre d'outils (toolbar) aligne ses raccourcis sur ceux de la fenêtre et rend visible ce qui était écrit sans effet. Aucune méthode n'est retirée ni ne change de signature ; deux codes de retour apparaissent (-5).

Quoi3.04.0
un outil à is_shortcut = "Delete" (une touche seule) et un champ dans la barreSuppr dans le champ déclenchait l'outil et n'effaçait rien ; hors de la barre, rienune touche seule n'est jamais un raccourci : il faut Ctrl ou Alt, ou F1 à F24 — la règle de la fenêtre
une touche de raccourci tenue (tous les composants)l'action se répétait : une bascule clignotaitune action par appui
of_register_shortcut(accord, cle) hérité, sur une toolbarne déclenchait rien, et la touche était avaléeprend l'adresse de l'outil ou de l'entrée ("main/save"), -5 sinon ; la forme à un argument rend -5 ; of_clear_shortcuts vide aussi is_shortcut
le raccourci d'un champ, d'un sélecteur de date, d'un libelléavalait la touche sans rien fairele champ reçoit le curseur (Ctrl+F sur une recherche), le sélecteur ouvre son calendrier ; un libellé n'en prend pas
l'info-bulle donnée à l'ajout (of_add_button(…, tooltip))balises en littéral ; deux bulles à la fois si is_tooltip était posé ensuiteune seule info-bulle thémée, texte riche, le raccourci en suffixe ; is_tooltip la remplace et se relit
of_add_bar(MAIN_BAR) après un premier outil sur mainrendait 0 sans rien faire-5 : pour la placer, ajoutez main avant tout outil
of_set_layout d'un texte qui n'est pas du JSONrendait 0-5
ue_layout_changedabsent quand un ajout de barre en poussait une autre ; levé quand on réaffichait une barre déjà visiblelevé dans le premier cas, plus dans le second
séparateurs, déroulant ou cascade dont les entrées sont toutes masquéestraits orphelins ; le déroulant et la cascade restaient actifs et muetspas de trait en tête, en queue ni doublé ; ils se dessinent grisés
un clic droit dans la barreaucun événement, ue_rclicked comprisue_item_rclicked(adresse) sur un outil, ue_rclicked hors de tout outil — jamais les deux
les couleurs d'une entrée de menu (of_menu_item(…).il_back_color)écrites et relues, jamais dessinéesdessinées dans le menu
toolbar : ue_rclicked, ue_mouse_enter, ue_mouse_leavedocumentés, mais jamais levéslevés : un clic droit sur la barre hors de tout outil, l'entrée et la sortie de la souris

La recette : (1) un raccourci d'outil sur une touche seule (hors F1 à F24) prend Ctrl ou Alt ; (2) sur une toolbar, of_register_shortcut reçoit l'adresse de l'outil ou de l'entrée ; (3) pour placer la barre main, appelez of_add_bar(MAIN_BAR, bande, rang) avant son premier outil.

11.18 statusbar : une poignée qui redimensionne, un message qui ne remplace pas le texte #

La seconde revue de la barre d'état (statusbar) donne à la poignée de redimensionnement son vrai rôle et fait de chaque clé vide ou inconnue un refus. Aucune méthode n'est retirée ni ne change de signature ; of_flash_panel gagne un code de retour (-5).

Quoi3.04.0
ib_show_resize_grip = true, puis tirer la poignéeun dessin : rien ne bougela fenêtre se redimensionne par son coin (bas-gauche en RTL) ; la poignée n'est pas dessinée sur une fenêtre maximisée ou sans bord redimensionnable
of_flash_panel sur une clé que la barre n'a jamais reçue, ou sur une adresse0, rien ne s'affiche-5
of_panel(k).is_text relu pendant un of_flash_panelle messagele texte du panneau (le message passe par-dessus)
of_panel(""), of_panel("a/b") : écriture puis relectureécrivait dans les panneaux sans clé et les séparateursne désigne rien : n'écrit nulle part, se relit vide
is_state hors des constantes STATE_* ("Error", "very bad")relu tel quel, sans couleur ; une valeur à espace levait une erreur de scriptla casse est ignorée ("Error" = erreur) ; toute autre valeur vaut « aucun état » et se relit vide
ii_progress = 150 puis relu150 (dessiné à 100 %)100, ce qui est dessiné
un panneau désactivé qui porte un étatgardait la couleur de l'état : il avait l'air actifgrisé, marque d'état comprise
un panneau retiré, vidé (of_clear, of_clear_menu), désactivé ou masqué pendant que sa liste est ouvertela liste restait ouverte, et un choix levait ue_panel_menu_clickedla liste se ferme, rien n'est levé (de même pour une entrée devenue grisée ou masquée)
double-clic sur un panneau à liste déroulanteue_panel_double_clicked en plus de la liste ouvertela liste seule
Flèche haut / bas sur un panneau à liste déroulante qui a le focuspassait au panneau voisinouvre la liste (les flèches Gauche / Droite se déplacent toujours)
une liste déroulante faite de séparateurs seulschevron et liste videpas de liste : le panneau reste ce que dit ib_clickable

La recette : (1) posez ib_show_resize_grip sur une barre d'état placée en bas d'une fenêtre redimensionnable ; (2) testez le retour de of_flash_panel comme celui des autres méthodes à clé ; (3) donnez une clé à tout panneau que vous voulez relire ou modifier.

11.19 dockcontainer : un of_select_panel qui trouve le panneau, des fenêtres flottantes qui se souviennent #

La seconde revue du conteneur de panneaux (dockcontainer) donne à of_select_panel un effet sur un panneau replié ou flottant, et fait retenir les fenêtres flottantes par la disposition. Aucune méthode n'est retirée ni ne change de signature.

Quoi3.04.0
of_select_panel d'un panneau replié, flottant ou masqué0, rien ne se voitreplié : son volet glisse ; flottant : sa fenêtre passe devant ; masqué : -5
of_float_panel du panneau principal ou d'un panneau masqué0, rien ne se passe-5
of_move_panel qui empile le panneau PRINCIPAL0, et son voisin disparaît sans onglet-5, rien ne bouge
as_position inconnue (of_add_panel, of_move_panel)0, le panneau se docke en bas-5, le contrôle n'est pas touché
disposition (of_get_layout, ue_layout_changed, of_set_layout) et panneaux FLOTTANTSoubliés : un panneau détaché revenait ancré ; déplacer sa fenêtre ne levait rienretenus avec la place de leur fenêtre, rouverts à la restauration (ramenés sur un écran) ; déplacer ou redimensionner la fenêtre lève ue_layout_changed
of_set_layout d'une disposition sans panneau principalle panneau principal courant est retiréil est gardé
is_title d'un panneau ajouté sans titresa clé ; un titre donné ensuite au panneau principal ne faisait pas naître son en-tête"" (l'onglet montre toujours la clé) ; l'en-tête du principal suit son titre

La recette : (1) ue_panel_selected, ue_panel_floated et ue_panel_pinned sont levés aussi après of_select_panel, of_float_panel et ib_pinned, comme pour un geste : si vous appeliez vous-même votre traitement juste derrière, retirez cet appel, il passerait deux fois ; (2) testez le -5 de of_move_panel, of_float_panel et of_select_panel ; (3) une disposition enregistrée avant la 4.0 se restaure telle quelle, ses panneaux restent ancrés.

11.20 tab : des codes de retour honnêtes, un clic droit qui revient à l'application #

La seconde revue des onglets (tab) fait dire à of_add_page et of_select_page ce qu'ils refusent, annonce la disposition quand votre code masque un onglet, et rend le clic droit à l'application quand le menu intégré est coupé. Aucune méthode n'est retirée ni ne change de signature ; un événement est ajouté.

Quoi3.04.0
of_add_page d'un contrôle déjà hébergé (par cet onglet sous une autre clé, ou par un autre composant)0, et un onglet sans rien derrière-5, rien n'est ajouté
of_select_page d'un onglet refusé alors qu'aucun onglet n'est actif (tous masqués)0-5
Masquer ou réafficher un onglet par votre code (ib_visible)aucun ue_layout_changedue_layout_changed levé avec la disposition entière, comme pour of_move_page : c'est l'avis que la disposition à enregistrer a changé
Clic droit sur un onglet avec ib_context_menu = falserienl'onglet est sélectionné puis ue_tab_rclicked(as_key) (nouveau) est levé : ouvrez-y votre menu
Revenir sur l'onglet courant pendant que ue_selection_changing attend sa réponseune réponse « oui » activait quand même l'autre ongletla question est annulée : le dernier geste de l'utilisateur l'emporte
Un onglet désactivé ou masqué pendant que ue_tab_closing attend sa réponsese fermait quand mêmereste ouvert
Fermer au clavier (Suppr) l'onglet qui a le focusle focus quittait la bande, les flèches ne répondaient plusle focus passe à l'onglet devenu actif

La recette : (1) testez le -5 de of_add_page (une page ne s'héberge qu'une fois) et de of_select_page ; (2) si vous enregistrez la disposition dans ue_layout_changed, rien à faire — elle suit désormais aussi vos ib_visible ; (3) là où ib_context_menu = false laissait le clic droit sans suite, scriptez ue_tab_rclicked.

11.21 listbar : une entrée masquée jamais sélectionnée, une disposition vérifiée #

La seconde revue de la barre de navigation (listbar) fait refuser à of_select_item une entrée masquée et à of_set_layout un texte qui n'est pas une disposition, et ajoute une pastille de compteur, le clavier Gauche / Droite et le clic droit d'entrée. Aucune méthode n'est retirée ni ne change de signature.

Quoi3.04.0
of_select_item d'une entrée masquée (ib_visible = false)0, une sélection invisible-5, la sélection ne bouge pas ; masquer l'entrée déjà sélectionnée la garde sélectionnée
of_set_layout d'un texte qui n'est pas un objet JSON (fichier tronqué)0, rien n'est appliqué-5, rien n'est envoyé
Section repliée dans une disposition restaurée, ajoutée plus tardnaît repliéenaît dépliée : le pli ne vaut que pour une section présente
Section au titre videses entrées collées à celles du dessus ; repliable, et plus rien pour la rouvrirun espace (un filet en rail) la sépare ; elle ne se replie jamais
Nouveau : is_badge (entrée), ue_item_rclicked(as_keys), Gauche / Droite et frappe d'une lettre—une pastille de compteur, un clic droit d'entrée (un seul événement, l'entrée n'est pas sélectionnée), le pli au clavier

La recette : (1) ue_selection_changed est levé aussi après un of_select_item de votre code (ouvrir la page d'accueil au démarrage, par exemple), comme pour un clic : si vous ouvriez la page vous-même juste derrière, laissez-le à l'événement, sinon elle s'ouvrirait deux fois ; (2) testez le -5 d'of_select_item si vous masquez des entrées, et celui d'of_set_layout si la disposition vient d'un fichier ; (3) une section sans titre ne se replie plus : donnez-lui un titre si elle doit se replier.

11.22 tilesbox : un titre qui ne crée plus de groupe, la réorganisation au clavier #

La seconde revue du panneau de tuiles (tilesbox) empêche le titre d'un groupe de créer ce groupe, fait refuser à of_add_live_item un texte vide, donne une seule tabulation par groupe et ajoute la réorganisation au clavier. Aucune méthode n'est retirée ni ne change de signature. il_badge_color suit désormais la règle de toutes les couleurs (voir la ligne picture, button, tilesbox plus haut).

Quoi3.04.0
of_group(clé).is_title sur un groupe jamais ajoutécréait un groupe visible qu'on ne pouvait ni remplir ni retirer (sauf of_clear)n'écrit rien : seul of_add_group crée un groupe ; une clé vide, avec / ou `` rend un handle inerte
of_add_live_item d'un texte vide0, et le texte fixe is_live_text était effacé-5, rien ne change
of_tile(adresse).of_count()0le nombre de faces posées par of_add_live_item
Réorganiser (ib_reorderable = true)à la souris seulementaussi au clavier : Ctrl+Gauche/Droite dans le groupe (sens de lecture), Ctrl+Haut/Bas vers le groupe voisin ; mêmes ue_tile_moved et ue_layout_changed
Touche Tabs'arrêtait sur chaque tuile ; une flèche vers un bord sans voisin sautait à la tuile précédente ou suivante du documentun arrêt par groupe (la dernière tuile focalisée), les flèches parcourent les tuiles ; au bord, le focus reste
Tuile désactivée ou masquée pendant qu'on la glissedéplacée au relâchement, ue_tile_moved levéle glisser est abandonné, rien ne bouge
ib_collapsed d'un groupe posé par votre codeaucun événementue_group_toggled, comme un clic sur l'en-tête (rien quand le groupe est déjà dans cet état)

La recette : (1) créez un groupe par of_add_group avant d'en changer le titre ; (2) testez le -5 d'of_add_live_item si le texte d'une face peut être vide ; (3) ce que vous faisiez dans ue_tile_moved vaut désormais aussi pour un déplacement au clavier.

11.23 stepbar : « tout terminé » ancré sur la dernière étape, des étapes retirées qui n'emportent plus rien #

La seconde revue de la barre d'étapes (stepbar) rend « tout terminé » cohérent avec la règle de l'étape en cours (une identité, pas un rang), fait partir avec une étape retirée ce qui lui appartenait, et corrige quatre défauts d'affichage. Aucune signature ne change.

Quoi3.04.0
of_add_step quand la barre est « tout terminé »l'étape ajoutée s'affichait terminée (coche) ; ii_current passait à n + 2 sans événementajoutée après la dernière étape d'alors, elle devient l'étape en cours et ue_step_changed est levé ; insérée avant, rien ne change
of_step(clé).is_state sur une clé qui ne nomme aucune étapegardé, puis appliqué à l'étape ajoutée plus tard sous ce nomignoré ; une étape ajoutée naît sur son état calculé
Couleurs et infobulle d'une étape retirée (of_remove_step, of_clear_steps)revenaient sur la prochaine étape ajoutée sous la même clépartent avec l'étape
Barre compactée (OVERFLOW_AUTO) dont l'étape en cours est forcée en erreurplus aucun libellé ; une étape forcée à STATE_CURRENT gagnait le sienle libellé reste à l'étape en cours (le rang de ii_current), quel que soit son état
OVERFLOW_SHRINKlibellés sur plusieurs lignes, mots longs coupés sans « … »une ligne par libellé, finie par « … »
POSITION_BOTTOM avec une seconde ligne (is_description)au-dessus du libellé, collée à luisous le libellé, au-dessus de la pastille
Survol d'une étape désactivée ou hors de portée (il_back_color_hover, il_text_color_hover)la couleur de survol s'allumaitrien ne s'allume : l'étape ne répondra pas au clic

La recette : si votre code ajoute une étape après avoir posé « tout terminé » (ii_current = of_count() + 1) et veut que la barre le reste, reposez ii_current = of_count() + 1 après l'ajout. Si vous rebâtissez la barre avec les mêmes clés, reposez les couleurs et infobulles voulues : elles ne survivent plus au retrait.

11.24 progressbar : une barre qui tient dans son contrôle, un libellé qui suit la langue #

La seconde revue de la barre de progression (progressbar) la fait tenir là où était un HProgressBar, n'envoie plus au composant que les valeurs qui changent le dessin, écrit le pourcentage dans la langue d'affichage et ajoute is_label_format (un libellé à vous) et is_state (pause, erreur). Aucune signature ne change.

Quoi3.04.0
Barre linéaire dans un contrôle bas ou largemarge de 12 px, 640 px de large au plus : sous 24 px de haut, une barre de défilement apparaissait et la barre était coupéemarge de 2 px, toute la largeur ; la piste (14 px) et le libellé rétrécissent avec la hauteur
Libellé du pourcentage (ib_label)« 50% » dans toutes les languesdans la langue d'affichage : « 50 % » en français
of_set_property("value", "12,5"), ou un texte qui n'est pas un nombreenvoyé tel quel : commande perdue sans rien dire ; un minimum invalide bloquait l'échelle jusqu'au prochain of_reset« 12,5 » est lu 12.5 ; un texte qui n'est ni un nombre (ni true/false pour un booléen) est ignoré
id_value relula valeur que le composant avait reçue ; chaque affectation était un aller-retour avec luila dernière valeur posée par l'application ; le composant ne reçoit que celles qui changent le dessin (un dixième de pour cent)
of_reset() sur une barre rempliela barre redescendait à zéro en glissantelle revient à zéro d'un coup

La recette : (1) si vous calculiez un pourcentage à la main, posez id_maximum et affectez la valeur brute, à chaque ligne si vous voulez ; (2) si un test automatique lisait le libellé, attendez le format de la langue d'affichage ; (3) pour montrer une pause ou une erreur, préférez is_state à une couleur choisie par il_color.

11.25 picture : une affectation relit le fichier, un échec dit sa raison #

La seconde revue de l'image (picture) lui fait relire le disque à chaque affectation, comme le Picture natif, donne à ue_error un second argument qui dit pourquoi l'image manque, refuse une adresse http:// au lieu d'échouer sans raison, et ne lève plus qu'un ue_clicked sur un double-clic. ue_error est la seule signature qui change.

Quoi3.04.0
picture : double-clic sur l'imagedeux ue_clicked, puis ue_double_clickedun seul ue_clicked, puis ue_double_clicked — comme le Picture natif
picture : ue_errorue_error (string as_message) : le message seulue_error (string as_message, string as_reason) : as_reason vaut une constante REASON_* (introuvable, trop gros, http refusé, format non affiché, autre). Votre script de l'événement reçoit l'argument de lui-même ; un appel event ue_error(…) écrit dans votre code en passe désormais deux
picture : is_source = "http://…"tenté en https par le moteur ; sur un serveur sans TLS, échec sans raisonrefusé d'emblée : pictogramme d'erreur et ue_error avec REASON_INSECURE. Téléchargez d'abord l'image (n_pbt_restclient.of_download) et affichez le fichier
picture : le même chemin réaffecté après avoir réécrit le fichier ; mono: ou tint: sur is_source ; une image .avifl'ancienne image ; le pictogramme d'erreur ; introuvablele fichier relu, comme le Picture natif ; le glyphe recoloré par le thème ; affichée
picture : image zoomée plus petite que son cadre (bandes) ; molette horizontale, pavé tactile ; bouton droit maintenuelle sortait du cadre au glisser ; un cran de zoom par événement, dézoom sur un défilement horizontal ; l'image se déplaçaitelle reste où is_align et is_valign la placent ; zoom proportionnel au geste, rien sur un défilement horizontal ; seul le bouton gauche déplace

La recette : (1) si un script ouvrait une fiche sur ue_clicked et une autre action sur ue_double_clicked, rien à faire — le double-clic ne rouvre plus la fiche ; (2) remplacez l'analyse du texte de as_message par un test de as_reason ; (3) une image d'un serveur intranet en http se télécharge d'abord (n_pbt_restclient.of_download vers un dossier temporaire), puis s'affiche par son chemin ; (4) si vous ajoutiez un ?v= au chemin pour forcer la relecture d'une image réécrite, retirez-le : la réaffectation suffit.

11.26 video : des sous-titres et des formats qui se lisent, un échec qui dit sa raison #

La seconde revue du lecteur (video) donne à ue_failed un second argument qui dit pourquoi un film ne joue pas, refuse une adresse http://, lit les .mkv et les .mov, charge les sous-titres donnés par URL, et met le film en pause quand le composant est masqué. ue_failed est la seule signature qui change.

Quoi3.04.0
video : ue_failedue_failed (string as_message)ue_failed (string as_message, string as_reason) — as_reason est une constante REASON_*
video : une source http://échouait en « introuvable »refusée tout de suite, REASON_INSECURE ; seul https se lit
video : un .mkv, un .mov.mkv « introuvable », .mov refusé par son nomservis et lus quand le moteur les décode ; .avi, .wmv, .flv restent refusés (REASON_FORMAT)
video : un sous-titre donné par URLne s'affichait jamais, sans rien diretéléchargé par le composant (le serveur doit autoriser CORS) ; un refus lève ue_subtitles_failed
video : of_add_subtitles deux fois pour la même langueremplaçait la piste en silence, 0-5 (aussi pour une langue à / ou `) ; of_remove_subtitles` d'abord
video : le composant masqué pendant la lecturele film continuait, avec le sonpause, ue_paused, et attente d'of_play (ib_pause_when_hidden, vrai par défaut)
video : glisser le volume sur la barreun ue_volume_changed par pixelun seul, au lâcher
video : of_capture vers un .jpgun PNG sous un nom .jpgun JPEG ; la surcharge of_capture(as_path, al_max_width) réduit l'image
video : of_get_last_error après un échec d'of_capturel'erreur précédente de la bibliothèquela raison de CET échec (dossier absent, chemin vide…)
video : Échap en plein écran, ib_enabled = falsesans effet (seul Alt+F4 sortait)sort du plein écran

La recette : (1) ajoutez as_reason à votre script de ue_failed et testez-le plutôt que le texte du message ; (2) un film ou un sous-titre d'un serveur intranet en http se télécharge d'abord (n_pbt_restclient.of_download vers un dossier temporaire), puis se lit par son chemin ; (3) ue_fullscreen_changed, ue_pip_changed, ue_source_changed et ue_chapter_changed sont levés aussi après vos propres appels (of_fullscreen, of_pip, of_next, of_seek…), comme pour un geste : si votre code appelait lui-même son traitement juste derrière, retirez cet appel, il passerait deux fois ; (4) un mur d'écrans qui doit jouer masqué pose ib_pause_when_hidden = false ; (5) pour remplacer la piste d'une langue, of_remove_subtitles puis of_add_subtitles.

11.27 pdfviewer : of_refresh dit ce qu'il fait, rien ne se télécharge à votre insu #

La seconde revue de la visionneuse (pdfviewer) donne un code de retour à of_refresh — et, pour garder le même nom au même sens, à celui du webbrowser et du shellexplorer —, dit tout lien du document, et refuse ce qui ne s'affichera jamais au lieu de laisser attendre. Aucune signature d'événement ne change.

Quoi3.04.0
pdfviewer · webbrowser · shellexplorer : of_refreshsubroutinelong : 0 une fois demandé, -4 sans document ou sans page (pdfviewer, webbrowser), -2 si le composant n'est pas créé
pdfviewer : of_refresh après un refus (http://…)ne faisait rien, sans événementle refus est redit : ue_load_failed
pdfviewer : une adresse data: de plus de 2 Mo de caractèresjamais affichée, aucun événementue_load_failed avec REASON_TOO_LARGE, tout de suite
pdfviewer : un PDF distant servi « en téléchargement »ue_load_failed, mais le fichier partait dans Téléchargementsue_load_failed avec REASON_REFUSED, rien n'est téléchargé
pdfviewer : ue_link_clicked sur un lien mailto:, file: ou relatifjamais levé (seuls http et https) ; un lien relatif arrivait en adresse internelevé pour tout lien ; as_url est un mailto:… tel quel, ou un chemin disque pour un fichier local
pdfviewer : of_print_to_pdfécrivait la page qui encadre le lecteur, pas le document-4, rien n'est écrit : copiez le fichier de is_source
pdfviewer : file://localhost/C:/…, file:////serveur/partage/…un chemin faux, introuvableC:\… et \\serveur\partage\…
pdfviewer : le focus donné au composant (Tab, of_focus_webview)restait sur la page : les touches ne faisaient pas défiler le documentpasse au document : PageDown, flèches, Début / Fin le font défiler

La recette : (1) un appel uo_pdf.of_refresh() compile tel quel ; testez son retour si vous voulez savoir qu'il n'y avait rien à relire ; (2) un document de plus de 1,5 Mo tenu en mémoire s'écrit dans un fichier temporaire, puis s'affiche par son chemin ; (3) dans ue_link_clicked, attendez aussi un mailto: et un chemin disque, pas seulement une adresse web ; (4) pour copier le document affiché, copiez le fichier de is_source plutôt qu'of_print_to_pdf.

11.28 codeeditor : une recherche qui se voit, un « aller à » qui déplace le curseur, remplacer #

La seconde revue de l'éditeur de code (codeeditor) amène à l'écran ce que la recherche trouve, garde le curseur de l'utilisateur pendant une recherche, renomme ii_doc_line et ajoute ce qu'un éditeur de script attend : remplacer, piloter le curseur, savoir s'il faut enregistrer, montrer une erreur dans la gouttière. Aucune signature d'événement ne change.

Quoi3.04.0
codeeditor : ii_doc_lineun long au préfixe d'integeril_doc_line : renommez-le ; une ligne au-delà du texte ne marque plus rien (elle se relit telle qu'écrite)
codeeditor : of_find avec ib_search_enabled = false0, sans rien chercher-4
codeeditor : of_find("")relançait la recherche précédentevide le champ et efface les surlignages, sans ue_find_result
codeeditor : of_find, Entrée dans la barrel'occurrence restait souvent hors de la vue ; le curseur allait sur ellel'occurrence est amenée à l'écran ; la recherche part du curseur, qui ne bouge qu'à la fermeture de la barre (Échap)
codeeditor : of_insert_text barre de recherche ouverteremplaçait l'occurrence trouvée, hors de la vue, et vidait l'historique de Ctrl+Zinsère au curseur de l'utilisateur, amené à l'écran ; Ctrl+Z l'annule
codeeditor : un nouveau is_textgardait le défilement de l'ancien document ; un texte en CR seul se relisait en LFs'affiche depuis sa première ligne et efface les marqueurs ; CR seul se relit en CR (un mélange en CRLF)
codeeditor : ib_current_line avec ib_wrapaucune bandela bande couvre toute la ligne du curseur
codeeditor : ajouts—remplacer (of_replace, of_replace_all, Ctrl+H) et options de recherche (ib_find_match_case, ib_find_whole_word, ib_find_regex, F3) ; curseur et sélection (il_caret_line, il_caret_column, of_select_range, of_selected_text, of_line_count) ; ib_modified ; marqueurs de gouttière (of_add_marker, of_remove_marker, of_clear_markers, of_marker_count)

La recette : (1) remplacez ii_doc_line par il_doc_line ; (2) testez le -4 d'of_find si la recherche peut être coupée ; (3) pour « aller à la ligne » d'une erreur en déplaçant le curseur, posez il_caret_line (et of_add_marker pour la montrer) — il_doc_line ne fait que marquer ; (4) si vous suiviez ue_caret_changed pour savoir où un extrait a été inséré, lisez il_caret_line après of_insert_text ; (5) un bouton Enregistrer peut suivre ib_modified, que vous remettez à false après l'enregistrement.

11.29 jsontree et xmltree : le clavier reste à l'arbre, une recherche qui ne déplace plus la sélection #

La seconde revue de l'arbre JSON (jsontree) a porté sur le moteur qu'il partage avec l'arbre XML (xmltree) : ce qui suit vaut pour les deux, sauf mention. Aucune signature ne change ; l'arbre JSON gagne of_expand_path, of_collapse_path, of_is_expanded, of_copy et l'événement ue_node_toggled, levé par un geste de l'utilisateur comme par of_expand_path et of_collapse_path.

Quoi3.04.0
jsontree, xmltree : Entrée sur une feuilletransmise à la fenêtre : son bouton par défaut partaitgardée par l'arbre, lève ue_node_clicked comme un clic ; sans sélection, rien
jsontree, xmltree : Échap, zone de recherche ouvertele bouton Annuler de la fenêtre partaitferme d'abord la zone ; zone fermée, Échap revient à la fenêtre
jsontree, xmltree : lignes fermantes (}, ], </x>)atteintes par les flèches (ue_selection_changed d'un bloc déjà annoncé) ; un clic ramenait la vue sur l'ouvrantesautées par le clavier ; un clic sélectionne le bloc sans déplacer la vue
jsontree, xmltree : Flèche droite sur une feuilledescendait d'une lignene fait rien, comme dans un arbre
jsontree, xmltree : une recherche pendant une sélectionof_search_next ou Échap pouvaient replier la ligne choisie et déplacer la sélection sans événementla ligne sélectionnée reste visible et sélectionnée : of_selected_path ne change pas
jsontree : le message de ue_errormoitié traduit, moitié anglais (« JSON invalide : Unexpected end of JSON (line 1, column 6) »)entièrement dans la langue d'affichage, ligne et colonne comprises : ne comparez pas son texte
jsontree, xmltree : un document de plus de 1 500 000 lignesaffiché, mais sa fin hors d'atteinte, sans rien direrefusé : un message dans l'arbre et ue_error
jsontree : Ctrl+C dans l'arbrene copiait rien, et partait comme raccourci de la fenêtrecopie la sélection (comme of_copy) ; sans sélection, le raccourci reste à la fenêtre

La recette : (1) si une fenêtre comptait sur Entrée dans l'arbre pour valider son bouton par défaut, ajoutez ce geste dans ue_node_clicked ; (2) ne cherchez plus de clé vide dans ue_selection_changed (une fermante n'est plus sélectionnée) ; (3) n'analysez pas le texte de ue_error : il suit la langue ; (4) pour rétablir les plis d'un utilisateur, lisez of_is_expanded et reposez-les par of_expand_path / of_collapse_path.

11.30 xmltree : chaque ligne a son XPath, tout XPath se sélectionne #

La seconde revue de l'arbre XML (xmltree) reprend tout ce que la section précédente dit du moteur partagé. Elle ajoute ce qui est propre au XML : un chemin qui désigne TOUJOURS le nœud de la ligne, lisible tel quel par n_pbt_xml. Aucune signature ne change ; l'arbre XML gagne of_selected_xml, of_copy, of_expand_path, of_collapse_path, of_is_expanded et l'événement ue_node_toggled.

Quoi3.04.0
xmltree : chemin d'une ligne de texte, de commentaire ou d'instruction de traitementcelui de son élément (alors que of_selected_value rendait son texte à elle) ; "" avant la racinele sien : /r/text()[2], /r/comment()[1], /r/processing-instruction('x')[1], /comment()[1] — n_pbt_xml.of_get_value y lit la même valeur
xmltree : élément dont le préfixe est redéclaré avec un autre URI, ou qui a un frère de même nom dans un autre espace de nomsun chemin qui ne trouvait rien, ou un AUTRE nœud*[local-name()='x' and namespace-uri()='urn:…'], qui désigne ce nœud-là
xmltree : of_select_pathseulement la forme exacte que l'arbre écrit, sinon -5tout XPath (//line[@sku='A'], /r/a[1]…) : le premier nœud trouvé est sélectionné, of_selected_path rend ensuite le chemin de l'arbre
xmltree : le message de ue_error« XML invalide : error on line 1 at column 11: … » ; l'arbre restait vide« XML invalide : ligne 1, colonne 11 (…) », dans la langue d'affichage ; l'arbre montre la source, la ligne fautive marquée
xmltree : <?xml-stylesheet?> sans déclaration XMLaffiché deux foisune seule ligne
n_pbt_xml : un XPath avec @xml:langrefusé (préfixe xml inconnu), valeur videlu : le préfixe xml est lié d'office, comme le veut la norme
xmltree : Flèche droite sur une balise à attributsles attributs ne s'atteignaient qu'à la sourisparcourt les attributs un par un (Flèche gauche revient), un ue_selection_changed par pas, puis descend
xmltree : Ctrl+C, plier par cheminrien ; Ctrl+C partait comme raccourci de la fenêtreof_selected_xml, of_copy et Ctrl+C (le XML de la sélection), of_expand_path, of_collapse_path, of_is_expanded (tout XPath), ue_node_toggled (un geste, ou of_expand_path / of_collapse_path)

La recette : (1) si vous remontiez d'une ligne de texte ou de commentaire à son élément par of_selected_path, prenez le parent du chemin (ce qui précède le dernier /) ; (2) n'analysez pas le texte de ue_error : il suit la langue ; (3) un chemin mémorisé en 3.0 sous des espaces de noms mêlés se retrouve en le redonnant à of_select_path, qui accepte désormais tout XPath, puis en relisant of_selected_path.

11.31 xml : des refus qui se disent, des espaces de noms qui tiennent #

La seconde revue de n_pbt_xml ne change aucune signature. Elle rend of_remove fidèle aux codes de la bibliothèque, refuse une lecture tant qu'un document bâti a un élément ouvert, et fait tenir les espaces de noms : ce qu'un mutateur écrit se relit dans le bon espace, ou se refuse en le disant.

Quoi3.04.0
xml : of_remove(""), of_remove sans document chargé, page qui ne répond pas0, comme « rien retiré »-5 ; -4 ; -2 — le compte (>= 0) seulement quand la suppression a été tentée
xml : une lecture (of_exists, of_count, of_get_value, of_is_valid…) ou une modification pendant qu'un élément bâti est encore ouvertle document était chargé tel quel, et la suite de la construction commençait un NOUVEAU document : ce qui précédait était perdu sans erreurrefusée : -4, vide ou false, et is_last_error = « the document is still being built : close its elements first » ; rien n'est perdu (of_xml et of_pretty restent permis)
xml : of_add_xml sous un élément à espace de noms par défaut, ou avec le préfixe de la cible (<s:Item/> sous s:Body)le fragment restait hors espace de noms (xmlns=''), invisible pour le XPath qui avait servi à l'ajouter ; le préfixe de la cible était refusé (-4)le fragment hérite des espaces de noms en vigueur à sa cible, comme of_add_child
xml : of_set_attr / of_add_child avec un nom préfixé (xsi:type, p:item)0, un attribut hors espace de noms que le XPath ne trouvait pas ; avec un préfixe non déclaré, un document qui ne se rechargeait plusdans l'espace de noms du préfixe (déclaré au nœud, ou lié par of_register_namespace) ; -4 et « undeclared prefix : xsi » s'il n'est lié nulle part
xml : of_pretty après un of_add_child sous un parent préfixé (s:Body)<Item> sans préfixe : relu, hors espace de noms<s:Item>, comme dans of_xml
xml : of_element_attr deux fois du même nom ; un nom :x, x: ou a:b:cdeux attributs (document mal formé) ; nom accepté (document qui ne se charge pas)un seul attribut, avec la seconde valeur ; nom refusé (is_last_error), l'élément laissé de côté
xml : of_transformapplique une feuille XSLT au document chargéretiré : XSLT n'existe plus dans le moteur (Chromium le retire) ; transformez côté serveur ou en PowerScript

La recette : (1) un of_remove testé = 0 (rien retiré) marche toujours ; testez < 0 (rien n'a pu être tenté) ; (2) si vous lisiez un document PENDANT sa construction (un of_exists pour contrôler, un of_count pour numéroter), fermez d'abord ses éléments, ou tenez le compte vous-même ; (3) un fragment de of_add_xml n'a plus à redéclarer l'espace de noms de sa cible : celui qui écrivait xmlns='' pour en sortir le peut toujours ; (4) testez le retour de of_set_attr / of_add_child avec un nom préfixé, et déclarez le préfixe (ou liez-le par of_register_namespace).

11.32 json : un tableau qui se bâtit vite, des nombres qui gardent leurs chiffres, un texte vide qui se dit vide #

La seconde revue de n_pbt_json ne retire ni ne change aucune signature. Elle ajoute les surcharges decimal et longlong d'of_set_number et d'of_add_number, et les lecteurs of_get_decimal et of_get_longlong. Bâtir un tableau par of_add_* ne reparcourt plus tout le tableau à chaque ajout : 2 000 lignes se bâtissent en une fraction de seconde au lieu de plusieurs minutes. Deux règles sont désormais écrites dans la doc, sans changer : une chaîne nulle s'écrit "" (pour un null JSON, of_set_raw(path, "null")), et une clé écrite deux fois est lue à sa PREMIÈRE occurrence.

Quoi3.04.0
json : of_load d'un texte fait de blancs (fin de ligne, tabulation)-4, comme un texte malformé-5, comme un texte vide
json : of_load d'un texte précédé d'un BOM (fichier UTF-8 avec BOM)-40, le BOM est ignoré
json : of_load d'un document imbriqué sur plus de 512 niveaux0 — et un texte très profond pouvait arrêter l'application-4, l'application reste vivante
json : of_set_number / of_add_number d'un decimal (ou d'un littéral comme 690.50)converti en double : une quinzaine de chiffres, un centime pouvait se perdresurcharge decimal : tous les chiffres, zéros finaux ôtés (690.5) ; un longlong a aussi la sienne
json : of_get_number d'un exposant à zéros de tête (1E-0000005)0, ou une valeur géantela bonne valeur (0.00001)
tous les composants : \u suivi de quatre caractères qui ne sont pas hexadécimaux, dans une chaîne lueles quatre caractères disparaissaientgardés tels quels, comme un échappement inconnu

La recette : (1) si vous testiez of_load(...) = -4 pour reconnaître un fichier vide, testez < 0 ; (2) un montant decimal passé à of_set_number s'écrit désormais avec tous ses chiffres, sans rien changer à votre code ; (3) un identifiant de plus de 15 chiffres se relit par of_get_longlong, un montant par of_get_decimal, plus par of_get_number.

11.33 crosstab : of_from_datastore, des refus qui se disent, la valeur affichée au double-clic #

La seconde revue du crosstab renomme of_set_data en of_from_datastore, le nom du datagrid et du scheduler qui lisent un DataStore de la même façon (mêmes arguments, mêmes codes). Tout ajout, filtre ou format qui nomme un champ inconnu rend désormais -5 au lieu de 0. Le tableau ne dessine plus que les colonnes visibles : un code client ou une date au jour posés en Colonnes ne figent plus l'écran. Nouveautés : is_thousands, CF_ICONS, les constantes VALUEFILTER_* et DATE_*.

Quoi3.04.0
crosstab : alimenter depuis un DataStoreof_set_data(ds)of_from_datastore(ds), mêmes codes
crosstab : un champ inconnu (faute de frappe) passé à un ajout, un filtre, un format, un ordre, un groupement de date0, rien ne se passe-5
crosstab : un type de filtre, une agrégation, une partie de date hors liste ; une mesure calculée en Lignes ; of_set_value_filter à une position sans mesure0 ; la position glissait sur la dernière mesure-5
crosstab : of_set_layout d'un texte qui n'est pas du JSON ; of_remove_calc_field / of_remove_calc_measure d'un nom inconnu0-5
crosstab : ad_value de ue_cell_double_clickedl'agrégat brut (400 sous « 80,0 % »), 0 pour une cellule videla valeur affichée (0.8), NULL pour une cellule vide ; un membre vide vaut null dans les tuples
crosstab : un même champ en Lignes (ou Colonnes, Filtres) ET en Valeursdépendait de l'ordre des appels : la valeur disparaissait ; « Retirer » d'une dimension retirait toutpermis partout ; ajouter ou déplacer une dimension garde les valeurs, « Retirer » ne retire que la puce visée
crosstab : un membre vide (NULL, texte vide) ; un texte avec tabulation ou retour à la ligne dans le DataStore« null » ou une ligne sans libellé ; des lignes fantômes, des colonnes décaléesun seul membre (vide), en dernier ; le texte reste dans sa ligne
crosstab : is_label après un nouvel of_from_datastore ; is_label = ""perdu ; une puce sans textegardé ; "" rend l'en-tête du DataWindow
crosstab : Ctrl+C en mode démoue_copy levé, presse-papiers écritrefusé comme un export, la grille le dit
crosstab : of_collapse_all ; filtre de membres de la grille ; of_export_xlsx au-delà de 16 384 colonnes ; exports en VALUES_ROWSles lignes seulement ; appliqué à chaque case ; un fichier illisible ; les mesures côte à côtelignes et colonnes ; appliqué par OK (10 000 membres listés au plus) ; refusé, ue_xlsx_saved dit pourquoi ; comme à l'écran

La recette : (1) remplacez of_set_data par of_from_datastore ; (2) si vous ignoriez le code rendu par of_add_*_field ou un filtre, vérifiez < 0 — une faute de frappe se voit enfin ; (3) dans ue_cell_double_clicked, testez IsNull(ad_value) avant de calculer, et relisez ad_value comme la valeur affichée (une part, pas une somme, en mode « % »).

11.34 Socle : of_count et of_keys_at comptent en long #

of_count rendait un integer et of_keys_at prenait un rang integer — sur tous les composants, sur leurs poignées et sur les objets non visuels qui les portent (commandpalette, messagebox, speechout, toaster). Au-delà de 32 767 éléments, le compte débordait : un calendrier (scheduler) alimenté par un DataStore de 40 000 lignes ne se comptait plus, et ses dernières lignes ne se parcouraient pas. Les quatre signatures sont désormais en long : long of_count ( ), long of_count ( string as_keys ), string of_keys_at ( long al_index ), string of_keys_at ( string as_keys, long al_index ).

La recette : un appel ne change pas. Une variable integer qui reçoit of_count() reste juste jusqu'à 32 767 : déclarez-la long. Un descendant qui surchargeait of_count ou of_keys_at reprend la nouvelle signature — le compilateur vous montre la ligne.

11.35 shellexplorer : un rafraîchissement qui garde l'état, chaque ligne pour elle #

La revue de l'explorateur du shell garde ses événements : of_select, of_expand et of_collapse les lèvent comme un clic, comme en 3.0. of_refresh et ib_show_files ne referment plus l'arbre. Nouveautés : is_file_filter (les fichiers montrés), ib_show_hidden (les éléments masqués, par défaut le réglage de l'Explorateur), ib_enabled et of_refresh(chemin), qui relit une seule branche.

Quoi3.04.0
shellexplorer : of_refresh(), ou ib_show_files changél'arbre se refermait, la sélection disparaissait sans événementles branches ouvertes et la sélection reviennent, retrouvées par leur chemin ; une sélection qui n'existe plus lève ue_selected("", "")
shellexplorer : of_expand, of_select, of_collapse d'un chemin vide0-5
shellexplorer : of_expand d'un fichier ou d'un dossier sans enfantrienue_path_not_found(…, "expand", "not a branch")
shellexplorer : of_keys_at(chemin, i)chemin/enfant, que rien ne relisaitle chemin de l'enfant, entier : il se réinjecte dans of_has, of_select, of_expand
shellexplorer : un même dossier affiché à deux niveaux (la Musique du Bureau et celle du dossier de l'utilisateur)un clic, un chevron ou un double-clic sur l'une agissait sur l'autrechaque ligne répond pour elle-même
shellexplorer : fichiers et dossiers masquésjamais montrésmontrés selon le réglage de l'Explorateur du poste, ou ib_show_hidden
shellexplorer : une branche sur un partage qui ne répond pas« … » pour toujours, même refermée et rouverteue_error « … : timeout » au bout de 30 secondes ; la branche se redemande à sa réouverture

La recette : (1) ue_selected et ue_expanded sont levés aussi après un of_select ou un of_expand de votre code, une fois le dossier atteint (un chemin encore à lire arrive un peu plus tard) : faites votre travail dans l'événement, pas juste derrière l'appel, ou relisez of_selected_key() une fois la sélection arrivée ; (2) dans ue_selected, traitez as_path = "" (la sélection a disparu) ; (3) testez -5 sur un chemin vide ; (4) posez ib_show_hidden = false si vos utilisateurs ne doivent jamais voir les éléments masqués, quel que soit leur Explorateur.

11.36 commandpalette : chaque objet ne touche qu'à sa palette, une fermeture qui se dit toujours, la langue de l'application #

Il n'y a qu'une palette à l'écran à la fois : quand un second objet palette ouvre la sienne, elle remplace la première. Un objet ne répond plus désormais que de sa palette et de son accord. ue_opened et ue_closed restent levés sur of_open / of_close : ils disent le cycle de vie de la fenêtre, pas un geste (même règle que les lecteurs audio et vidéo). Nouveautés : of_insert_command (une commande à un rang choisi), of_anchor_under (la palette sous un contrôle, en pixels écran), et sur la poignée is_group, is_hint, is_keywords, is_icon.

Quoi3.04.0
commandpalette : ue_closedsans argument ; rien du tout quand la palette mourait avant de paraître (fermée ou remplacée aussitôt, fenêtre refusée)ue_closed(string as_reason) suit chaque of_open qui a rendu 0 : "", cancelled, failed ou blocked
commandpalette : of_is_open, of_close, of_reset, la destruction d'un objet dont la palette a été remplacée par celle d'un autrerépondaient VRAI pour la palette de l'autre, et la fermaientne répondent que de leur palette : FAUX, et rien n'est fermé
commandpalette : détruire (ou remettre à zéro) un objet dont l'accord a été repris par un autre objet palette de la même fenêtreretirait l'accord de l'autre : la touche ne répondait plus nulle partl'accord de l'autre reste
commandpalette : of_register_shortcut d'une touche que le crochet ne nomme pas (ctrl+ù, win+k, space sans modificateur)0 (« posé »), et la touche ne faisait jamais rien-5 ; l'accord précédent est gardé
commandpalette : of_register_shortcut avec is_shortcut vide et aucun accord posé02
commandpalette : of_add_command d'une clé qui contient une virgule0 — et is_recent la relisait comme deux commandes-5
commandpalette : un groupe déclaré en plusieurs fois (File, Edit, puis File)deux en-têtes « File »un seul, à la place de sa première apparition ; l'ordre des commandes est gardé dans le groupe
commandpalette : la recherche et les accentspreferences ne trouvait pas « Préférences »les accents ne comptent pas
commandpalette : la languela palette parlait anglais quelle que soit PBT_SetLanguagela langue de l'application ; is_placeholder posé par vous n'est pas traduit
commandpalette : le raccourci affiché sur une ligne, clavier AZERTY ; AltGr dans la rechercheCtrl+A se lisait Ctrl+Q ; taper € (AltGr+E) lançait la commande montrée en Ctrl+Alt+Ela touche est lue comme la DLL la nomme ; un caractère tapé n'est jamais un accord
commandpalette : un accord posé sans ipo_owner (toute l'application) avant l'accord d'une fenêtre, sur la même touchegagnait aussi dans cette fenêtrel'accord de la fenêtre passe d'abord
commandpalette : POSITION_ABSOLUTEune commande de clé x ou y ramenait la palette au bord de l'écran ; sur deux écrans, elle allait sur celui de la fenêtreil_x / il_y tiennent, sur l'écran du point demandé
commandpalette : inv_pumpvariable interne restée publiqueprotégée : elle ne fait pas partie de l'API, rien à lire ni à écrire
commandpalette : une commande dont le texte cite __licensela palette ne s'ouvrait pas (-5)s'ouvre : seul un mot réservé écrit en clé reste refusé

La recette : (1) si votre code déclenche lui-même ue_closed(), passez-lui une raison ("") ; un script qui ne fait que le recevoir compile tel quel ; (2) si vous attendiez ue_opened après of_open, traitez aussi ue_closed("cancelled"), "failed", "blocked" ; (3) testez 2 et -5 au retour d'of_register_shortcut ; (4) renommez une clé de commande qui contient une virgule.

11.37 radialmenu : une clé nue qui vise juste, une roue ouverte qui suit l'application, un libellé qui se lit #

La roue est dessinée une fois, et l'application continue de tourner pendant qu'elle est à l'écran : ce que vous changez entre-temps compte désormais. Le moyeu n'épelle plus rien (il ne l'avait jamais fait depuis la 3.0, contrairement à ce que disait la documentation) : c'est la branche pointée qui montre son libellé entier.

Quoi3.04.0
radialmenu : of_item avec une clé nue (of_item("csv"))changeait le libellé et l'état de la seule branche qui la portait, mais ses couleurs ne se dessinaient pas, et la poignée survivait au retrait du parentest résolue en l'adresse complète (import/csv) : même poignée, couleurs comprises, libérée avec le parent. Ambiguë ou inconnue : la poignée ne change rien
radialmenu : une poignée sur une adresse pas encore ajoutéeune couleur posée par elle colorait la branche ajoutée ensuite à cette adresse, même après of_clearn'écrit rien ; of_clear oublie toutes les couleurs
radialmenu : of_showne rendait rienrend un long : 0, ou -2 si le composant n'est pas créé
radialmenu : of_show(-1, -1)ouvrait la roue au curseurl'ouvre au point (-1, -1), comme toute coordonnée négative ; au curseur, c'est of_show()
radialmenu : une branche retirée, vidée, grisée ou masquée pendant que la roue est ouvertese choisissait encore : ue_item_selected pour une branche disparuene se choisit plus : ue_dismissed ; of_clear, of_remove_item et of_reset ferment la roue ouverte
radialmenu : clic droit ailleurs pendant que la roue est ouvertela nouvelle roue remplaçait l'ancienne sans ue_dismissedue_dismissed pour l'ancienne, puis la nouvelle roue
radialmenu : libellé long ou videcoupé à deux lignes et lisible nulle part ; vide, une tranche sans rienla branche pointée le montre entier ; vide, la clé s'affiche
radialmenu : lecture de droite à gauchela couronne tournait dans le sens horaire, ← remontaitla couronne tourne dans l'autre sens, ← et → s'échangent

La recette : (1) of_show rend un long : un appel seul compile tel quel ; (2) remplacez of_show(-1, -1) par of_show() ; (3) si vous défaisiez dans ue_dismissed ce que vous posiez à l'ouverture, rien à faire : il arrive désormais aussi quand une roue en remplace une autre ; (4) une poignée obtenue par une clé portée par deux branches ne change plus rien : donnez l'adresse.

11.38 toaster : des événements qui disent quel toast, des refus qui se disent, un toast qui attend d'être vu #

Les trois événements du toast changent de signature, of_add_button rend un code, et un toast ne se perd plus quand l'application est réduite.

Quoi3.04.0
toaster : ue_toast_clicked, ue_toast_action, ue_toast_dismissed(string as_key …) : as_key portait l'identifiant du toast, en texte(long al_id, string as_key …) : al_id est le nombre rendu par of_show, as_key le is_key du toast (vide sans clé)
toaster : of_add_buttonrendait le nombre de boutons ; une clé déjà prise, une clé vide et un quatrième bouton passaient sans un motrend 0 ; -5 sans rien ajouter pour une clé vide, déjà prise, qui contient / ou une barre verticale, ou un quatrième bouton. Le nombre se lit par of_count()
toaster : of_show avec un réglage hors bornesmontrait quand même : une nature inconnue en information, un coin inconnu en haut à gaucherend -5 et ne montre rien : is_kind, is_position ou is_sound hors de leurs constantes, il_max_visible hors de 0 à 20, il_timeout sous TIMEOUT_AUTO
toaster : la même is_key montrée par deux toastersle second remplaçait le toast du premier et lui prenait ses événements ; une mise à jour gardait le coin d'originechaque toaster a le sien ; une mise à jour reprend aussi le coin, l'ancrage à l'écran et la fenêtre d'ancrage
toaster : le sonun son système à chaque toast, information et succès compris ; aucun pour un toast sorti de la file d'attenteis_sound : SOUND_AUTO (défaut) = erreur et avertissement seulement, SOUND_ALWAYS, SOUND_NEVER ; joué quand le toast est demandé, même s'il attend sa place
toaster : toasts ancrés à l'écran depuis deux fenêtres, ou sans ipo_ownerse posaient exactement l'un sur l'autre ; le plafond se comptait par fenêtreune seule pile par moniteur et par coin, et il_max_visible compte par moniteur
toaster : un toast ancré à une fenêtre réduitepartait à -32 000 px et s'éteignait sans avoir été vuattend : il ne s'affiche pas et son compte à rebours ne tourne pas avant le retour de la fenêtre
toaster : un toast qui arrive pendant que la pile est survoléedécomptait son temps et pouvait partir pendant la lecturenaît en pause, comme les autres
toaster : PBT_SetLanguage, PBT_SetDefaultTheme, PBT_SetDefaultThemeAccent, PBT_SetDefaultFont, PBT_SetFlowDirection pendant qu'un toast est affichéne l'atteignaient pas ; la taille de police restait 11 ptle suivent aussitôt, taille de police comprise
toaster : le texte d'un toastne se sélectionnait pas ; saisir la barre de défilement d'un long texte pouvait répondre et fermerse sélectionne et se copie (clic droit, Copier) ; la sélection et la barre de défilement ne ferment plus le toast
toaster : il_button_countvariable publiqueprivée : lisez le nombre de boutons par of_count()
toaster : un toast dont le texte cite __licensene s'affichait pass'affiche : seul un mot réservé écrit en clé reste refusé
toaster : of_close d'un toast affichéaucun événementue_toast_dismissed, comme sa croix ; un toast encore en attente, jamais vu, ne lève rien

La recette : (1) ajoutez long al_id en premier argument de vos ue_toast_clicked, ue_toast_action et ue_toast_dismissed, et remplacez Long(as_key) par al_id ; as_key est désormais la clé du toast ; (2) si vous lisiez le retour de of_add_button comme un nombre de boutons, lisez of_count() ; (3) pour garder un son sur une information ou un succès, posez is_sound = SOUND_ALWAYS.

11.39 messagebox : un champ obligatoire vide n'est jamais validé, des choix aux clés uniques #

Cinq comportements changent ; aucune signature.

Quoi3.04.0
messagebox : ib_input_required et un bouton par défaut à compte à rebours (of_add_button_timed)le clic automatique validait la boîte champ vide (of_show rendait le bouton, of_input_value une chaîne vide)le compte à rebours s'épuise sans cliquer ; le bouton attend que le champ soit rempli
messagebox : Échap ou Alt+F4 sur un bouton à la fois par défaut et d'annulation, champ obligatoire viderendait 1, comme un clic sur ce boutonrend 0 : fermée sans choix
messagebox : of_add_choiceacceptait une clé déjà prise, ou qui contient / ou ``rend -5 et n'ajoute rien
messagebox : of_choose sans aucun choixmontrait une boîte à un seul bouton Annulerne montre rien : chaîne vide, et of_get_last_error dit « no choice to show »
messagebox : les boutons des boîtes prêtes (of_info, of_confirm, of_yes_no, of_prompt…) quand l'application n'a posé aucune langue« Ok »« OK », le mot du catalogue anglais (« Cancel », « Yes », « No » pour les autres)

La recette : (1) un champ obligatoire se valide désormais à la main — si vous comptiez sur le clic automatique pour avancer, donnez une valeur par défaut au champ (is_input_value) ; (2) donnez à chaque choix une clé unique, sans / ni |, et testez -5 si vos clés viennent de données.

11.40 Socle : la langue annoncée par défaut, les nombres décimaux de tout poste #

Deux corrections du socle, valables pour tous les composants ; aucune signature ne change.

Quoi3.04.0
la langue annoncée par un composant (<html lang>)le français, tant que l'application ne choisissait pas de languel'anglais, la langue par défaut des composants ; la langue choisie par l'application la remplace toujours
un nombre décimal donné à une propriété (id_*)seule la virgule décimale était convertie : sur un poste dont le séparateur décimal est un autre caractère, la valeur n'arrivait pasle séparateur décimal du poste, quel qu'il soit, est converti

La recette : rien à changer. Une application qui choisit sa langue la voit toujours appliquée ; une lecture d'écran qui lisait en français un composant d'une application anglaise le lit désormais en anglais.

11.41 Clavier, focus et place : ce que les tests de la 4.0 ont redressé #

Des comportements vus en jouant les composants dans une vraie application ; aucune signature ne change, une méthode s'ajoute.

Quoi3.04.0
Entrée sur un CommandButton PowerBuilder qui a le focusrien (la touche se perdait)le bouton est pressé (clicked), comme dans une boîte de dialogue Windows ; le bouton par défaut d'une barre ne l'est pas
Un composant désactivé (ib_enabled = false)Tab s'arrêtait dessusil sort de l'ordre de tabulation ; réactivé (ou of_reset), il y reprend sa place
Un raccourci Ctrl + un caractère sans touche à lui (AZERTY : - sur la touche 6, + avec Maj)Ctrl+- ne trouvait pas son accordaprès la touche, le caractère de la disposition active : Ctrl+-, Ctrl++, Ctrl+,, Ctrl+. partent sur tout clavier
La frappe dans un menu ouvert (recherche, lettres soulignées)une touche de la rangée du haut donnait son chiffre (AZERTY : - arrivait en 6)le caractère de la disposition ; une lettre soulignée &1 répond toujours à la touche 1
Le calendrier du sélecteur de date (toolbar)à la souris seulementau clavier aussi : flèches (jour, semaine), Page préc./suiv. (mois), Début/Fin, Entrée choisit, Échap ferme
Alt avec deux rubans (ou barres de menus) dans la même fenêtre, sans sous-fenêtre entre euxle premier crééle plus proche du focus à l'écran
breadcrumb dans une barre très étroitele premier segment ne cédait jamais : le lieu courant tombait à rien, le fil débordaitaprès le milieu, le lieu courant cède jusqu'à une lettre et « … », puis le premier segment ; rien ne sort de la barre
menubar : un choix fait à la souris dans le déroulantle focus restait sur la barre (Édition > Coller ne collait nulle part)le focus revient au contrôle qui l'avait
ribbon : taper dans une zone de liste puis choisir dans sa listedeux ue_combo_changed : le texte tapé, puis le choixun seul, le choix
toolbar : is_text = "" posé dans ue_text_changed, le focus dans le champl'ancien texte revenait, avec un second événementle champ reste vide
Le focus rendu à un composant après une fenêtre de la bibliothèque (palette de commandes)la page, sans élément : le curseur de l'éditeur de code avait disparul'élément qui l'avait
Un libellé à lettre soulignée (&File) en droite-à-gaucheles lettres en désordre (« ileF »)le mot se lit dans l'ordre
n_pbt_utils.of_dir_folders(as_dir, ref as_names[])DirList dans une ListBox : 4,5 s pour 30 000 dossiers, et le dossier courant de l'application changeaitnouveau : les sous-dossiers comme l'Explorateur les montre, triés, en une passe ; -4 illisible, -5 chemin vide
breadcrumb : of_add_children(as_keys, as_child_keys[], as_texts[])une branche à la fois (of_add_child) : 30 000 sous-dossiers ouvraient le menu en plus de 20 snouveau : toute une rangée en un appel

La recette : rien à changer. Une application dont un CommandButton focalisé devait ignorer Entrée le rend inactif (Enabled = false) ou lui retire le focus ; pour un dossier volumineux, remplacez la boucle d'of_add_child par un seul of_add_children.

11.42 Données et clavier : ce que le second lot de tests de la 4.0 a redressé #

Des comportements vus en jouant les composants de données dans une vraie application ; aucune signature ne change.

Quoi3.04.0
Entrée ou Échap frappées dans un composant qui ne les prend pasperdues : le bouton Default ou Cancel d'un CommandButton PowerBuilder ne partait pasla touche revient à la fenêtre PowerBuilder, comme le promet le chapitre 6.4 : Échap presse le bouton Cancel, Entrée le bouton Default
PBT_SetLanguage suivi aussitôt d'un ordre au composantle texte d'un événement levé par cet ordre (ue_error de xmltree) restait dans l'ancienne languela langue vaut dès l'ordre suivant
jsontree, xmltree : le focus donné au composant (of_focus_webview, la touche Tab)restait sur la page : les flèches et Entrée n'allaient nulle partl'arbre le prend ; F3 et Maj+F3 passent à l'occurrence suivante ou précédente de la recherche
xmltree : une erreur signalée APRÈS le dernier caractère de sa ligneaucune colonne soulignéela fin de la ligne est marquée (↵)
codeeditor en retour à la ligne (ib_wrap)la bande il_doc_line pouvait se poser une rangée trop haut, sur la fin de la ligne précédenteles bandes couvrent toutes les rangées de leur ligne et suivent le redimensionnement
codeeditor : « Tout remplacer » et of_replace_all sur un long texteplusieurs secondes quand le focus était dans l'éditeur ; au-delà, of_replace_all pouvait rendre 0instantané, et le nombre de remplacements est rendu ; Ctrl+H avec une recherche vide met le curseur dans « Rechercher »
crosstab : « Ajouter aux colonnes » (ou aux lignes, aux filtres) depuis le menu d'une puce, au clavierle focus se perdait ; seule Entrée ouvrait le menu d'une pucele focus suit la puce dans sa nouvelle zone ; Maj+F10 et la touche Menu ouvrent aussi son menu
json : des milliers de of_add_* à la suiteprès d'une seconde pour 2 000 lignesquelques dizaines de millisecondes ; le document est le même

La recette : rien à changer. Une application qui traitait elle-même Échap frappée dans un composant (un raccourci enregistré par of_register_shortcut) le garde : un raccourci passe avant la fenêtre.

11.43 Contenu et médias : ce que le troisième lot de tests de la 4.0 a redressé #

Des comportements vus en jouant les composants de contenu et de médias dans une vraie application ; aucune signature ne change.

Quoi3.04.0
speechout : of_speak puis of_pause dans le même scriptue_started et la première ue_sentence arrivaient avant ue_paused : la voix était annoncée partieue_started est levé quand la voix se met réellement à parler ; une pause posée avant la tient : rien n'est dit ni annoncé jusqu'à of_resume
speechout : une langue sans voix exacte sur le poste (fr-CA là où il n'y a que fr-FR)ue_started annonçait la langue demandée (fr-CA)ue_started annonce la langue réellement lue (fr-FR), après ue_voice_fallback
webbrowser : Tab après le dernier contrôle de la barre d'adressele focus quittait le composant pour la fenêtre PowerBuilderle focus entre dans le site, comme dans un navigateur ; Maj+Tab depuis le site revient à la barre
webbrowser : ib_private = true posé alors que la navigation est déjà privéesans effet : le site retrouvait ce qu'il avait gardé dans la session privéeune session privée neuve et vide à chaque fois
video en plein écran : une boîte modale de l'application (un MessageBox dans ue_ended)cachée sous le film, qui lui reprenait le clavier : l'application semblait figéele film cède : la boîte passe devant et reçoit le clavier ; à sa fermeture, le film reprend l'écran et Échap en sort
tilesbox : une flèche au bord, à côté d'une tuile plus petiteFlèche haut sur une grande tuile du premier rang sautait de côté, sur la petite voisineseule une tuile entièrement au-delà du bord compte : au bord, le focus reste en place
dockcontainer : il_back_color / il_text_color d'un panneau empiléperdues dès que son onglet était actif (il prenait l'accent du thème)l'onglet actif garde les couleurs du panneau, comme sa languette sur le rail
progressbar : id_value posé à chaque tour d'une longue boucleenviron 2,5 s pour 20 000 lignesbien moins d'une seconde ; la barre avance toujours pendant la boucle

La recette : rien à changer. Une application qui comptait sur ue_started pour savoir qu'of_speak avait été accepté lit plutôt son code retour (0) ; celle qui compare la langue de ue_started à is_lang apprend désormais le repli par cette différence, en plus de ue_voice_fallback.

11.44 Données : lire une cellule, trier et chercher plus finement (json, jsontree, xmltree, crosstab) #

Ces ajouts de la 4.0 ne retirent aucune signature. Deux changent ce que vous voyez sans que vous ayez rien écrit : Ctrl+C du crosstab copie désormais les en-têtes, et ue_cell_double_clicked reçoit un argument de plus.

Quoi3.04.0
crosstab : ue_cell_double_clicked( string as_row_tuple_json, string as_col_tuple_json, double ad_value )( string as_row_tuple_json, string as_col_tuple_json, integer ai_measure, double ad_value ) : ai_measure est la position de la valeur double-cliquée dans Valeurs, à partir de 1 ; avec les deux tuples, c'est l'adresse que relit of_get_cell_value
crosstab : Ctrl+C sur des cellulesles chiffres seulsles en-têtes avec : les noms des colonnes sur une première ligne, le membre de chaque ligne (son chemin, « North / Boston ») dans une première colonne ; ib_copy_headers = false rend les chiffres seuls
crosstab : of_remove_field, of_get_cell_value—nouveaux : retirer un champ de toutes les zones sans reconstruire la disposition ; lire la valeur d'une cellule par ses tuples et la position de sa mesure
json : of_get_array, of_pretty (long al_indent)—nouveaux : tous les éléments d'un tableau en un appel ; une indentation en espaces, ou le document compact sur une ligne avec 0
jsontree, xmltree : la recherchetoujours sans casse, et à l'intérieur des motsib_find_match_case et ib_find_whole_word, comme le codeeditor, avec les bascules Aa et ab de la zone de recherche ; par défaut, la recherche reste celle de la 3.0

La recette : un script de ue_cell_double_clicked n'a rien à changer, l'argument s'ajoute avant la valeur. Une application qui recolle le résultat de Ctrl+C dans un traitement qui n'attend que des chiffres pose ib_copy_headers = false.

11.45 Navigation et conteneurs : onglets au clavier, panneaux au double-clic (tab, dockcontainer, ribbon, stepbar, listbar) #

Ces ajouts de la 4.0 ne retirent aucune signature. Trois gestes changent ce que voit un utilisateur sans que vous ayez rien écrit : le clic du milieu et Ctrl+Tab sur un tab, et le double-clic sur un panneau de dockcontainer ou sur la barre de titre de sa fenêtre flottante.

Quoi3.04.0
tab : clic du milieu sur un ongletrienferme un onglet fermable, par le même chemin que sa croix : ue_tab_closing si ib_veto_close = true, puis ue_tab_closed ; un onglet non fermable ou désactivé ne fait rien
tab : Ctrl+Tab, Ctrl+Maj+Tab, Ctrl+Page suivante / précédenterienl'onglet suivant ou précédent qui peut devenir actif, en boucle, que le clavier soit dans la bande ou dans une page hébergée (un contrôle PowerBuilder, un autre composant) ; c'est un geste : ue_selection_changing si ib_veto_selection = true, puis ue_selection_changed. Depuis un contrôle hors du tab, la touche reste à la fenêtre
dockcontainer : double-clic sur un en-tête ou un onglet ; sur la barre de titre d'une fenêtre flottanterien ; la fenêtre flottante s'agrandissaitdétache le panneau dans une fenêtre flottante (ue_panel_floated) ; sur la barre de titre de cette fenêtre, le raccroche à sa place (ue_panel_docked), comme sa croix
dockcontainer : clic droit sur un en-tête ou un ongletrienun menu Détacher, Fermer, Fermer les autres (les autres panneaux fermables du même groupe) ; chaque fermeture pose sa propre question
dockcontainer : ib_veto_close, ue_panel_closing, of_close_panel, n_pbt_dock_panel.ib_closable—nouveaux : la question avant la fermeture d'un panneau (facultative, false par défaut), la fermeture par le code (-4 si vous la refusez, -5 pour le panneau principal ou un panneau non fermable), et la possibilité de fermer changée en direct
ribbon : n_pbt_ribbon_item.is_image, id_min, id_max, id_stepfixés à l'ajoutl'image d'un contrôle et la plage d'un compteur se changent en direct et se relisent ; la valeur d'un compteur est ramenée dans sa nouvelle plage sans lever ue_value_changed, comme id_value
stepbar : STATE_WARNING, STATE_SKIPPED, NAV_VISITED—nouveaux : une étape passée avec un avertissement (pastille ambre), une étape ignorée (anneau en pointillés), et un mode où toute étape déjà atteinte reste cliquable, même en avant après un retour
listbar : n_pbt_listbar_section.ib_pinned—nouveau : une section épinglée en bas de la barre (Paramètres, Aide), qui reste visible quand la barre défile, dans le rail aussi ; la disposition enregistrée garde l'ordre des sections

La recette : rien à changer. Dans une page de tab, Ctrl+Tab change désormais d'onglet même quand le focus est dans un contrôle de la page, comme dans une boîte de propriétés de Windows. Pour agrandir une fenêtre flottante du dockcontainer, son bouton Agrandir reste là.

11.46 Menus : le chevron de la barre de menus, une liste déroulante dans la barre d'outils, dix mille commandes (menubar, toolbar, commandpalette) #

Ces ajouts de la 4.0 ne retirent aucune signature. Un comportement par défaut change : une barre de menus trop étroite ne revient plus à la ligne, elle replie ses derniers titres dans un chevron. Et of_open d'une palette de commandes ne refuse plus de s'ouvrir sans ipo_owner ni ipo_receiver.

Quoi3.04.0
menubar : une barre trop étroite pour ses titresrevenait à la ligne : sa hauteur suivait les rangées, ue_auto_height à chaque changement de largeurreste sur une ligne : les titres qui ne tiennent pas, depuis la fin, passent dans le déroulant d'un chevron (leurs entrées en cascade, Alt + leur lettre les ouvre depuis le chevron, les flèches s'y arrêtent comme sur un titre, à gauche en RTL) ; la hauteur ne change plus. ib_wrap = true rend l'ancien comportement
menubar : ib_track_hover, ue_item_hover, of_add_header, n_pbt_menubar_menu.is_align—nouveaux : l'entrée pointée dans un déroulant, pour l'aide d'une barre d'état (facultatif, false par défaut ; une adresse vide à la fermeture), des en-têtes de section dans un déroulant, et un menu calé au bout de la barre (ALIGN_END, Aide)
toolbar : of_add_combo, of_add_combo_item, of_remove_combo_item, of_clear_combo, ue_combo_changed, n_pbt_toolbar_item.ib_editable—nouveaux : une liste déroulante dans la barre, modifiable ou non, que l'on garde vivante repliée dans le chevron ; son event porte le nom et le sens de celui du ruban
commandpalette : deux palettes posées sur le même ipo_ownerpartageaient leur file d'événements (l'une pouvait recevoir le ue_closed de l'autre), et la seconde reprenait l'accord de la premièrechacune ses événements et son accord ; un même accord posé par la seconde lui revient (1). of_open et of_register_shortcut ne rendent plus -5 sans ipo_owner ni ipo_receiver : les événements arrivent toujours
commandpalette : des milliers de commandeschaque ligne dessinée : l'ouverture et la frappe ralentissaientseules les lignes visibles sont dessinées : 10 000 commandes s'ouvrent et se filtrent sans attente
Raccourcis de toute la bibliothèque : AltGr + une touche qui écrit un caractère (l'euro d'un clavier français)lançait le raccourci Ctrl+Alt de cette touche, dans un champ PowerBuilder aussile caractère est tapé, aucun raccourci ne part ; AltGr seul ne donne plus le clavier à une barre de menus ou à un ruban

La recette : une barre de menus dont la hauteur variable était voulue pose ib_wrap = true ; une application qui repositionnait ses contrôles dans ue_auto_height à chaque redimensionnement n'a plus rien à faire après le premier. Un raccourci de l'application posé sur Ctrl+Alt + une lettre que le clavier de l'utilisateur écrit avec AltGr ne part plus pendant qu'il tape : choisissez une autre touche.

11.47 Contenu et médias : un journal ligne à ligne, la taille réelle d'une image, l'attente d'un film (statictext, picture, video) #

Ces ajouts de la 4.0 ne retirent aucune signature et ne changent aucun défaut. Deux comportements se précisent : le zoom d'une image peut dépasser son plafond pour atteindre la taille réelle, et un film d'une URL lu sans réseau le dit.

Quoi3.04.0
statictext : of_append_text, ib_follow_end—nouveaux : un journal qui s'écrit ligne à ligne — seule la ligne ajoutée part vers le composant — et, sur option, la vue qui reste en bas tant que le lecteur ne remonte pas
statictext : ib_auto_width, ue_auto_width—nouveaux : l'userobject prend la largeur de son texte (facultatif, false par défaut), comme ib_auto_height le fait pour la hauteur
picture : id_max_zoom, la touche 1le zoom s'arrêtait à 8.0 fois le cadrage, quoi qu'il arrive : un grand scan affiché petit ne se lisait jamais pixel pour pixelle plafond se règle (id_max_zoom, 8.0 par défaut) ; la touche 1 montre la taille réelle, et le plafond s'élève jusqu'à elle quand elle demande davantage
video : ue_buffering, of_is_bufferingun film qui attendait ses données restait figé sans rien direun anneau à l'accent du thème tourne sur l'image, et ue_buffering(true) puis ue_buffering(false) encadrent l'attente
video : un film d'une URL alors que le poste n'a pas de réseau« ce fichier est introuvable ou illisible », ue_failed avec REASON_UNSUPPORTED« pas de connexion réseau » sur l'image, ue_failed avec REASON_NETWORK

La recette : rien à changer. Un journal qui réécrivait is_text à chaque ligne passe à of_append_text ; un code qui testait REASON_UNSUPPORTED pour un film d'une URL hors réseau teste REASON_NETWORK.

11.48 Revue du 03/10/2026 : une disposition remise se dit, un export vers un chemin relatif tombe au bon endroit (toolbar, crosstab) #

Aucune signature ne change. Deux comportements s'alignent sur la règle de la bibliothèque : tout changement de disposition se dit, et un chemin relatif d'écriture se résout comme pour les autres exports.

Quoi3.04.0
toolbar : of_set_layoutaucun événementlève ue_layout_changed, comme le dockcontainer et le datagrid : tout changement de disposition se dit, qu'il vienne de l'utilisateur ou de votre code
crosstab : of_export_csv, of_export_xlsx vers un chemin relatifécrit dans le dossier courant du moment — qu'un DirList ou une boîte de fichiers avait pu déplacer ; ue_csv_saved / ue_xlsx_saved rendaient le chemin tel que donnéécrit dans le dossier où l'application a démarré, comme les autres exports natifs ; l'event rend le chemin complet ; un chemin qui dépend du dossier courant d'un lecteur (\x, C:x) est refusé

La recette : une application qui enregistre la disposition dans ue_layout_changed réenregistre la même valeur après of_set_layout — sans conséquence. Un export qui comptait sur le dossier courant du moment donne un chemin complet.


← Migrer de la 2.0 à la 3.0 · Sommaire · Notes de version →