treeview — u_pbt_treeview #
← Référence des composants · Sommaire du guide
treeview montre des données en arbre : des nœuds qui en contiennent d'autres, ouverts et fermés par leur chevron, avec une image, un badge, une case à cocher à trois états et une sélection simple ou multiple. Dès qu'on lui ajoute une colonne, il devient une liste en arbre (TreeList) : la première colonne porte l'arbre, les autres montrent les champs de chaque nœud, triables d'un clic sur leur en-tête. Une branche peut promettre des enfants qu'elle ne lit qu'à l'ouverture ; l'utilisateur renomme un nœud (F2) et le glisse ailleurs, votre application pouvant refuser avant ; une recherche ne garde que ce qui correspond. L'arbre se remplit à la main ou depuis un DataStore hiérarchique (une ligne nomme son parent), et peut y réécrire ce que l'utilisateur change.
▶ Le voir en vrai — Application de démonstration, tuile Tree view : l'aperçu, le code qui le produit et cette page, côte à côte.
En bref #
| Userobject | u_pbt_treeview |
| Classes d'items | n_pbt_treeview_node (of_node(keys)), n_pbt_treeview_column (of_column(key)) |
| Sert à | Une arborescence de dossiers, un organigramme, des catégories de produits, des droits à cocher, une nomenclature avec ses quantités |
| Principe | Un nœud a une clé unique sous son parent ; son adresse joint les clés de ses niveaux par / ("europe/france") |
| Options opt-in | ib_checkboxes, ib_editable, ib_drag_drop, ib_veto_changes, ib_veto_selection, ib_veto_toggle, ib_single_expand, ib_parents_first, ib_toolbar, ib_show_lines, ib_write_back, ib_allow_drop |
| Limite en mode démo | Les 8 premiers nœuds de chaque niveau dessinés, sous chaque parent, dans l'ordre du modèle, et 200 nœuds dans tout l'arbre, les premiers ajoutés (un nœud masqué compte, lots et groupes compris ; un total ne compte jamais ce que le plafond cache) — voir le mode démo |
Démarrage rapide #
// Two levels : a continent, then its countries (the parent is added first)
uo_tree.of_add_node(/*keys*/ "europe", /*text*/ "Europe")
uo_tree.of_add_node(/*keys*/ "europe/france", /*text*/ "France")
uo_tree.of_add_node(/*keys*/ "europe/italy", /*text*/ "Italy")
// Open the continent : its countries show
uo_tree.of_node(/*keys*/ "europe").ib_expanded = true
// event ue_node_opened of uo_tree : (string as_keys)
// A double click or Enter on a node : your own window shows it
OpenWithParm(w_country, as_keys)
Une adresse par nœud #
Un nœud est désigné par son adresse : les clés de ses niveaux jointes par /. "europe" est en haut, "europe/france" dans "europe" — le parent est ajouté d'abord. Une clé est unique sous son parent : "europe/paris" et "usa/paris" sont deux nœuds. Une adresse prise, un parent inconnu, un niveau vide, une clé qui contient | ou commence par __ : l'ajout rend -5 et of_get_last_error dit pourquoi. of_insert_node place un nœud parmi ses frères (position comptée à partir de 1), of_move_node le déplace avec son sous-arbre sous un autre parent ("" = en haut) : son adresse change, et les poignées prises à l'ancienne adresse sont libérées aussitôt (une poignée prise ensuite à la nouvelle reste valable). Pour parcourir l'arbre : of_count() et of_keys_at(n) pour le premier niveau, of_count(adresse) et of_keys_at(adresse, n) pour les enfants d'un nœud — qui rend l'adresse complète, réutilisable telle quelle.
// Local variables
long ll_i
// Paris first among the cities of France, then Italy moved under a new region
uo_tree.of_add_node(/*keys*/ "europe/france/lyon", /*text*/ "Lyon")
uo_tree.of_insert_node(/*keys*/ "europe/france/paris", /*text*/ "Paris", /*image*/ "", /*position*/ 1)
uo_tree.of_add_node(/*keys*/ "south", /*text*/ "Southern Europe")
uo_tree.of_move_node(/*keys*/ "europe/italy", /*to_parent_keys*/ "south", /*position*/ 1)
// The children of France, by their whole address
for ll_i = 1 to uo_tree.of_count(/*keys*/ "europe/france")
lb_cities.AddItem(uo_tree.of_keys_at(/*keys*/ "europe/france", /*index*/ ll_i))
next
Ouvrir, sélectionner, cocher #
Un nœud s'ouvre par son chevron, un double-clic, le clavier ou votre code (ib_expanded de sa poignée, of_expand_all, of_collapse_all, of_expand_to_level, of_scroll_to_node, ce qu'ouvre of_select_node ; of_clear_children ferme) : chacun lève ue_node_toggled, puis ue_layout_changed. La sélection suit is_selection_mode : un nœud (SELECT_SINGLE, le défaut), plusieurs avec Ctrl et Maj comme dans l'Explorateur (SELECT_MULTIPLE), ou aucun (SELECT_NONE : le clavier ne déplace qu'un focus). of_select_node sélectionne un nœud seul, ouvre ce qui le contient et l'amène à l'écran — un arbre ouvre pour sélectionner, comme le TreeView de Windows, mais il juge d'abord : un nœud masqué ou contenu par un masqué, au-delà du plafond démo ou écarté par la recherche est refusé (-5, of_get_last_error dit pourquoi) et rien ne s'ouvre. ue_selection_changed reçoit les adresses sélectionnées en tableau JSON — qu'un clic, le clavier ou votre code l'ait changée, ou qu'un nœud sélectionné ait quitté l'écran (branche fermée, nœud retiré ou masqué, nœud caché par la recherche). Fermer une branche y ramène le focus. Avec ib_checkboxes, chaque nœud a une case ; avec ib_check_cascade (le défaut), une coche de l'utilisateur sur un parent coche son sous-arbre sauf un nœud grisé et son sous-arbre, qui restent tels quels (le parent est alors mixte) ; une coche de votre code coche tout. Pendant une recherche, la cascade prend tout le sous-arbre, nœuds cachés compris. Sous la cascade, un parent est l'état des enfants que l'arbre peut dessiner (ni masqués ni, en mode démo, au-delà du plafond) : coché quand ils le sont tous, mixte quand une partie l'est. Une coche posée par l'utilisateur lève ue_node_checked ; une coche posée par votre code (ib_checked, of_check_all) est une valeur, muette comme SetItem. Les enfants reçus sous une feuille cochée prennent sa coche — tous, toute la réponse à ue_children_needed — jusqu'à ce qu'une coche (geste ou code) ou un nœud déplacé dedans y mette fin. Une coche de l'utilisateur ne touche jamais un nœud au-delà du plafond démo, ni, avec ib_write_back, un nœud masqué. of_select_nodes(as_keys_json) sélectionne plusieurs nœuds d'un coup en SELECT_MULTIPLE — le pendant d'of_selected_keys — avec une seule question aux vétos et un seul ue_selection_changed ; le focus va à la dernière adresse nommée.
// Local variables
n_pbt_json lnv_json
string ls_keys[]
long ll_i
// A box before each node : checking a parent checks its subtree
uo_tree.ib_checkboxes = true
uo_tree.of_node(/*keys*/ "europe/france").ib_checked = true
// Every checked node, in the order of the tree
lnv_json.of_load(/*json*/ uo_tree.of_checked_keys())
for ll_i = 1 to lnv_json.of_get_array(/*path*/ "", /*values*/ ls_keys)
lb_chosen.AddItem(ls_keys[ll_i])
next
Demander d'abord : la sélection et l'ouverture #
Un écran maître-détail ne doit pas quitter une fiche non enregistrée. Avec ib_veto_selection, ue_selection_changing reçoit la sélection actuelle et celle demandée (tableaux JSON d'adresses) avant tout choix : un clic, Ctrl ou Maj + clic, le clavier, F3, of_select_node, of_clear_selection, of_search_next ou of_search_prev. Rendez FALSE pour refuser : rien ne bouge, pas même le focus du clavier, et la méthode rend -4 ; ue_node_clicked est levé quand même, le clic a eu lieu. Ce qui sort de la sélection par conséquence — une branche fermée, un nœud retiré, masqué ou caché par la recherche — n'est pas demandé. De même, ib_veto_toggle pose ue_node_toggling avant chaque ouverture ou fermeture, d'un geste ou du code : un ib_expanded refusé n'envoie rien (of_get_last_error le dit), of_expand_all, of_collapse_all et of_expand_to_level appliquent les autres nœuds et rendent -4, of_select_node et of_scroll_to_node rendent -4 sans rien ouvrir. of_select_node demande d'abord les ouvertures (ue_node_toggling), puis la sélection : une application n'agit jamais sur une sélection acceptée pour une ouverture refusée ensuite. Ce qui sort de la sélection par conséquence ne se refuse pas : pour qu'une branche qu'on ferme ne quitte pas une fiche non enregistrée, associez ib_veto_selection à ib_veto_toggle et refusez la fermeture de la branche qui la contient. ib_single_expand ne laisse qu'une branche ouverte sous chaque parent : ouvrir un nœud ferme ses sœurs ouvertes, sans rien demander ; le poser ne ferme rien sur le moment.
// A record shown beside the tree : ask before the selection leaves it, and before
// a branch closes (closing the branch that holds it would leave it)
uo_tree.ib_veto_selection = true
uo_tree.ib_veto_toggle = true
// event ue_selection_changing of uo_tree : (string as_from_keys_json, string as_keys_json)
// Unsaved changes in the detail : the user decides
if dw_detail.ModifiedCount() > 0 then
if MessageBox("Unsaved changes", "Leave this record without saving?", Question!, YesNo!) = 2 then return false
end if
return true
// event ue_node_toggling of uo_tree : (string as_keys, boolean ab_expanding)
// Closing the branch that holds an unsaved record would leave it : refused
if not ab_expanding and dw_detail.ModifiedCount() > 0 then
if Pos(uo_tree.of_selected_key() + "/", as_keys + "/") = 1 then return false
end if
return true
Des branches lues à la demande #
Un grand arbre — un disque, un catalogue, une table de milliers de lignes — n'a pas à être lu d'un coup. ib_has_children = true sur un nœud est une promesse : son chevron s'affiche alors qu'il ne contient rien. Quand il s'ouvre — un clic, le clavier, votre code, ou of_select_node qui ouvre ce qui contient un nœud —, ue_children_needed est levé : vos of_add_node faits pendant l'événement sont là quand la branche s'ouvre, après le retour de la ligne qui l'a ouverte (ib_expanded = true ne les attend pas). La promesse tient jusqu'à cette réponse, même si un nœud y a été ajouté ou déposé entre-temps ; n'ajoutez rien, et elle est retirée (le chevron disparaît). Reposer ib_has_children = true la fait redemander à la prochaine ouverture. Une ouverture faite pendant l'événement ne lève qu'un ue_node_toggled. of_expand_all n'ouvre que les branches qui ont déjà des enfants : une branche dont la promesse n'a pas répondu reste fermée, aucune question n'est posée en masse. Pour une table, inutile d'appeler of_add_node ligne par ligne : of_from_datastore(ads, as_parent_keys) fait des lignes d'un DataStore les enfants du nœud, en un seul envoi — le patron ItemPopulate → Retrieve du TreeView de PowerBuilder. ROLE_PARENT y nomme une ligne du même lot (vide ou inconnu : directement sous le nœud) ; le même DataStore redonné sous le même nœud remplace son lot, un autre DataStore ajoute le sien. of_row d'un nœud de lot rend sa ligne dans son DataStore, et ib_write_back y écrit. of_clear_children retire les enfants d'un nœud et lui fait promettre de nouveau : sa prochaine ouverture redemande (le « rafraîchir » d'un dossier). Donnez à chaque lot son propre DataStore (créé à l'ouverture de sa branche, gardé tant que ses nœuds sont montrés) : un DataStore rechargé pour un autre nœud — Reset, Retrieve, puis of_from_datastore sous un autre nœud — emporte ses lignes vers le nouveau lot, et PowerBuilder redonne les mêmes RowID après un Reset. Les nœuds du lot d'avant gardent alors ce qu'ils montrent mais n'ont plus de ligne : of_row rend 0, un déplacement par le code rend -5 (« loaded again »), un texte renommé ou une coche est refusé et ue_write_back_failed dit pourquoi, et le chargement qui l'a causé le compte (stale=N) dans of_get_last_error. Le même DataStore redonné sous le même nœud remplace son lot ; pour rafraîchir un lot depuis un autre objet DataStore, appelez d'abord of_clear_children, sinon il s'ajoute à côté du premier. Une colonne nommée has_children (ROLE_HAS_CHILDREN) fait promettre ses propres enfants à une ligne, sans boucle. as_parent_keys vide est refusé (-5) : le haut de l'arbre, c'est of_from_datastore(ads).
// A folder that promises children : nothing is read before it opens
uo_tree.of_add_node(/*keys*/ "docs", /*text*/ "Documents", /*image*/ "img\packimages.dll:png/folder")
uo_tree.of_node(/*keys*/ "docs").is_expanded_image = "mono:img\packimages.dll:svg/samples/folder-open"
uo_tree.of_node(/*keys*/ "docs").ib_has_children = true
// event ue_children_needed of uo_tree : (string as_keys)
// Local variables
datastore lds_folders
n_pbt_utils lnv_utils
// The folder opens : ITS sub-folders are retrieved into a DataStore of their own and
// added in ONE call - code is their key and name their text (of_map, once), the
// column has_children says whether each one promises its own
lds_folders = create datastore
lds_folders.DataObject = "d_folders"
lds_folders.SetTransObject(SQLCA)
// as_keys is the whole ADDRESS (docs/reports) : the code of the folder is its LAST key
lds_folders.Retrieve(lnv_utils.of_leaf(/*keys*/ as_keys))
uo_tree.of_from_datastore(/*ads*/ lds_folders, /*parent_keys*/ as_keys)
// One DataStore per lot, kept while its nodes are shown : of_row and ib_write_back
// read it ; the window destroys them when it closes
ids_lots[UpperBound(ids_lots) + 1] = lds_folders
Renommer et déplacer #
Avec ib_editable, l'utilisateur renomme un nœud : F2, ou un clic sur le nœud déjà sélectionné (après un court délai, comme l'Explorateur). Entrée (ou quitter le champ) garde le texte, Échap le rend, un texte vidé est refusé (l'édition s'annule) ; ue_node_edited reçoit le texte tapé et l'ancien — un texte tapé est du texte, jamais du balisage. Une commande de votre code pendant l'édition garde le champ et ce qui y est tapé ; si la ligne éditée quitte l'écran sans geste de l'utilisateur (code, défilement), l'édition est annulée. Avec ib_drag_drop, il glisse un nœud : sur le quart haut d'une ligne il va avant elle, sur le quart bas après — en premier enfant si c'est une branche ouverte —, au milieu dedans ; une branche fermée survolée s'ouvre au bout d'un instant, l'arbre défile près de ses bords, Échap annule, un nœud ne va jamais dans son propre sous-arbre ni là où sa clé est prise, et rien ne se dépose sur la ligne d'un nœud grisé. Un glisser dont l'arbre ne voit pas le bouton relâché — la fenêtre perd le focus (Alt+Tab, une boîte de message) — est annulé : rien ne bouge. Sous un tri, ou avec ib_parents_first, un dépôt ne va que dedans. ue_node_moved reçoit la nouvelle adresse, l'ancienne et la place sous le nouveau parent ; un nœud lâché à sa place ne demande, n'écrit ni ne lève rien. Avec ib_veto_changes, ue_node_editing et ue_node_moving sont posés avant — ue_node_moving avec la place finale, celle que dira ue_node_moved : rendez FALSE pour refuser — rien ne change, et of_move_node rend -4. Un seul nœud glisse à la fois, même en sélection multiple.
// Renaming and moving by the user, with a question before each change
uo_tree.ib_editable = true
uo_tree.ib_drag_drop = true
uo_tree.ib_veto_changes = true
// event ue_node_moving of uo_tree : (string as_keys, string as_to_parent_keys, long al_position)
// Nothing goes to the top level : FALSE keeps the node where it is
if as_to_parent_keys = "" then return false
return true
Votre code ouvre lui aussi un nom en édition : of_edit_node(as_keys) — l'EditLabel d'un TreeView PowerBuilder, pour un « Nouveau dossier » qui s'ouvre prêt à être nommé. Le nœud est d'abord sélectionné (ce qui le contient s'ouvre), puis le champ s'ouvre ; la fin appartient à l'utilisateur, comme ci-dessus. Un verrou arrête l'utilisateur, jamais votre code : il marche avec ib_editable = false, sur un nœud en lecture seule ou grisé. of_cancel_edit() ferme le champ et rend le texte, comme Échap.
// A new folder, opened at once in edit mode : the user types its name, then Enter
uo_tree.of_add_node(/*keys*/ "docs/new", /*text*/ "New folder")
uo_tree.of_edit_node(/*keys*/ "docs/new")
Verrous, Suppr et copie #
Trois verrous par nœud arrêtent l'utilisateur, jamais votre code : ib_read_only (ni renommé ni glissé, il reste une cible), ib_drop_target = false (rien n'est déposé dedans, ni un nœud ni un fichier — avant ou après lui reste permis) et ib_show_checkbox = false (pas de case : le nœud ne compte pas pour son parent, n'est pas dans of_checked_keys, et la cascade le traverse vers ses enfants). Suppr lève ue_delete_requested avec les nœuds sélectionnés (en SELECT_NONE, celui du focus ; sans sélection sinon, rien n'est levé), sauf grisés et en lecture seule : l'arbre ne retire rien, votre application appelle of_remove_node pour ce qu'elle supprime. Ctrl+C (ou Ctrl+Inser) lève ue_copy avec les nœuds sélectionnés (en SELECT_NONE, celui du focus) en texte tabulé, un nombre brut (un point, ni groupement ni symbole) : le texte après autant de tabulations que sa profondeur, puis les colonnes d'une liste en arbre alignées, une ligne d'en-tête d'abord ; l'arbre essaie aussi le presse-papiers du navigateur, que la page peut se voir refuser — ClipBoard(as_tsv) pour être sûr.
// The system folder : neither renamed nor dragged, nothing dropped into it, no check box
uo_tree.of_node(/*keys*/ "system").ib_read_only = true
uo_tree.of_node(/*keys*/ "system").ib_drop_target = false
uo_tree.of_node(/*keys*/ "system").ib_show_checkbox = false
// event ue_delete_requested of uo_tree : (string as_keys_json)
// Local variables
n_pbt_json lnv_json
string ls_keys[]
long ll_i
// Delete pressed : the tree removes nothing, your application decides
lnv_json.of_load(/*json*/ as_keys_json)
for ll_i = 1 to lnv_json.of_get_array(/*path*/ "", /*values*/ ls_keys)
uo_tree.of_remove_node(/*keys*/ ls_keys[ll_i])
next
// event ue_copy of uo_tree : (string as_tsv)
// Ctrl+C : the nodes copied, ready for a spreadsheet
ClipBoard(as_tsv)
Des fichiers déposés depuis l'Explorateur #
Avec ib_allow_drop, l'arbre accepte des fichiers glissés depuis l'Explorateur de Windows sur un nœud : le nœud sous le curseur s'allume pendant le glisser, ue_drop_files reçoit son adresse et les chemins complets. as_keys est vide pour un dépôt à côté des nœuds, sur un nœud grisé ou sur un nœud dont ib_drop_target vaut false. ue_drag_enter et ue_drag_leave disent qu'un glisser de fichiers est entré, puis reparti sans rien déposer.
// Files of the Explorer dropped on a folder of the tree
uo_tree.ib_allow_drop = true
// event ue_drop_files of uo_tree : (string as_keys, string as_files[])
// The folder under the cursor : your application copies the files there
if as_keys <> "" then wf_copy_files(as_files, uo_tree.of_get_field(/*keys*/ as_keys, /*field*/ "path"))
Colonnes, tri et disposition #
of_add_column fait de l'arbre une liste en arbre : la première colonne porte l'arbre (son titre est is_tree_title), chaque colonne ajoutée montre le champ de même clé de chaque nœud — posé par of_set_field, ou une colonne du DataStore. La poignée d'une colonne (of_column) règle son titre, sa largeur (0 = automatique), son alignement, son format (un masque numérique comme "#,##0.00" aux séparateurs de la langue d'affichage, ou des jetons de date pour une valeur "yyyy-mm-dd", ceux du datagrid), sa visibilité et sa place. Un clic sur un en-tête trie les frères de chaque niveau — croissant, décroissant, puis l'ordre d'ajout — et lève ue_sort_changed ; of_sort fait de même par le code. Le tri ne change que l'ordre affiché : of_keys_at et les positions gardent l'ordre d'ajout. L'utilisateur élargit une colonne par le bord de son en-tête et la déplace en glissant l'en-tête. Ce qu'il a arrangé — largeurs, ordre, visibilité, tri, nœuds ouverts — se lit par of_get_layout et se rend par of_set_layout ; ue_layout_changed porte la disposition entière après chaque geste qui la change, et quand votre code écrit la largeur, la place ou la visibilité d'une colonne (ii_width, ii_index, ib_visible) et que la disposition change. Des valeurs égales gardent l'ordre du modèle, et le tri est refait quand la langue d'affichage change. Retirer la colonne triée (of_remove_column, of_clear_columns) lève ue_sort_changed avec la clé suivante du tri — SORT_NONE quand c'était la seule —, puis ue_layout_changed. Les cinq couleurs de la poignée d'une colonne (il_accent, il_back_color, il_text_color, il_back_color_hover, il_text_color_hover) colorent son en-tête. Dès qu'il y a des colonnes, la colonne de l'arbre reste figée au défilement horizontal. Le tri peut porter sur plusieurs clés : of_sort(as_sort) lit la syntaxe du SetSort d'un DataWindow (« type A, text D », « text » étant le texte des nœuds), of_sort(as_column, as_dir) accepte aussi un champ qu'aucune colonne ne montre, et ue_sort_changed reçoit le tri entier en troisième argument. ib_parents_first met à chaque niveau les nœuds qui ont (ou promettent) des enfants avant les feuilles — les dossiers avant les fichiers — quel que soit le tri. Une colonne ne peut pas prendre la clé text, qui nomme le texte des nœuds (-5) : of_sort("text", as_dir) trie par lui, et of_sort accepte plusieurs blancs entre une colonne et son sens, comme SetSort.
// A tree list : the population of each country beside the tree
uo_tree.is_tree_title = "Country"
uo_tree.of_add_column(/*key*/ "population", /*title*/ "Population", /*width*/ 120)
uo_tree.of_column(/*key*/ "population").is_format = "#,##0"
uo_tree.of_column(/*key*/ "population").is_align = u_pbt_treeview.ALIGN_END
uo_tree.of_set_field(/*keys*/ "europe/france", /*field*/ "population", /*value*/ "68000000")
// The largest countries first, inside each continent
uo_tree.of_sort(/*column*/ "population", /*dir*/ u_pbt_treeview.SORT_DESC)
// The folders first, then by type and by name
uo_tree.ib_parents_first = true
uo_tree.of_sort(/*sort*/ "type A, text A")
Exporter l'arbre avec sa hiérarchie : of_export_csv(as_path) écrit un CSV (UTF-8, point-virgule) où le texte d'un nœud se tient dans la cellule de son niveau — une cellule plus à droite par niveau —, les colonnes d'une liste en arbre après le niveau le plus profond, une ligne d'en-tête d'abord ; of_export_xlsx(as_path) écrit un classeur Excel où le texte est en retrait de son niveau et chaque branche groupée sous son parent, repliables dans Excel, les nombres restant des nombres. is_export_scope dit lesquels : EXPORT_ALL (le défaut) tous les nœuds, branches fermées comprises, EXPORT_SHOWN les lignes à l'écran. L'arbre construit le fichier, la DLL l'écrit, ue_csv_saved / ue_xlsx_saved confirment ; refusé en mode démo.
// The tree written to Excel - every node, the closed branches too ; ue_xlsx_saved confirms
uo_tree.is_export_scope = u_pbt_treeview.EXPORT_ALL
uo_tree.of_export_xlsx(/*path*/ "C:\exports\countries.xlsx")
Des totaux par branche #
Une colonne d'une liste en arbre peut montrer, sur chaque branche, le total de ce qu'elle contient : is_summary sur sa poignée vaut SUMMARY_SUM, SUMMARY_AVG, SUMMARY_MIN, SUMMARY_MAX ou SUMMARY_COUNT (les valeurs non vides). Le calcul descend jusqu'aux feuilles — une moyenne est celle des feuilles, jamais une moyenne de moyennes — et le total s'écrit en gras, par is_format — un compte toujours en nombre brut. Une branche qui a sa propre valeur la garde et la fait remonter, sauf avec ib_summary_over_value sur la colonne. Ne comptent que les nœuds que l'arbre peut dessiner (jamais un masqué) ; avec ib_summary_filtered, sur le composant, seulement ce que la recherche montre. of_get_field rend le total brut (un nombre au point), le tri sur cette colonne utilise les totaux, et les totaux suivent chaque ajout, retrait ou glisser. SUMMARY_MIN et SUMMARY_MAX comparent aussi des dates (yyyy-mm-dd, yyyy-mm-dd hh:mm:ss, hh:mm:ss), et une somme d'entiers reste exacte au-delà de 2^53.
// Each continent shows the sum of its countries, in bold
uo_tree.of_column(/*key*/ "population").is_summary = u_pbt_treeview.SUMMARY_SUM
// The total of Europe, read like a field
st_total.text = uo_tree.of_get_field(/*keys*/ "europe", /*field*/ "population")
Rechercher #
is_filter ne montre que les nœuds dont le texte contient la recherche (casse ignorée), avec les nœuds qui les contiennent, ouverts, et le texte trouvé surligné. "" rend tout. Ce qui contient une correspondance s'affiche ouvert sans changer ib_expanded, et les chevrons sont inertes le temps de la recherche. Avec ib_toolbar, une barre au-dessus de l'arbre porte un champ de recherche (qui écrit is_filter : une lecture le rend à l'instant), et les boutons Tout déplier et Tout replier. Échap dans le champ vide la recherche, Flèche bas passe à l'arbre, Entrée et F3 vont à la correspondance suivante (Maj : la précédente) sans que le champ perde le clavier. Un nœud sélectionné que la recherche cache sort de la sélection, et ue_selection_changed le dit ; le nœud qui le contient n'est pas sélectionné à sa place. of_select_node et of_scroll_to_node refusent un nœud que la recherche écarte (-5). Pour aller de correspondance en correspondance, of_search_next et of_search_prev sélectionnent la suivante ou la précédente après le nœud du focus, en boucle (F3 et Maj+F3 au clavier), et of_match_count dit combien la recherche en a trouvé. of_find_node(as_field, as_value, as_after_keys) trouve sans filtrer : l'adresse du premier nœud dont le champ ("" = son texte) vaut exactement la valeur, dans l'ordre que l'arbre montre, branches fermées comprises ; redonnez l'adresse trouvée pour le suivant. En SELECT_NONE, of_search_next et of_search_prev y déplacent le focus, comme F3. of_find_node part après la place d'as_after_keys dans l'ordre affiché — un nœud masqué aussi ; un nœud inconnu rend "" et of_get_last_error le dit. of_find_nodes(as_field, as_value) rend toutes les correspondances d'un coup, en tableau JSON dans l'ordre affiché.
La recherche ignore les accents par défaut, comme le tri : « montreal » trouve « Montréal », et le I pointé du turc compte pour un I (« izmir » trouve « İzmir ») ; ib_filter_accents = true les fait compter. En sélection multiple, Ctrl+A sélectionne tous les nœuds affichés (une seule question avec ib_veto_selection).
// A search field above the tree, and a first search from the code
uo_tree.ib_toolbar = true
uo_tree.is_filter = "par"
// Local variables
string ls_keys
// The first node whose code is FR, selected if there is one
ls_keys = uo_tree.of_find_node(/*field*/ "code", /*value*/ "FR", /*after_keys*/ "")
if ls_keys <> "" then uo_tree.of_select_node(/*keys*/ ls_keys)
// Every node whose status is late, selected at once (a multiple selection)
uo_tree.is_selection_mode = u_pbt_treeview.SELECT_MULTIPLE
uo_tree.of_select_nodes(/*keys_json*/ uo_tree.of_find_nodes(/*field*/ "status", /*value*/ "late"))
Depuis un DataStore #
of_from_datastore fait un nœud de chaque ligne d'une table hiérarchique : la colonne ROLE_KEY donne sa clé (sans elle, le RowID de la ligne), la colonne ROLE_PARENT nomme la clé du nœud qui le contient (vide, inconnue, ou une boucle : en haut) — avec une colonne ROLE_KEY, une valeur de parent nomme une clé, jamais un RowID. Les autres rôles : le texte (ROLE_TEXT, montré comme texte, jamais comme balisage), l'image, la coche, le badge et l'ouverture au chargement. Une colonne joue un rôle quand elle s'appelle comme lui (key, parent, text…) ou quand of_map le dit. Chaque colonne est un champ (of_get_field) — les colonnes de la liste ne sont pas créées pour vous : of_add_column avec le nom de la colonne. Dates et nombres sont lus quels que soient les réglages régionaux, sous une seule forme : une date yyyy-mm-dd, une date-heure yyyy-mm-dd hh:mm:ss, un nombre au point sans zéro inutile (1234,50 devient 1234.5) — une colonne décimale se met en forme et se trie comme un nombre. Deux lignes de même clé : la seconde prend "clé~RowID". Ce que le chargement a dû corriger (lignes dont le parent n'est pas là, boucles cassées, clés en double, clés impossibles) est dit par of_get_last_error, le retour restant 0. of_reload_row relit une ligne changée par votre code et met son nœud à jour en place ; une ligne dont la clé ou le parent a changé déplace son nœud. Le nœud d'une ligne retiré par of_remove_node reste parti jusqu'au prochain of_from_datastore ; of_reload_row de sa ligne le ramène. Avec ib_write_back, un texte renommé est écrit dans la colonne ROLE_TEXT et un nœud qui change de parent l'écrit dans la colonne ROLE_PARENT (NULL en haut, quel que soit son type ; un déplacement parmi les mêmes frères n'écrit rien), avant l'événement ; un nœud de ligne ne va alors ni sous un nœud posé à la main, ni sous une ligne sans valeur de clé — sa colonne parent ne saurait pas le dire. Une valeur que le DataStore refuse, ou un DataStore détruit depuis le chargement (no DataStore is bound), remet le nœud en place et lève ue_write_back_failed. Sans ib_write_back, un glisser ne déplace que le nœud : sa ligne garde ce que dit le DataStore, et la relecture suivante des lignes (of_map, is_group_by, of_reload_row, un nouveau chargement) remet le nœud où sa ligne le dit — son ancienne poignée est libérée. L'Update reste à vous. La poignée d'un nœud lit le numéro de sa ligne (of_row). of_from_datastore lit aussi les lignes d'un DataWindow ou d'un DataWindowChild — celui que l'utilisateur voit à côté : l'arbre écrit alors dans celui-là. Avec ib_write_back, une coche de l'utilisateur s'écrit aussi dans la colonne ROLE_CHECKED de chaque ligne qu'elle a changée — la cascade comprise, et les branches au-dessus dont l'état passe à coché ou décoché (une branche qui devient mixte garde sa valeur) —, épelée comme la colonne l'écrit déjà (1/0, Y/N, T/F, O/N, -1/0… ; une colonne qui ne montre que son non écrit le oui habituel : Y pour N, 1 pour 0 — O et -1 seulement si la colonne en a déjà un) ; une colonne dont les valeurs ne sont ni un oui ni un non est refusée, avec sa raison. Chaque valeur est jugée d'abord et l'écriture est tout ou rien : un refus rend les coches du geste et lève ue_write_back_failed. of_row_keys rend l'adresse du nœud d'une ligne du DataStore principal : retirez le nœud avant un DeleteRow. Tout write-back est tout ou rien — chaque valeur jugée avant qu'une seule ne s'écrive ; une date-heure garde son heure, une colonne time s'écrit, se lit et se groupe en hh:mm:ss. Un déplacement écrit par of_move_node est rejugé après ue_node_moving, et ce qui était écrit est remis si le nœud ne bouge pas. Avec ib_write_back, un nœud de ligne dont le DataStore n'a pas de colonne ROLE_TEXT ne se renomme pas. Un nouveau chargement ne libère que les poignées de ce qu'il remplace : celle d'un nœud posé à la main, une poignée inerte ou prise à une adresse pas encore créée restent valides ; of_from_datastore depuis un DataWindow vérifie que ses données se partagent (-5 avec la raison). Ce qu'une relecture des lignes a dû redresser se compte dans of_get_last_error — y compris les nœuds posés à la main remontés en tête parce que leur groupe n'existe plus (lifted=N) et les lots partis avec leur nœud (lots=N) ; of_map et is_group_by le disent pour toutes les sources.
// The departments : each row names its parent by its id
ids_depts.Retrieve()
uo_tree.of_map(/*role*/ u_pbt_treeview.ROLE_KEY, /*column*/ "dept_id")
uo_tree.of_map(/*role*/ u_pbt_treeview.ROLE_PARENT, /*column*/ "parent_id")
uo_tree.of_map(/*role*/ u_pbt_treeview.ROLE_TEXT, /*column*/ "dept_name")
uo_tree.of_from_datastore(/*ads*/ ids_depts)
// Two columns of the DataStore shown beside the tree
uo_tree.of_add_column(/*key*/ "head_count", /*title*/ "Staff")
uo_tree.of_add_column(/*key*/ "budget", /*title*/ "Budget")
uo_tree.of_column(/*key*/ "budget").is_format = "#,##0"
// A renamed or moved department is written into its row before the event
uo_tree.ib_write_back = true
uo_tree.ib_editable = true
uo_tree.ib_drag_drop = true
// event ue_node_moved of uo_tree : (string as_keys, string as_old_keys, long al_position)
// parent_id is already written in the row : save it
if ids_depts.Update() = 1 then commit using sqlca;
Un rôle se résout par DataStore : la colonne qu'of_map(ads, as_role, as_column) a donnée à ce DataStore, sinon celle d'of_map(as_role, as_column) quand ce DataStore l'a, sinon la colonne qui porte le nom du rôle. Un lot d'employés sous un arbre de départements n'a donc besoin d'aucune colonne des départements. Une table dont les racines portent 0 dans leur colonne parent (une colonne NOT NULL) le dit par is_root_parent_value = "0" ("0|-1" pour deux valeurs) : ces lignes sont en haut sans compter comme orphelines, et un nœud remonté en haut avec ib_write_back écrit 0 au lieu de NULL. Les colonnes ROLE_STATE_IMAGE et ROLE_OVERLAY_IMAGE donnent l'image d'état et l'image superposée d'un nœud, lues comme ROLE_IMAGE.
// event ue_children_needed of uo_tree : (string as_keys)
// Local variables
datastore lds_staff
n_pbt_utils lnv_utils
// The employees of the department that opens, in a DataStore of their own
lds_staff = create datastore
lds_staff.DataObject = "d_staff"
lds_staff.SetTransObject(SQLCA)
lds_staff.Retrieve(lnv_utils.of_leaf(/*keys*/ as_keys))
// THEIR key and THEIR text : the departments keep dept_id and dept_name
uo_tree.of_map(/*ads*/ lds_staff, /*role*/ u_pbt_treeview.ROLE_KEY, /*column*/ "emp_id")
uo_tree.of_map(/*ads*/ lds_staff, /*role*/ u_pbt_treeview.ROLE_TEXT, /*column*/ "emp_name")
uo_tree.of_from_datastore(/*ads*/ lds_staff, /*parent_keys*/ as_keys)
// Kept while its nodes are shown ; the window destroys them when it closes
ids_lots[UpperBound(ids_lots) + 1] = lds_staff
// The roots of the table carry 0 in parent_id (a NOT NULL column) : 0 names the top
uo_tree.is_root_parent_value = "0"
uo_tree.of_from_datastore(/*ads*/ ids_depts)
Un arbre groupé par colonnes #
Le style TreeView d'un DataWindow, sans DataWindow : is_group_by = "region|country|city" fait des lignes de of_from_datastore les feuilles de groupes bâtis sur les valeurs de ces colonnes, un niveau par colonne (ROLE_PARENT n'y joue aucun rôle, ROLE_KEY nomme les feuilles). La clé d'un groupe est sa valeur (/, | et % écrits %2F, %7C, %25), son texte la valeur écrite au format de la colonne de même clé, « (vide) » pour une valeur vide ; la poignée d'un nœud de groupe lit of_group_column() et of_group_value(). Posé après un chargement, il regroupe ; of_reload_row range une ligne dont une valeur a changé dans son nouveau groupe. of_set_level_image donne une image à tous les nœuds d'un niveau, of_expand_to_level ouvre l'arbre jusqu'à un niveau, et is_summary donne les totaux de chaque groupe. Avec ib_write_back, une feuille déposée sous un groupe du dernier niveau écrit toutes ses colonnes de groupe avant l'événement ; ailleurs, et pour un nœud de groupe, le déplacement est refusé. Le texte d'un groupe suit un format posé après le chargement, l'arrivée de sa colonne et la langue d'affichage ; une valeur qui commence par __ s'écrit %5F_ dans la clé ; of_group_value d'une date-heure vaut yyyy-mm-dd hh:mm:ss, d'une heure hh:mm:ss. Sans ib_write_back, une feuille glissée sous un autre groupe retourne dans le sien au regroupement suivant, puisque sa ligne n'a pas changé ; un nœud posé à la main sous un groupe qui disparaît remonte en tête.
// The sales, one row per sale, grouped by region, country and city : the customer is
// the text of each sale
uo_tree.is_group_by = "region|country|city"
uo_tree.of_map(/*role*/ u_pbt_treeview.ROLE_TEXT, /*column*/ "customer")
uo_tree.of_from_datastore(/*ads*/ ids_sales)
// The amount of each sale, and the total of each group
uo_tree.of_add_column(/*key*/ "amount", /*title*/ "Amount")
uo_tree.of_column(/*key*/ "amount").is_format = "#,##0.00"
uo_tree.of_column(/*key*/ "amount").is_summary = u_pbt_treeview.SUMMARY_SUM
// A globe before every region ; only the regions show at first
uo_tree.of_set_level_image(/*level*/ 1, /*image*/ "mono:img\packimages.dll:svg/ribbon/globe", /*expanded_image*/ "")
uo_tree.of_expand_to_level(/*level*/ 1)
Propriétés #
| Propriété | Type | Défaut | Rôle | ||
|---|---|---|---|---|---|
is_selection_mode | string | SELECT_SINGLE | Comment l'utilisateur sélectionne : SELECT_SINGLE (un nœud), SELECT_MULTIPLE (Ctrl et Maj, comme l'Explorateur) ou SELECT_NONE (le clavier ne déplace qu'un focus, rien n'est sélectionné). Une autre valeur est refusée : l'ancienne reste, of_get_last_error dit pourquoi | ||
ib_checkboxes | boolean | false | Une case à cocher avant chaque nœud | ||
ib_check_cascade | boolean | true | Une coche de l'utilisateur sur un nœud coche son sous-arbre, sauf un nœud grisé et son sous-arbre ; une coche du code coche tout. Un parent est l'état des enfants que l'arbre peut dessiner : coché quand ils le sont tous, mixte (CHECK_MIXED) quand une partie l'est. false : chaque nœud garde sa propre coche ; une coche de l'utilisateur ne touche jamais un nœud au-delà du plafond démo, ni, avec ib_write_back, un nœud masqué | ||
ib_editable | boolean | false | L'utilisateur renomme un nœud : F2, ou un clic sur le nœud déjà sélectionné. Entrée garde, Échap rend (ue_node_edited) ; un texte vidé est refusé | ||
ib_drag_drop | boolean | false | L'utilisateur glisse un nœud avant, après ou dans un autre (ue_node_moved) ; jamais dans son propre sous-arbre ; un dépôt sur le quart bas d'une branche ouverte en fait le premier enfant ; la fenêtre qui perd le focus pendant un glisser l'annule | ||
ib_veto_changes | boolean | false | Poser ue_node_editing et ue_node_moving avant qu'un texte tapé soit gardé ou qu'un nœud bouge — au geste comme par of_move_node (désactivé par défaut, comme tout événement annulable) | ||
is_filter | string | "" | La recherche : seuls les nœuds dont le texte la contient se montrent, avec ceux qui les contiennent, ouverts, le texte trouvé surligné. "" montre tout. Le champ de la barre d'outils l'écrit aussi : une lecture la rend à l'instant ; un nœud sélectionné qu'elle cache sort de la sélection (ue_selection_changed) | ||
ib_toolbar | boolean | false | Une barre au-dessus de l'arbre : le champ de recherche, Tout déplier, Tout replier | ||
ib_show_lines | boolean | false | Des traits fins relient chaque nœud à son parent | ||
ii_indent | integer | 18 | Le retrait d'un niveau, en pixels, de 8 à 64. Une autre valeur est refusée : l'ancienne reste, of_get_last_error dit pourquoi | ||
is_tree_title | string | "" | Le titre de la colonne de l'arbre d'une liste en arbre. Accepte le balisage riche | ||
ib_write_back | boolean | false | Avec un arbre nourri par of_from_datastore : un texte renommé est écrit dans la colonne ROLE_TEXT, un nœud qui change de parent l'écrit dans la colonne ROLE_PARENT (NULL en haut ; un déplacement parmi les mêmes frères n'écrit rien), avant l'événement. Un nœud de ligne ne va alors ni sous un nœud posé à la main, ni sous une ligne sans valeur de clé. Une valeur refusée, ou un DataStore détruit, remet le nœud en place et lève ue_write_back_failed. Sans lui, un glisser ne déplace que le nœud. L'Update reste à vous. Une coche de l'utilisateur s'écrit aussi dans la colonne ROLE_CHECKED de chaque ligne qu'elle change. Une coche écrit aussi les branches au-dessus dont l'état passe à coché ou décoché ; chaque valeur est jugée d'abord, tout ou rien ; sans colonne ROLE_TEXT, un nœud de ligne ne se renomme pas | ||
ib_enabled | boolean | true | false grise l'arbre : les nœuds restent affichés, plus rien ne répond à l'utilisateur et l'arbre quitte l'ordre de la touche Tab. Votre code change toujours tout ; il ne prend plus le focus | ||
ib_veto_selection | boolean | false | Demander ue_selection_changing avant que la sélection change : un choix de l'utilisateur, of_select_node, of_clear_selection (désactivé par défaut, comme tout événement annulable) | ||
ib_veto_toggle | boolean | false | Demander ue_node_toggling avant qu'un nœud s'ouvre ou se ferme, d'un geste ou du code | ||
ib_single_expand | boolean | false | Une seule branche ouverte sous chaque parent : ouvrir un nœud ferme ses sœurs ouvertes (ue_node_toggled pour chacune, sans rien demander) ; le poser ne ferme rien sur le moment ; of_expand_all et of_expand_to_level l'ignorent | ||
ib_parents_first | boolean | false | À chaque niveau, les nœuds qui ont (ou promettent) des enfants avant les feuilles — les dossiers avant les fichiers —, quel que soit le tri ; un dépôt n'y va alors que dedans | ||
ib_summary_filtered | boolean | false | Les totaux des branches (is_summary d'une colonne) ne comptent que ce que la recherche montre ; false : tout nœud que l'arbre peut dessiner | ||
is_group_by | string | "" | Un arbre groupé par colonnes, comme le style TreeView d'un DataWindow : `"region | country" fait un niveau de groupes par colonne, les lignes de of_from_datastore étant les feuilles sous le dernier. Posé après un chargement, il regroupe ; une colonne absente du DataStore est ignorée. Ce qu'un regroupement a dû redresser, pour toutes les sources, se lit dans of_get_last_error` | |
is_root_parent_value | string | "" | Les valeurs de parent qui nomment le haut de l'arbre, jointes par ` | ("0", "0 | -1") : une telle ligne est en haut sans compter comme orpheline, et un nœud remonté en haut avec ib_write_back écrit la première au lieu de NULL. ""` : seul un parent vide (NULL) nomme le haut |
ib_filter_accents | boolean | false | false : la recherche (is_filter) ignore les accents, comme le tri ; true : ils comptent | ||
ib_auto_tooltip | boolean | true | Un libellé coupé par la largeur montre son texte entier en info-bulle — jamais par-dessus une info-bulle que votre application a donnée au nœud | ||
is_export_scope | string | EXPORT_ALL | Ce qu'écrivent of_export_csv et of_export_xlsx : EXPORT_ALL tous les nœuds, branches fermées comprises, EXPORT_SHOWN les lignes à l'écran. Un nœud masqué n'est jamais écrit ; une autre valeur est refusée | ||
ib_allow_drop | boolean | false | Accepter les fichiers déposés depuis l'Explorateur sur un nœud : le nœud sous le curseur s'allume, ue_drop_files le nomme avec les chemins complets | ||
is_theme_style | string | "" | Style visuel du composant (constantes THEME_STYLE_*) ; vide = celui de l'application, suivi à chaque changement | ||
is_theme_mode | string | "" | Variante claire ou sombre (constantes THEME_MODE_*) ; vide = celle de l'application, suivie à chaque changement | ||
il_theme_accent | long | -1 | Couleur d'accent de ce composant (-1 = l'accent de l'application, ou celui du thème) | ||
is_tooltip | string | "" | Info-bulle simple affichée au survol du composant | ||
is_super_tooltip_title | string | "" | Titre de l'info-bulle enrichie (prend le pas sur is_tooltip) | ||
is_super_tooltip_text | string | "" | Texte de l'info-bulle enrichie (balisage riche accepté) | ||
is_super_tooltip_image | string | "" | Image de l'info-bulle enrichie |
Propriétés d'un nœud — n_pbt_treeview_node #
Sa poignée, par of_node(adresse). Une lecture demande à l'arbre ce qu'est le nœud maintenant. Son of_count() compte ses enfants, son of_keys_at(n) rend l'adresse de son n-ième enfant (à partir de 1), son of_has(clé) dit s'il a cet enfant, son of_key() rend sa clé.
| Propriété | Type | Défaut | Rôle |
|---|---|---|---|
is_text | string | "" | Le texte du nœud. Accepte le balisage riche. Vide, le nœud montre sa clé |
is_image | string | "" | L'image avant le texte : un fichier du poste, une ressource "fichier.dll:nom", un glyphe "mono:…" / "tint:…" dessiné au thème, une adresse https://. http:// est refusé (ue_image_failed, REASON_INSECURE) |
is_expanded_image | string | "" | L'image quand le nœud est ouvert (un dossier ouvert) ; "" garde is_image |
is_state_image | string | "" | L'image d'état du nœud, avant son image : un drapeau, un statut — la StatePicture d'un TreeView PowerBuilder. Un clic dessus lève ue_state_clicked et ne sélectionne pas le nœud ; mêmes sources et refus qu'is_image |
is_overlay_image | string | "" | Une petite image dessinée par-dessus le coin bas de l'image du nœud (une flèche de raccourci, un cadenas) — l'OverlayPicture d'un TreeView PowerBuilder |
is_selected_image | string | "" | L'image du nœud quand il est sélectionné — la SelectedPicture d'un TreeView PowerBuilder. "" garde is_image |
ib_expanded | boolean | false | true ouvre le nœud (ses enfants se montrent), false le ferme ; ue_node_toggled suit, comme pour un clic sur son chevron. Un nœud sans enfant se lit false ; ouvrir un nœud qui ne fait que promettre des enfants les demande (ue_children_needed) ; ils arrivent avec la réponse, après le retour de cette ligne ; avec ib_veto_toggle, ue_node_toggling est posé d'abord ; refusé, rien n'est envoyé et of_get_last_error le dit |
ib_has_children | boolean | false | Une promesse d'enfants : le chevron s'affiche alors que rien n'est encore ajouté. Ouvrir le nœud lève ue_children_needed, où votre application les ajoute. La promesse tient jusqu'à la réponse, même si un nœud y a été ajouté ou déposé ; la reposer à true fait redemander à la prochaine ouverture |
ib_checked | boolean | false | La coche du nœud (ib_checkboxes de l'arbre). Avec ib_check_cascade, l'écrire coche tout le sous-arbre (grisés compris), et elle se lit true quand ses enfants que l'arbre peut dessiner sont tous cochés (of_check_state dit mixte) ; les enfants reçus sous une feuille cochée prennent sa coche. Une coche écrite par votre code ne lève rien |
ib_enabled | boolean | true | false grise le nœud : l'utilisateur ne peut ni le sélectionner, ni le cocher, ni le renommer, ni le glisser, rien ne se dépose sur sa ligne, le clavier le saute, et une coche de l'utilisateur sur un parent le laisse tel quel avec son sous-arbre. Votre code le sélectionne et le coche toujours |
ib_visible | boolean | true | false retire de l'écran le nœud et son sous-arbre ; il garde son adresse |
is_badge | string | "" | Un petit badge après le texte (balisage accepté) : un nombre d'éléments non lus ; "" aucun |
ib_read_only | boolean | false | true : l'utilisateur ne peut ni le renommer ni le glisser (il reste une cible), et Suppr l'exclut ; votre code le peut toujours |
ib_drop_target | boolean | true | false : rien n'est déposé dedans, ni un nœud glissé ni un fichier de l'Explorateur ; avant ou après lui reste permis |
ib_show_checkbox | boolean | true | false : pas de case sur ce nœud (ib_checkboxes) — il ne compte pas pour son parent, n'est pas dans of_checked_keys, et la cascade le traverse vers ses enfants |
of_keys ( ) → string | — | — | Rend l'adresse du nœud : ses clés jointes par / |
of_level ( ) → long | — | — | Rend sa profondeur : 1 pour un nœud du haut, 2 pour un nœud dedans… 0 quand l'arbre ne le contient pas |
of_position ( ) → long | — | — | Rend sa place parmi les enfants de son parent, à partir de 1, dans l'ordre d'ajout (un tri ne change que l'ordre affiché) ; 0 quand l'arbre ne le contient pas |
of_parent_keys ( ) → string | — | — | Rend l'adresse de son parent ; "" pour un nœud du haut |
of_check_state ( ) → string | — | — | Rend l'état de sa case : CHECK_ON, CHECK_OFF ou CHECK_MIXED (une partie de ses enfants cochée, avec ib_check_cascade) ; "" quand l'arbre ne le contient pas |
of_row ( ) → long | — | — | Rend le numéro de ligne d'aujourd'hui, dans le DataStore de of_from_datastore, de la ligne d'où vient le nœud — quelle que soit la clé qu'il a dû prendre, et après un tri ou un filtre du DataStore. 0 pour un nœud ajouté à la main ou dont la ligne est partie ; un nœud de lot rend sa ligne dans son DataStore, un nœud de groupe 0 ; 0 aussi quand le DataStore de son lot a été rechargé pour un autre nœud |
of_group_column ( ) → string | — | — | Pour un nœud de groupe de is_group_by : la colonne sur laquelle son niveau groupe ("region") ; "" pour tout autre nœud |
of_group_value ( ) → string | — | — | Pour un nœud de groupe : la valeur de sa colonne qu'il représente, telle que les lignes la tiennent (une date yyyy-mm-dd, un nombre au point, "" pour le groupe des valeurs vides) ; "" pour tout autre nœud ; une date-heure yyyy-mm-dd hh:mm:ss, une heure hh:mm:ss |
is_tooltip | string | "" | Info-bulle simple affichée au survol de l'item |
is_super_tooltip_title | string | "" | Titre de l'info-bulle enrichie de l'item (prend le pas sur is_tooltip) |
is_super_tooltip_text | string | "" | Texte de l'info-bulle enrichie de l'item (balisage riche accepté) |
is_super_tooltip_image | string | "" | Image de l'info-bulle enrichie de l'item |
il_accent | long | -1 | Accent du nœud : sa sélection (tant que l'arbre a le focus) et sa case cochée le prennent ; le badge garde la couleur du thème (-1 = celui du composant) |
il_back_color | long | -1 | Fond de la ligne du nœud, en RGB(r,v,b) (-1 = ce que donne le thème). Une ligne sélectionnée prend les couleurs de la sélection |
il_text_color | long | -1 | Couleur du texte de la ligne du nœud (-1 = ce que donne le thème) |
il_back_color_hover | long | -1 | Fond de la ligne du nœud sous le pointeur (-1 = ce que donne le thème) |
il_text_color_hover | long | -1 | Couleur du texte de la ligne du nœud sous le pointeur (-1 = ce que donne le thème) |
Propriétés d'une colonne — n_pbt_treeview_column #
Sa poignée, par of_column(clé). Une valeur écrite par votre code est muette, comme SetItem — sauf sa disposition : ii_width, ii_index et ib_visible écrits par votre code lèvent ue_layout_changed quand la disposition change, comme un geste. Une lecture rend ce que l'utilisateur a pu changer (largeur, place).
| Propriété | Type | Défaut | Rôle |
|---|---|---|---|
is_title | string | "" | Le titre dans l'en-tête (balisage accepté) ; "" montre la clé |
ii_width | integer | 0 | La largeur en pixels : 0 est automatique (aussi large que le titre et les valeurs dessinées), sinon de 40 à 2000. L'utilisateur glisse le bord de l'en-tête : une lecture la rend à l'instant |
is_align | string | ALIGN_START | Où se tiennent les valeurs dans leurs cellules : ALIGN_START, ALIGN_CENTER, ALIGN_END — le début et la fin de la lecture, qui suivent une application de droite à gauche. Une autre valeur est refusée |
is_format | string | "" | Comment une valeur est écrite : un masque numérique pour un nombre ("#,##0.00", séparateurs de la langue d'affichage), les jetons de date d'un format d'affichage PowerBuilder pour une date ou une date-heure ("dd/mm/yyyy", "d mmm yyyy hh:mm" — mm après une heure, ce sont les minutes —, AM/PM, s, f, littéraux "…", [shortdate], [longdate], [time]), les mêmes que le datagrid ; "" écrit la valeur telle quelle |
ib_visible | boolean | true | false retire la colonne de l'écran ; elle garde sa place et sa clé |
ii_index | integer | — | Sa place parmi toutes les colonnes, à partir de 1 : l'écrire déplace la colonne. L'utilisateur glisse aussi un en-tête : une lecture la rend à l'instant |
ib_sortable | boolean | true | Un clic sur son en-tête trie l'arbre par cette colonne. L'en-tête de la colonne de l'arbre (is_tree_title) trie toujours, par le texte des nœuds |
is_summary | string | "" | Le total que chaque branche montre dans cette colonne : SUMMARY_SUM, SUMMARY_AVG, SUMMARY_MIN, SUMMARY_MAX, SUMMARY_COUNT (les valeurs non vides), de ce que ses enfants apportent jusqu'aux feuilles, en gras ; SUMMARY_NONE ("") : aucun. of_get_field lit le total, un tri l'utilise ; SUMMARY_COUNT s'écrit en nombre brut, jamais par is_format ; SUMMARY_MIN et SUMMARY_MAX comparent aussi des dates |
ib_summary_over_value | boolean | false | false : une branche qui a sa propre valeur dans la colonne la garde (et la fait remonter) ; true : le total prend sa place |
il_accent | long | -1 | Accent de l'en-tête : sa flèche de tri et l'anneau du clavier le prennent (-1 = celui du composant) |
il_back_color | long | -1 | Fond de l'en-tête, en RGB(r,v,b) (-1 = ce que donne le thème) |
il_text_color | long | -1 | Couleur du texte de l'en-tête (-1 = ce que donne le thème) |
il_back_color_hover | long | -1 | Fond de l'en-tête sous le pointeur (-1 = ce que donne le thème) |
il_text_color_hover | long | -1 | Couleur du texte de l'en-tête sous le pointeur (-1 = ce que donne le thème) |
is_tooltip | string | "" | Info-bulle simple au survol de l'en-tête de la colonne |
is_super_tooltip_title | string | "" | Titre de l'info-bulle enrichie de l'en-tête (prend le pas sur is_tooltip) |
is_super_tooltip_text | string | "" | Texte de l'info-bulle enrichie de l'en-tête (balisage riche accepté) |
is_super_tooltip_image | string | "" | Image de l'info-bulle enrichie de l'en-tête |
Constantes #
Elles vivent sur u_pbt_treeview : u_pbt_treeview.CHECK_MIXED.
| Constante | Valeur | Sens |
|---|---|---|
SUMMARY_NONE | "" | Pas de total — le défaut |
SUMMARY_SUM | "sum" | La somme |
SUMMARY_AVG | "avg" | La moyenne des feuilles |
SUMMARY_MIN | "min" | La plus petite valeur |
SUMMARY_MAX | "max" | La plus grande valeur |
SUMMARY_COUNT | "count" | Le nombre de valeurs non vides |
SELECT_SINGLE | "single" | Un nœud sélectionné à la fois — le défaut |
SELECT_MULTIPLE | "multiple" | Plusieurs, avec Ctrl et Maj |
SELECT_NONE | "none" | Aucun : seul un focus se déplace |
SORT_ASC | "asc" | Croissant |
SORT_DESC | "desc" | Décroissant |
SORT_NONE | "none" | Pas de tri : l'ordre d'ajout |
CHECK_ON | "on" | Coché (avec la cascade : tout le sous-arbre) |
CHECK_OFF | "off" | Non coché |
CHECK_MIXED | "mixed" | Une partie des enfants cochée |
ALIGN_START | "start" | Au début de la lecture — le défaut |
ALIGN_CENTER | "center" | Au centre |
ALIGN_END | "end" | À la fin de la lecture (les nombres) |
ROLE_KEY | "key" | La clé du nœud (un identifiant) ; sans elle, le RowID |
ROLE_PARENT | "parent" | La clé du nœud qui le contient ; avec une colonne ROLE_KEY, jamais un RowID |
ROLE_TEXT | "text" | Son texte (montré comme texte) |
ROLE_IMAGE | "image" | Son image |
ROLE_CHECKED | "checked" | Coché quand la valeur dit oui (1, -1, true, y, yes, on, t, o ; non : 0, false, n, no, off, f, casse ignorée) ; réécrite comme la colonne l'écrit déjà ; sous la cascade, lu pour une feuille seulement : un parent y est l'état de ses enfants |
ROLE_BADGE | "badge" | Son badge |
ROLE_EXPANDED | "expanded" | Ouvert au chargement quand la valeur dit oui |
ROLE_HAS_CHILDREN | "has_children" | La ligne promet des enfants quand la valeur dit oui : un chevron, et ue_children_needed à l'ouverture du nœud ; lu une fois, à la création du nœud |
ROLE_STATE_IMAGE | "state_image" | Son image d'état |
ROLE_OVERLAY_IMAGE | "overlay_image" | Son image superposée |
EXPORT_ALL | "all" | Export : tous les nœuds, branches fermées comprises — le défaut |
EXPORT_SHOWN | "shown" | Export : les lignes à l'écran |
REASON_INSECURE | "insecure" | Une adresse http:// |
REASON_NOT_FOUND | "notfound" | Un fichier introuvable |
REASON_UNC | "unc" | Un chemin réseau venu d'une colonne de DataStore, refusé avant toute requête |
Méthodes #
| Méthode | Rôle | |
|---|---|---|
of_add_node (string as_keys, string as_text) | Ajoute un nœud à son adresse, à la fin de son parent : "europe" en haut, "europe/france" dans "europe" (ajouté d'abord). as_text accepte le balisage ("" montre la clé). Rend 0 une fois ajouté, -5 pour une adresse au niveau vide, une clé contenant ` | ou commençant par __, une adresse déjà prise, un parent inconnu (of_get_last_error dit lequel), -2` quand le composant n'est pas créé |
of_add_node (string as_keys, string as_text, string as_image) | La même chose avec son image (is_image de la poignée). Rend 0 une fois ajouté, -5 comme ci-dessus, -2 quand le composant n'est pas créé | |
of_insert_node (string as_keys, string as_text, string as_image, long al_position) | Ajoute un nœud à une place parmi les enfants de son parent, à partir de 1 (au-delà de la dernière : à la fin). Rend 0 une fois ajouté, -5 comme of_add_node, -2 quand le composant n'est pas créé | |
of_remove_node (string as_keys) | Retire un nœud et tout ce qu'il contient (leurs poignées sont libérées). Retirer le nœud sélectionné fait passer la sélection à ce qui le contenait (ue_selection_changed). Le nœud d'une ligne de DataStore reste parti jusqu'au prochain of_from_datastore : ni of_map ni la relecture d'une autre ligne ne le ramènent, of_reload_row de sa ligne si. Rend 0 une fois retiré, -5 pour une adresse que l'arbre ne contient pas, -2 quand le composant n'est pas créé | |
of_move_node (string as_keys, string as_to_parent_keys, long al_position) | Déplace un nœud avec son sous-arbre sous un autre parent ("" = en haut), à une place à partir de 1 (au-delà de la dernière : à la fin) — ou à une autre place parmi ses frères. Son adresse change : les poignées prises à l'ancienne adresse sont libérées par cet appel, aussitôt ; une poignée prise ensuite à la nouvelle reste valable (un déplacement parmi les mêmes frères ne libère rien). Avec ib_veto_changes, ue_node_moving est posé d'abord, avec la place finale ; avec ib_write_back, un nœud de ligne qui change de parent l'écrit avant de bouger (un déplacement parmi les mêmes frères n'écrit rien). ue_node_moved suit, comme pour un glisser. Ce qu'il écrit est rejugé après ue_node_moving ; si le nœud ne bouge pas, ce qui était écrit est remis. Rend 0 (aussi quand il y est déjà : rien n'est demandé, écrit ni levé), -4 si l'application refuse ou si le DataStore refuse la valeur (ue_write_back_failed), -5 pour un nœud ou un parent inconnu, un déplacement dans son propre sous-arbre, une clé déjà prise sous le nouveau parent, avec ib_write_back un nœud de ligne sous un nœud posé à la main ou sous une ligne sans valeur de clé, un nœud de lot hors de son lot ou dont le DataStore a été rechargé pour un autre nœud, une feuille d'un arbre groupé ailleurs que sous un groupe du dernier niveau, un nœud de groupe, un nœud qui a bougé ou est parti pendant ue_node_moving, -2 quand le composant n'est pas créé | |
of_clear ( ) | Vide l'arbre : nœuds, poignées et lignes lues (le DataStore reste lié pour un nouveau of_from_datastore) ; les colonnes et les options restent. ue_selection_changed suit s'il y avait une sélection. Les colonnes gardent leurs couleurs et leurs info-bulles. Les images des niveaux (of_set_level_image) restent aussi. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé | |
of_node (string as_keys) | La poignée n_pbt_treeview_node d'un nœud, par son adresse (créée au premier accès) : son texte, son image, sa coche, ses états, ses couleurs et son info-bulle ; une adresse impossible (niveau vide, ` | , __`) rend une poignée inerte, qui ne lit et n'écrit rien |
of_edit_node (string as_keys) | Ouvre le texte d'un nœud en édition depuis votre code — l'EditLabel d'un TreeView PowerBuilder. Le nœud est d'abord sélectionné (en SELECT_NONE, seulement amené à la vue), puis le champ s'ouvre ; la fin est celle de l'utilisateur (Entrée : ue_node_editing, puis ue_node_edited ; Échap ou of_cancel_edit rend le texte). Marche avec ib_editable = false, sur un nœud en lecture seule ou grisé. Rend 0 une fois le champ ouvert, -5 pour un nœud que l'arbre ne tient pas ou ne peut pas dessiner, un arbre grisé, un nœud de groupe d'is_group_by ou une ligne dont le DataStore n'a pas de colonne ROLE_TEXT avec ib_write_back (of_get_last_error dit lequel), -4 quand ue_selection_changing (ou ue_node_toggling) a refusé, -2 quand le composant n'est pas créé | |
of_cancel_edit ( ) | Ferme le champ d'une édition en cours (ouverte par l'utilisateur ou par of_edit_node) et rend le texte, comme Échap : rien n'est levé. Rend 0 une fois appliqué (aucune édition en cours : 0, rien ne change), -2 quand le composant n'est pas créé | |
of_expand_all ( ) | Ouvre tous les nœuds qui ont des enfants (une branche seulement promise reste fermée : rien n'est demandé). ue_node_toggled suit pour chacun, puis ue_layout_changed une fois. Rend 0 une fois appliqué, -4 quand ue_node_toggling en a refusé, -2 quand le composant n'est pas créé | |
of_collapse_all ( ) | Ferme tous les nœuds. ue_node_toggled suit pour chacun de ceux qui étaient ouverts, puis ue_layout_changed une fois. Rend 0 une fois appliqué, -4 quand ue_node_toggling en a refusé, -2 quand le composant n'est pas créé | |
of_expand_all (string as_keys) | Ouvre un nœud et tout nœud sous lui qui a des enfants (l'ExpandAll(handle) de PowerBuilder) ; "" = tout l'arbre. Rend 0 une fois appliqué, -4 quand ue_node_toggling en a refusé, -5 pour un nœud que l'arbre ne contient pas, -2 quand le composant n'est pas créé | |
of_collapse_all (string as_keys) | Ferme un nœud et tout nœud sous lui ; "" = tout l'arbre. Rend 0 une fois appliqué, -4 quand ue_node_toggling en a refusé, -5 pour un nœud que l'arbre ne contient pas, -2 quand le composant n'est pas créé | |
of_expand_to_level (long al_level) | Montre l'arbre jusqu'à un niveau : les niveaux au-dessus de al_level s'ouvrent, ce niveau et les suivants se ferment (1 : seul le haut se voit). Une branche dont la promesse n'a pas répondu reste fermée. ue_node_toggled pour chaque nœud changé, puis ue_layout_changed. Rend 0 une fois appliqué, -4 quand ue_node_toggling en a refusé, -5 pour un niveau sous 1, -2 quand le composant n'est pas créé | |
of_set_level_image (integer ai_level, string as_image, string as_expanded_image) | L'image de tout nœud d'un niveau (1 = le haut) qui n'en a pas à lui — le SetLevelPictures de PowerBuilder, pratique pour un arbre groupé : as_image, et as_expanded_image pendant que le nœud est ouvert ("" garde as_image). Deux "" retirent les images du niveau. Rend 0 une fois posé, -5 pour un niveau sous 1, -2 quand le composant n'est pas créé | |
of_clear_children (string as_keys) | Retire les enfants d'un nœud (leurs poignées sont libérées ; un nœud de ligne reste parti jusqu'au prochain of_from_datastore) et garde le nœud, qui promet de nouveau : sa prochaine ouverture lève ue_children_needed — le « rafraîchir » d'un dossier. Ouvert, il se ferme (ue_node_toggled). Il ferme sans demander ue_node_toggling, et ue_layout_changed suit. Rend 0 une fois appliqué, -5 pour un nœud que l'arbre ne contient pas, -2 quand le composant n'est pas créé | |
of_scroll_to_node (string as_keys) | Montre un nœud : ce qui le contient s'ouvre (ue_node_toggled pour chacun, du plus haut au plus bas), puis l'arbre défile jusqu'à lui. La sélection ne change pas. Un nœud que l'arbre ne pourrait pas dessiner est refusé avant que rien ne s'ouvre. Rend 0 une fois appliqué, -5 pour un nœud que l'arbre ne contient pas ou ne dessine pas (masqué ou contenu par un masqué, au-delà du plafond démo, écarté par la recherche ; of_get_last_error dit lequel), -4 si ue_node_toggling refuse d'ouvrir un nœud qui le contient (ib_veto_toggle), -2 quand le composant n'est pas créé | |
of_select_node (string as_keys) | Sélectionne un nœud seul, comme un clic : ce qui le contient s'ouvre (une branche promise pose sa question), le focus va sur lui et il vient à l'écran ; ue_selection_changed suit (déjà sélectionné seul : rien n'est levé). Un nœud grisé se sélectionne aussi : le grisé arrête l'utilisateur, pas votre code. Le nœud est jugé d'abord : un arbre ouvre pour sélectionner, comme le TreeView de Windows, mais rien ne s'ouvre pour un nœud refusé. Avec les deux vétos, les ouvertures sont demandées d'abord (ue_node_toggling), puis la sélection (ue_selection_changing). Rend 0 une fois sélectionné, -5 pour un nœud que l'arbre ne contient pas ou ne dessine pas (masqué ou contenu par un masqué, au-delà du plafond démo, écarté par la recherche ; of_get_last_error dit lequel), ou quand is_selection_mode vaut SELECT_NONE, -4 si ue_selection_changing refuse la sélection (ib_veto_selection) ou ue_node_toggling un nœud à ouvrir (ib_veto_toggle), -2 quand le composant n'est pas créé | |
of_select_nodes (string as_keys_json) | Sélectionne plusieurs nœuds d'un coup — le pendant d'of_selected_keys : as_keys_json est un tableau JSON d'adresses, dans n'importe quel ordre (["europe/france","asia"], une adresse en double compte une fois). Chaque nœud est jugé d'abord (là, et dessinable une fois ouvert ce qui le contient) ; puis ce qui les contient s'ouvre, le focus et l'ancre vont à la dernière adresse nommée, et ue_selection_changed suit une fois. Avec ib_veto_toggle, ue_node_toggling est demandé pour chaque nœud qu'il ouvre, puis avec ib_veto_selection ue_selection_changing une fois pour toute la sélection. "[]" ne laisse rien sélectionné ; en SELECT_SINGLE, une adresse au plus. Rend 0 une fois sélectionnés (aussi quand cette sélection est déjà là : rien n'est levé), -4 refusé, -5 pour un texte qui n'est pas un tableau JSON d'adresses, une adresse que l'arbre ne contient pas ou ne dessine pas (of_get_last_error dit laquelle), plus d'une adresse en SELECT_SINGLE, ou SELECT_NONE, -2 quand le composant n'est pas créé | |
of_clear_selection ( ) | Ne laisse aucun nœud sélectionné : ue_selection_changed("[]") suit (rien de sélectionné : rien n'est levé). Rend 0 une fois appliqué, -4 si ue_selection_changing refuse, -2 quand le composant n'est pas créé | |
of_selected_key ( ) | L'adresse du nœud sélectionné (celui qui a le focus quand plusieurs le sont) ; "" sinon. Lu en direct | |
of_selected_keys ( ) | Les adresses de tous les nœuds sélectionnés, en tableau JSON dans l'ordre de l'arbre : ["europe/france","asia"] ; "[]" si aucun. Lu en direct ; se lit avec n_pbt_json | |
of_checked_keys ( ) | Les adresses de tous les nœuds cochés, en tableau JSON dans l'ordre de l'arbre. Avec ib_check_cascade, un nœud dont tout le sous-arbre est coché en fait partie, un nœud mixte non. Lu en direct | |
of_check_all (boolean ab_checked) | Coche (ou décoche) tous les nœuds d'un coup. Une coche écrite par le code est une valeur : rien n'est levé. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé | |
of_sort (string as_column, string as_dir) | Trie les nœuds affichés, à chaque niveau : par une colonne (sa clé) ou par le texte des nœuds (as_column = ""). as_dir : SORT_ASC, SORT_DESC ou SORT_NONE (l'ordre d'ajout). L'ordre du modèle (of_keys_at, of_position) ne change pas. ue_sort_changed puis ue_layout_changed suivent, comme pour un clic sur un en-tête. as_column peut aussi nommer un champ qu'aucune colonne ne montre ; une colonne résumée trie sur ses totaux, et avec ib_parents_first les branches restent avant les feuilles. as_column "text" est le texte des nœuds, comme "". Rend 0 une fois appliqué (aussi quand le tri est déjà celui-là : rien n'est levé), -5 pour un nom qui n'en est pas un (lettres, chiffres et _) ou un sens inconnu, -2 quand le composant n'est pas créé | |
of_sort (string as_sort) | Trie sur plusieurs clés, dans leur ordre : la première décide, les suivantes départagent. as_sort s'écrit comme le lit le SetSort d'un DataWindow — "type A, text D" (asc et desc aussi, sans direction = croissant, text = le texte des nœuds, tout autre nom une colonne ou un champ) ; "" retire le tri. ue_sort_changed puis ue_layout_changed suivent. Plusieurs blancs entre une colonne et son sens sont acceptés, comme par SetSort. Rend 0 une fois trié (aussi quand c'est déjà ce tri : rien n'est levé), -5 pour un nom qui n'en est pas un, une autre direction ou une clé nommée deux fois, -2 quand le composant n'est pas créé | |
of_find_node (string as_field, string as_value, string as_after_keys) | L'adresse du premier nœud dont le champ vaut exactement as_value (la casse compte) : as_field "" = le texte du nœud, tout autre nom un champ (le vôtre, une colonne du DataStore, le total d'une colonne résumée). Dans l'ordre que l'arbre montre, branches fermées et nœuds écartés par la recherche compris, jamais un nœud masqué ; as_after_keys "" part du premier, sinon après ce nœud : redonnez l'adresse trouvée pour le suivant. "" quand il n'y en a pas (of_get_last_error dit pourquoi quand les arguments sont refusés). Il part après la place d'as_after_keys dans l'ordre affiché — un nœud masqué aussi ; un as_after_keys inconnu, ou un appel pendant une attente, rend "" et of_get_last_error dit pourquoi (cette lecture le vide d'abord). of_find_nodes les rend toutes d'un coup | |
of_find_nodes (string as_field, string as_value) | Tous les nœuds dont le champ vaut exactement as_value (la casse compte), en une passe : leurs adresses en tableau JSON, dans l'ordre que l'arbre affiche (["europe/france","asia"]) ; "[]" s'il n'y en a pas. as_field "" est le texte du nœud, tout autre nom un champ. Les branches fermées et les nœuds que la recherche écarte sont parcourus, jamais un nœud masqué (ni, en mode démo, un nœud au-delà du plafond). "[]" avec of_get_last_error quand le nom de champ n'en est pas un ou pendant une attente. Lisez-le avec n_pbt_json | |
of_search_next ( ) | Sélectionne le nœud suivant que la recherche a trouvé (is_filter), après le nœud du focus, en boucle ; F3 fait de même. Comme of_select_node : ue_selection_changed suit, et avec ib_veto_selection ue_selection_changing est posé d'abord. En SELECT_NONE, il y déplace le focus et rend 0 ; pendant une attente, il rend -5 et of_get_last_error dit pourquoi. Rend 0 une fois sélectionné, -4 refusé, -5 sans recherche ou sans correspondance, -2 quand le composant n'est pas créé | |
of_search_prev ( ) | Sélectionne le nœud précédent que la recherche a trouvé, avant le nœud du focus, en boucle ; Maj+F3 fait de même. En SELECT_NONE, il y déplace le focus et rend 0 ; pendant une attente, il rend -5 et of_get_last_error dit pourquoi. Rend 0 une fois sélectionné, -4 refusé, -5 sans recherche ou sans correspondance, -2 quand le composant n'est pas créé | |
of_match_count ( ) | Rend combien de nœuds la recherche (is_filter) a trouvés, lu à l'instant ; 0 sans recherche | |
of_add_column (string as_key, string as_title) | Ajoute une colonne à la fin : l'arbre devient une liste en arbre, la première colonne porte l'arbre, celle-ci montre le champ de même clé de chaque nœud (of_set_field, ou la colonne du DataStore). Sa largeur est automatique. La clé text est refusée (-5) : elle nomme le texte des nœuds. Rend 0 une fois ajoutée, -5 pour une clé qui ne peut pas en être une (vide, contenant / ou ` | , commençant par __) ou une colonne déjà là, -2` quand le composant n'est pas créé |
of_add_column (string as_key, string as_title, integer ai_width) | La même chose avec une largeur en pixels (0 = automatique ; 40 à 2000). Rend 0 une fois ajoutée, -5 comme ci-dessus, -2 quand le composant n'est pas créé | |
of_remove_column (string as_key) | Retire une colonne (sa poignée est libérée) ; la dernière partie, la liste redevient un arbre. Retirer la colonne triée lève ue_sort_changed avec la clé suivante du tri — SORT_NONE quand c'était la seule —, puis ue_layout_changed. Rend 0 une fois retirée, -5 pour une colonne que la liste ne contient pas, -2 quand le composant n'est pas créé | |
of_clear_columns ( ) | Retire toutes les colonnes (leurs poignées sont libérées) : la liste redevient un arbre. Retirer la colonne triée lève ue_sort_changed avec la clé suivante du tri — SORT_NONE quand c'était la seule —, puis ue_layout_changed. Rend 0 une fois appliqué, -2 quand le composant n'est pas créé | |
of_column (string as_key) | La poignée n_pbt_treeview_column d'une colonne (créée au premier accès) : son titre, sa largeur, son alignement, son format, sa visibilité, sa place et si un clic sur son en-tête trie | |
of_set_field (string as_keys, string as_field, string as_value) | Donne à un nœud un champ à vous : of_set_field("europe/france", "population", "68000000") ; la colonne de clé population le montre. Un nœud d'un DataStore a déjà chaque colonne comme champ ; un champ à vous du même nom passe devant. Un nom de champ : lettres, chiffres et _, sans chiffre au début. Rend 0 une fois posé, -5 pour un nœud inconnu ou un nom qui n'en est pas un, -2 quand le composant n'est pas créé | |
of_get_field (string as_keys, string as_field) | Lit un champ d'un nœud, en direct : un des vôtres (of_set_field), une colonne du DataStore d'où il vient, ou un champ intégré (key, keys, text, badge, level, position, count, image). "" quand il n'en a pas ; pour une colonne résumée (is_summary), le total brut de la branche, un nombre au point ; le champ intégré count compte les enfants que l'arbre peut dessiner | |
of_from_datastore (datastore ads) | Nourrit l'arbre depuis un DataStore : une ligne = un nœud (voir plus haut). Les nœuds d'un chargement précédent partent (leurs poignées sont libérées) ; les nœuds ajoutés à la main en haut restent, leurs poignées aussi. Deux lignes de même clé : la seconde prend "clé~RowID" ; une clé impossible (contenant / ou ` | , ou commençant par __) : le RowID — ses enfants la retrouvent par sa valeur. Avec une colonne ROLE_KEY, une valeur de parent nomme une clé, jamais un RowID. Dates et nombres sont lus quels que soient les réglages régionaux (date yyyy-mm-dd, hh:mm:ss, nombre au point). Ce que le chargement a dû corriger (parents absents, boucles, clés en double ou impossibles) est dit par of_get_last_error, le retour restant 0. Avec is_group_by, les lignes sont les feuilles de groupes (ROLE_PARENT n'y joue aucun rôle). Un nouveau chargement emporte les lots pendus sous ses lignes et garde ceux pendus sous un nœud posé à la main. Un nouveau chargement ne libère que les poignées de ce qu'il remplace (un nœud posé à la main, une poignée inerte, une adresse pas encore créée gardent la leur) ; un nœud de ligne déplacé sans ib_write_back revient à la place que dit sa ligne. Le rapport d'of_get_last_error compte aussi les nœuds posés à la main remontés en tête (lifted=N) et les lots partis avec leur nœud (lots=N). Rend 0 une fois chargé, -5 quand le DataStore n'est pas valide, n'a aucune colonne ou n'a pas une colonne nommée par of_map (of_get_last_error la nomme), -2` quand le composant n'est pas créé |
of_from_datastore (datawindow adw) | La même chose depuis les lignes d'un DataWindow : l'arbre écrit dans ce DataWindow (ib_write_back), celui que l'utilisateur voit à côté. Ses données sont partagées avec un DataStore de passage : un DataWindow qui ne peut pas les partager est refusé (-5, avec la raison). Rend 0 une fois chargé, -5 comme ci-dessus, -2 quand le composant n'est pas créé | |
of_from_datastore (datawindowchild adwc) | La même chose depuis les lignes d'un DataWindowChild (une liste déroulante DataWindow, un rapport imbriqué) : l'arbre écrit dans celui-ci. Rend 0 une fois chargé, -5 comme ci-dessus, -2 quand le composant n'est pas créé | |
of_from_datastore (datastore ads, string as_parent_keys) | Un lot : les lignes d'un DataStore deviennent les enfants du nœud as_parent_keys, le reste de l'arbre ne bouge pas — ce que fait ue_children_needed en un seul appel. Un rôle se résout pour chaque DataStore : la colonne d'of_map(ads, …) pour celui-ci, sinon celle d'of_map quand il l'a, sinon la colonne qui porte le nom du rôle ; ROLE_PARENT nomme une ligne du même lot (vide ou inconnu : le nœud lui-même). Le même DataStore redonné sous le même nœud remplace son lot (ses poignées sont libérées), un autre ajoute le sien ; of_row d'un nœud du lot est sa ligne dans ce DataStore, et ib_write_back y écrit. Une clé déjà prise sous le nœud prend "clé~RowID". Un DataStore par lot : rechargé pour un autre nœud (Reset, Retrieve — PowerBuilder redonne les mêmes RowID), il emporte ses lignes vers le nouveau lot, et les nœuds du lot d'avant gardent ce qu'ils montrent sans ligne (of_row 0, un déplacement par le code -5, un write-back refusé par ue_write_back_failed ; le chargement compte stale=N). Pour rafraîchir un lot depuis un autre objet DataStore, of_clear_children d'abord. Rend 0 une fois chargé, -5 quand le DataStore n'est pas valide, n'a aucune colonne, n'a pas une colonne nommée pour lui par of_map(ads, …), ou que as_parent_keys est vide (le haut de l'arbre, c'est of_from_datastore(ads)) ou n'est pas un nœud de l'arbre, -2 quand le composant n'est pas créé | |
of_from_datastore (datawindow adw, string as_parent_keys) | Un lot depuis les lignes d'un DataWindow (voir ci-dessus). Rend 0 une fois chargé, -5 comme ci-dessus, -2 quand le composant n'est pas créé | |
of_from_datastore (datawindowchild adwc, string as_parent_keys) | Un lot depuis les lignes d'un DataWindowChild. Rend 0 une fois chargé, -5 comme ci-dessus, -2 quand le composant n'est pas créé | |
of_row_keys (long al_row) | L'adresse du nœud d'une ligne du DataStore de of_from_datastore (le principal, pas un lot), par son numéro de ligne d'aujourd'hui : retirez le nœud (of_remove_node) avant le DeleteRow. "" quand la ligne n'a pas de nœud (retiré, jamais chargé, pas de telle ligne). "" aussi une fois le DataStore principal redonné comme lot, jusqu'au prochain chargement principal | |
of_map (string as_role, string as_column) | Donne un rôle (ROLE_KEY, ROLE_PARENT, ROLE_TEXT…) à une colonne du DataStore quand son nom ne le dit pas : of_map(ROLE_PARENT, "manager_id"). Le rôle vaut pour chaque DataStore qui a cette colonne : un lot lu d'un DataStore qui ne l'a pas prend la colonne qui porte le nom du rôle, et of_map(ads, …) donne à un DataStore ses propres rôles. Avant ou après of_from_datastore : après, les lignes sont relues, et ce qui a été posé sur les nœuds reste. "" comme colonne rend le rôle à la colonne qui porte son nom. Un nouveau ROLE_KEY ou ROLE_PARENT donne de nouvelles adresses : seules les poignées des nœuds dont l'adresse a changé sont libérées, les autres restent valables. Les rôles donnés restent pour les of_from_datastore suivants, même après of_clear ; seul of_reset les oublie. Sa relecture des lignes dit ce qu'elle a dû redresser, pour toutes les sources, dans of_get_last_error. Rend 0 une fois posé, -5 quand le rôle n'est pas une constante ROLE_ ou la colonne n'est pas une du DataStore du dernier of_from_datastore, -2 quand le composant n'est pas créé | |
of_map (datastore ads, string as_role, string as_column) | Donne un rôle à une colonne pour ce DataStore seulement : le lot des départements et celui des employés d'un même arbre nomment chacun leur clé et leur texte. Passe avant of_map(as_role, as_column) pour ce DataStore ; "" rend le rôle. Avant ou après of_from_datastore : après, les lignes sont relues, ce qui a été posé sur les nœuds reste. Rend 0 une fois posé, -5 quand le DataStore n'est pas valide, que le rôle n'est pas une constante ROLE_ ou que le DataStore n'a pas cette colonne, -2 quand le composant n'est pas créé | |
of_map (datawindow adw, string as_role, string as_column) | La même chose pour les lignes d'un DataWindow donné à of_from_datastore. Rend 0 une fois posé, -5 pour un argument refusé, -2 quand le composant n'est pas créé | |
of_map (datawindowchild adwc, string as_role, string as_column) | La même chose pour les lignes d'un DataWindowChild donné à of_from_datastore. Rend 0 une fois posé, -5 pour un argument refusé, -2 quand le composant n'est pas créé | |
of_reload_row (long al_row) | Renvoie une ligne du DataStore de of_from_datastore à l'arbre, lue maintenant : après que votre code l'a changée (SetItem, une fenêtre d'édition). al_row est le numéro de ligne d'aujourd'hui ; le nœud suit la ligne en place : ce qui a été posé dessus (ouverture, gris, visibilité, champs, couleurs) reste, rien n'est levé. Une ligne dont la clé ou le parent a changé déplace son nœud (les poignées de ce qui a bougé sont libérées, les autres restent valables) ; une ligne que l'arbre n'a pas encore (InsertRow) arrive aussi, à son rang parmi ses frères ; la ligne d'un nœud retiré par of_remove_node revient. Chaque valeur est écrite comme le chargement l'écrit. Seul le DataStore principal est relu, pas un lot (redonnez-le) ; dans un arbre groupé, une ligne dont une valeur de groupe a changé va dans son nouveau groupe. Une fois le DataStore principal redonné comme lot, il rend -5 jusqu'au prochain chargement principal ; une ligne dont le parent ou le groupe change déplace son nœud en place. Rend 0 une fois envoyée, -5 quand aucun DataStore n'est lié, que l'arbre a été vidé par of_clear depuis le chargement, ou que la ligne n'existe pas, -2 quand le composant n'est pas créé | |
of_export_csv (string as_path) | Écrit l'arbre dans un fichier CSV (UTF-8, point-virgule) avec sa hiérarchie : le texte d'un nœud dans la cellule de son niveau, les colonnes après le niveau le plus profond, une ligne d'en-tête d'abord ; un nombre brut, avec la marque décimale de la langue d'affichage. is_export_scope dit lesquels ; ue_csv_saved confirme ; un chemin relatif s'écrit dans le dossier de départ de l'application. Refusé en mode démo. Rend 0 une fois demandé, -5 quand le chemin est vide, -2 quand le composant n'est pas créé | |
of_export_xlsx (string as_path) | Écrit l'arbre dans un classeur Excel (.xlsx) : le texte d'un nœud dans la première colonne, en retrait de son niveau et groupé sous son parent (les niveaux de plan d'Excel : chaque branche se replie par le + / - de la marge, jusqu'à 7 niveaux, tout est écrit ouvert), les colonnes après, les nombres restant des nombres (avec le format de leur colonne quand c'est un masque numérique). is_export_scope dit lesquels ; ue_xlsx_saved confirme. Refusé en mode démo. Rend 0 une fois demandé, -5 quand le chemin est vide, -2 quand le composant n'est pas créé | |
of_get_layout ( ) | Ce que l'utilisateur a arrangé, en JSON : {"columns":[{"key":"","width":260,"visible":true},…],"sort":{"column":"","dir":"none"},"expanded":["europe"]} — la colonne de l'arbre d'abord (clé ""), puis chaque colonne dans son ordre avec sa largeur (0 = automatique) et sa visibilité, le tri, les nœuds ouverts. À ranger (fichier, registre, base) puis à rendre à of_set_layout. Lu en direct. Elle porte aussi "sorts" (toutes les clés du tri), "selected" (les nœuds sélectionnés) et "top" (le nœud en haut de la vue, jamais des pixels) | |
of_set_layout (string as_layout_json) | Remet une disposition lue par of_get_layout ou reçue par ue_layout_changed : largeurs, ordre et visibilité des colonnes, tri, et quels nœuds sont ouverts (ceux qu'elle ne nomme pas se ferment). Une colonne ou un nœud qu'elle nomme et que l'arbre ne contient pas est ignoré. ue_layout_changed est levé une fois quand quelque chose a changé (ni ue_node_toggled ni ue_sort_changed : elle remet un état). Elle rend aussi la sélection (ue_selection_changed si elle a changé, rien n'est demandé) et fait défiler jusqu'au nœud du haut. Une adresse qu'elle demande ouverte dans une branche pas encore répondue est retenue : elle s'ouvre d'elle-même quand la réponse de sa branche l'apporte (ue_node_toggled, puis ue_layout_changed) ; ue_selection_changed n'est levé qu'une fois. Les questions de ib_veto_selection et ib_veto_toggle ne sont pas posées : elle remet un état, typiquement au démarrage. Une branche promise qui tient déjà un nœud n'est pas ouverte sur la moitié de son contenu : elle demande d'abord ue_children_needed. Rend 0 une fois appliqué, -5 quand le texte est vide ou n'est pas un objet JSON, -2 quand le composant n'est pas créé |
Événements #
| Événement | Déclenché quand |
|---|---|
ue_node_clicked (string as_keys) | Un nœud a été cliqué (et sélectionné, sauf en SELECT_NONE). Un clic sur le chevron ou sur la case ne le lève pas ; un nœud grisé ne lève rien |
ue_node_opened (string as_keys) | Un double-clic sur un nœud, ou Entrée : ouvrez votre éditeur pour lui. Un double-clic sur une branche l'ouvre ou la ferme aussi (ue_node_toggled) |
ue_node_rclicked (string as_keys, long al_x, long al_y) | Un clic droit sur un nœud (sélectionné d'abord, sauf si ue_selection_changing le refuse ou en SELECT_NONE : agissez sur as_keys, jamais sur of_selected_key), ou la touche Menu (ou Maj + F10) sur le nœud qui a le focus. al_x, al_y sont des pixels d'écran — le point du clic, ou le coin bas-gauche du nœud pour la touche Menu —, ceux que prend un contextmenu : uo_menu.of_show(al_x, al_y) ; pour un menu PowerBuilder, PopMenu(PointerX(), PointerY()) de votre fenêtre |
ue_node_toggled (string as_keys, boolean ab_expanded) | Un nœud s'est ouvert (ab_expanded = true) ou fermé : son chevron, un double-clic, le clavier, ou votre code (ib_expanded, of_expand_all, of_collapse_all, et ce que of_select_node ou of_scroll_to_node ouvrent) ; une ouverture faite pendant ue_children_needed ne le lève qu'une fois ; of_expand_to_level, of_clear_children (qui ferme) et une branche que of_set_layout a retenue le lèvent aussi |
ue_selection_changed (string as_keys_json) | La sélection a changé : un clic, le clavier, votre code (of_select_node, of_clear_selection), ou des nœuds sélectionnés qui ont quitté l'écran (branche fermée, nœud retiré ou masqué, nœud caché par la recherche — ce qui le contient n'est pas sélectionné à sa place). as_keys_json est le tableau JSON des adresses sélectionnées, dans l'ordre de l'arbre : ["europe/france", "asia"] |
ue_node_checked (string as_keys, boolean ab_checked) | L'utilisateur a coché (ab_checked = true) ou décoché un nœud : sa case, ou Espace. Avec ib_check_cascade, tout son sous-arbre suit, déjà en place quand l'événement arrive. Une coche écrite par votre code ne lève rien. Une coche de l'utilisateur saute un nœud grisé et son sous-arbre |
ue_children_needed (string as_keys) | Une branche promise par ib_has_children s'ouvre et ne contient pas encore ses enfants : ajoutez-les maintenant (of_add_node) ; la branche s'ouvre avec eux au retour de l'événement, après le retour de la ligne qui l'a ouverte. La promesse tient jusqu'à cette réponse, même si un nœud y a été ajouté ou déposé ; sous une feuille cochée, tous les enfants ajoutés prennent sa coche. N'ajoutez rien, et la promesse est retirée (le chevron disparaît) |
ue_node_editing (string as_keys, string as_text) → boolean | Annulable, posé avant qu'un texte tapé par l'utilisateur soit gardé, seulement quand ib_veto_changes = true. Renvoyer FALSE refuse : le nœud garde son texte. Par défaut : TRUE |
ue_node_edited (string as_keys, string as_text, string as_old_text) | L'utilisateur a renommé un nœud (F2, ou un second clic lent avec ib_editable). Le nœud montre déjà as_text ; as_old_text est celui qu'il avait. Avec ib_write_back, le DataStore est déjà écrit |
ue_node_moving (string as_keys, string as_to_parent_keys, long al_position) → boolean | Annulable, posé avant qu'un nœud bouge (un glisser ou of_move_node), seulement quand ib_veto_changes = true. as_to_parent_keys vaut "" pour le haut, al_position sa place finale là-bas, à partir de 1, bornée aux frères — celle que dira ue_node_moved. Un nœud déjà à sa place ne demande rien. Rendre FALSE refuse : rien ne bouge, et of_move_node rend -4. Un of_move_node du même nœud fait dans l'événement n'est pas redemandé : il s'applique, et le of_move_node qui posait la question rend alors -5 ; un autre nœud est demandé normalement. Par défaut : TRUE |
ue_node_moved (string as_keys, string as_old_keys, long al_position) | Un nœud a bougé avec son sous-arbre : un glisser de l'utilisateur ou of_move_node. as_keys est sa nouvelle adresse, as_old_keys celle qu'il avait, al_position sa place sous son nouveau parent (à partir de 1). Les poignées prises à l'ancienne adresse sont déjà libérées (of_move_node les libère aussitôt, un glisser avant cet événement) ; une poignée prise à la nouvelle reste valable |
ue_sort_changed (string as_column, string as_dir, string as_sort) | Le tri a changé : un clic sur un en-tête ou of_sort. as_column est sa première clé ("" pour le texte des nœuds), as_dir sa direction (une constante SORT_), as_sort le tri entier écrit comme le lit le SetSort d'un DataWindow ("type A, text D", "" sans tri). Retirer la colonne triée le lève avec la clé suivante du tri, SORT_NONE quand c'était la seule |
ue_layout_changed (string as_layout_json) | La disposition a changé : largeur ou ordre d'une colonne, tri, nœud ouvert ou fermé, ou of_set_layout. as_layout_json est la disposition entière, comme of_get_layout la rend. Une largeur, une place ou une visibilité de colonne écrite par votre code le lève aussi, quand la disposition change ; titre, format, alignement, tri permis et total restent muets |
ue_write_back_failed (string as_keys, string as_col, string as_value, string as_reason) | ib_write_back : le DataStore a refusé une valeur (un type qu'il ne peut pas tenir, une ligne supprimée depuis le chargement), ou il n'y a plus de DataStore (as_reason = no DataStore is bound). Le nœud est revenu (as_keys est l'adresse qu'il a de nouveau) ; l'événement du geste n'est pas levé. as_reason dit aussi quand le lot du nœud a été rechargé pour un autre nœud, ou quand la colonne de coche porte des valeurs qui ne sont ni un oui ni un non |
ue_image_failed (string as_keys, string as_reason) | L'image d'un nœud n'a pas pu être montrée : as_reason vaut REASON_INSECURE (une adresse http://), REASON_UNC (un chemin réseau venu d'une colonne de DataStore) ou REASON_NOT_FOUND (fichier introuvable). Dit une fois par nœud et par image |
ue_selection_changing (string as_from_keys_json, string as_keys_json) → boolean | Annulable, posé avant que l'utilisateur choisisse une autre sélection (un clic, le clavier, F3) et avant of_select_node, of_clear_selection, of_search_next / of_search_prev, seulement quand ib_veto_selection = true. as_from_keys_json est la sélection actuelle, as_keys_json celle demandée (tableaux JSON d'adresses). Rendre FALSE refuse : rien ne bouge, pas même le focus du clavier, et la méthode rend -4. Ce qui sort de la sélection par conséquence (branche fermée, retrait, masquage, recherche) n'est pas demandé. of_select_nodes demande une fois pour toute la sélection. Pour envoyer l'utilisateur ailleurs, sélectionnez pendant l'événement puis rendez FALSE : une sélection faite pendant l'événement n'est pas redemandée. Par défaut : TRUE |
ue_node_toggling (string as_keys, boolean ab_expanding) → boolean | Annulable, posé avant qu'un nœud s'ouvre (ab_expanding = true) ou se ferme, seulement quand ib_veto_toggle = true : un geste (chevron, double-clic, clavier, *, barre d'outils, branche survolée pendant un glisser) et votre code (ib_expanded, of_expand_all, of_collapse_all, of_expand_to_level — une question par nœud —, of_select_node et of_scroll_to_node pour ce qu'ils ouvrent). Rendre FALSE refuse : le nœud reste tel quel, et une méthode rend -4. Les sœurs que ferme ib_single_expand ne sont pas demandées. Par défaut : TRUE. of_clear_children ferme sans demander |
ue_delete_requested (string as_keys_json) | L'utilisateur a appuyé sur Suppr : as_keys_json est le tableau JSON des nœuds sélectionnés (en SELECT_NONE, celui du focus ; sans sélection sinon, rien n'est levé), ni grisés ni en lecture seule. L'arbre ne retire rien : appelez of_remove_node pour ce que votre application supprime |
ue_copy (string as_tsv) | L'utilisateur a appuyé sur Ctrl+C (ou Ctrl+Inser) : as_tsv tient les nœuds sélectionnés (en SELECT_NONE, celui du focus ; sans sélection sinon, rien n'est levé) dans l'ordre de l'arbre, un par ligne, le texte après autant de tabulations que sa profondeur, puis les colonnes d'une liste en arbre alignées (une ligne d'en-tête d'abord), un nombre brut (un point, ni groupement ni symbole). L'arbre essaie aussi le presse-papiers du navigateur, qui peut être refusé à la page : ClipBoard(as_tsv) pour être sûr |
ue_drop_files (string as_keys, string as_files[]) | Des fichiers ont été déposés depuis l'Explorateur sur un nœud (ib_allow_drop) : as_keys est l'adresse du nœud sous le curseur — vide pour un dépôt à côté des nœuds, sur un nœud grisé ou sur un nœud dont ib_drop_target vaut false —, as_files les chemins complets |
ue_state_clicked (string as_keys) | L'utilisateur a cliqué l'image d'état d'un nœud (is_state_image) : un drapeau, un statut que votre application allume et éteint. Le nœud n'est pas sélectionné, comme pour sa case ; un nœud grisé ne lève rien. Levé pour un geste seulement |
ue_csv_saved (string as_path, boolean ab_ok, string as_error) | Le CSV demandé par of_export_csv est écrit (ab_ok = true) — ou pas : as_error dit pourquoi (le mode démo, un chemin qu'on ne peut pas écrire). as_path est le chemin écrit, un relatif résolu |
ue_xlsx_saved (string as_path, boolean ab_ok, string as_error) | Le classeur demandé par of_export_xlsx est écrit (ab_ok = true) — ou pas : as_error dit pourquoi |
ue_drag_enter ( ) | Un glisser de fichiers depuis l'Explorateur est entré dans le composant (ib_allow_drop) |
ue_drag_leave ( ) | Le glisser de fichiers est reparti sans rien déposer — un dépôt lève ue_drop_files seul |
ue_ready ( ) | Le composant a fini de charger ; tout ce qui a été envoyé avant a été rejoué |
ue_runtime_missing ( ) | Le runtime WebView2 est absent : le composant reste vide |
ue_bg_color (long al_color) | Le composant a calculé sa couleur de fond de thème ; l'userobject l'a déjà adoptée (backcolor) |
Clavier et souris #
- Clic sur un nœud : il est sélectionné (
ue_node_clicked) ; sur son chevron : il s'ouvre ou se ferme ; sur sa case : il est coché ; double-clic :ue_node_opened, et une branche s'ouvre ou se ferme ; clic droit :ue_node_rclicked. EnSELECT_MULTIPLE, Ctrl + clic ajoute ou retire un nœud, Maj + clic prend la plage depuis le dernier. - Haut / Bas : le nœud précédent, le suivant ; Début / Fin : le premier, le dernier ; Page préc. / Page suiv. : d'un écran. Les nœuds grisés sont sautés.
- Droite ouvre le nœud, puis descend à son premier enfant ; Gauche le ferme, puis remonte à son parent — inversées dans une application de droite à gauche.
*du pavé numérique ouvre tout le sous-arbre ;+/-du pavé numérique ouvrent et ferment — ceux du clavier principal se tapent, pour atteindre « +1.2 » ou « -Débits ». - Espace coche le nœud (avec
ib_checkboxes), sinon le sélectionne ; Entrée :ue_node_opened; F2 : renommer (avecib_editable) ; touche Menu ou Maj + F10 :ue_node_rclicked. - En
SELECT_MULTIPLE, Maj + flèches étendent la sélection, Ctrl + flèches ne déplacent que le focus, Ctrl + Espace ajoute ou retire le nœud du focus, Ctrl + A sélectionne tous les nœuds affichés (une seule question avecib_veto_selection). - Les premières lettres d'un texte sélectionnent le nœud affiché qui commence par elles, comme une flèche (en
SELECT_NONE, elles n'y amènent que le focus). - Suppr :
ue_delete_requested(l'arbre ne retire rien) ; Ctrl+C ou Ctrl+Inser :ue_copy; F3 / Maj+F3 : la correspondance suivante / précédente de la recherche (enSELECT_NONE, le focus y va), depuis l'arbre ou depuis le champ de recherche, où Entrée fait de même. Suppr et Ctrl+C n'agissent sur le nœud du focus qu'enSELECT_NONE. - L'en-tête d'une liste en arbre est un arrêt de la touche Tab : Gauche / Droite vont d'en-tête en en-tête (inversées dans une application de droite à gauche), Début / Fin au premier et au dernier, Entrée ou Espace trie, Ctrl + Gauche / Droite rétrécit ou élargit la colonne de 10 pixels, Ctrl + Maj + Gauche / Droite la déplace, Bas passe aux lignes.
- Glisser un nœud (avec
ib_drag_drop) : un fantôme suit le pointeur, une barre montre où il tombera avant ou après, un cadre quand il tombe dedans ; Échap annule. Glisser le bord d'un en-tête élargit la colonne, glisser l'en-tête la déplace — un fantôme et une barre d'insertion montrent où, Échap annule —, cliquer l'en-tête trie. Un glisser dont l'arbre ne voit pas le bouton relâché — la fenêtre perd le focus (Alt+Tab, une boîte de message) — est annulé : rien ne bouge, une largeur revient. - L'arbre est un arrêt de la touche Tab (plus l'en-tête d'une liste en arbre, le champ et les boutons de la barre d'outils) ; un anneau pointillé de la couleur du texte marque le nœud qui a le focus. Un arbre grisé ne prend pas le focus.
Exemples #
Des droits à cocher #
// The rights of a role : a module, then what it allows
uo_rights.ib_checkboxes = true
uo_rights.of_add_node(/*keys*/ "sales", /*text*/ "Sales")
uo_rights.of_add_node(/*keys*/ "sales/read", /*text*/ "Read orders")
uo_rights.of_add_node(/*keys*/ "sales/write", /*text*/ "Create and change orders")
uo_rights.of_add_node(/*keys*/ "sales/delete", /*text*/ "Delete orders")
// What the role already has ; Sales shows mixed
uo_rights.of_node(/*keys*/ "sales/read").ib_checked = true
uo_rights.of_node(/*keys*/ "sales").ib_expanded = true
// event ue_node_checked of uo_rights : (string as_keys, boolean ab_checked)
// Delete never without write : checking it checks write too
if as_keys = "sales/delete" and ab_checked then this.of_node(/*keys*/ "sales/write").ib_checked = true
Retrouver sa disposition au prochain lancement #
// event ue_layout_changed of uo_tree : (string as_layout_json)
// Widths, order, sort and open nodes, kept for the next start
// (the nodes need STABLE keys : a ROLE_KEY column, never the RowIDs a new Retrieve gives)
SetProfileString("app.ini", "tree", "layout", as_layout_json)
// Local variables
string ls_layout
// After the tree is filled : the layout of the last time, if there is one
ls_layout = ProfileString("app.ini", "tree", "layout", "")
if ls_layout <> "" then uo_tree.of_set_layout(/*layout_json*/ ls_layout)
Un menu sur un nœud #
// The entries of the menu, once : uo_menu is a contextmenu of the window, and
// is_menu_keys a string instance variable that keeps the node right-clicked
uo_menu.of_add_item(/*keys*/ "expand", /*text*/ "Expand")
uo_menu.of_add_item(/*keys*/ "delete", /*text*/ "Delete")
// event ue_node_rclicked of uo_tree : (string as_keys, long al_x, long al_y)
// The node clicked is kept : the selection may have stayed elsewhere (a veto that
// refused it, SELECT_NONE). The menu opens where the user clicked
is_menu_keys = as_keys
uo_menu.of_show(/*x*/ al_x, /*y*/ al_y)
// event ue_item_selected of uo_menu : (string as_keys)
// The entry chosen acts on the node right-clicked
choose case as_keys
case "expand"
uo_tree.of_node(/*keys*/ is_menu_keys).ib_expanded = true
case "delete"
uo_tree.of_remove_node(/*keys*/ is_menu_keys)
end choose
Bonnes pratiques #
- Des clés stables : un identifiant, pas un libellé — le texte se renomme, la clé reste.
of_keys_atrend des adresses complètes, à passer telles quelles àof_node. Une disposition gardée d'un lancement à l'autre (of_get_layout) exige une colonneROLE_KEY: sans elle, les clés des lignes sont leurs RowID, qu'un nouveauRetrievedonne à d'autres lignes. - Des branches à la demande dès que l'arbre est grand ou coûteux à lire :
ib_has_childrenetue_children_neededne lisent que ce que l'utilisateur ouvre. - Un DataStore par lot : rechargé pour un autre nœud, un DataStore emporte ses lignes — et PowerBuilder ses RowID — loin du lot d'avant, dont les nœuds n'ont alors plus de ligne.
- Beaucoup de nœuds : seules les lignes visibles sont dessinées — dix mille nœuds défilent comme vingt. Les ajouter est une autre affaire : chaque
of_add_nodeest un message à l'arbre, environ 0,7 ms (2 000 nœuds ≈ 1,3 s mesurées, 10 000 ≈ 7 s attendues) ; un gros arbre se charge parof_from_datastore, en un seul message, ou se lit à la demande, un lot par branche (of_from_datastore(ads, as_parent_keys)). - Les colonnes d'un DataStore sont des identifiants autant que des valeurs : choisissez celles que vous montrez par
of_add_column, rien n'est créé pour vous. - Une coche est une valeur : posée par votre code, elle ne lève rien ; lisez
of_checked_keysquand l'utilisateur valide. of_get_last_errordit pourquoi le dernier appel a été refusé ; il est vidé par toute méthode qui agit et toute propriété écrite, et parof_find_node/of_find_nodes, qui disent par lui pourquoi ils n'ont rien trouvé.- Un ordre donné pendant une attente (du code PowerBuilder qui s'exécute pendant que l'arbre attend sa page, un timer par exemple) n'est pas vérifié d'avance : la page décide seule, et un ajout ou un déplacement qu'elle refuse rend quand même
0. - Pendant une attente (un événement du composant en cours de réponse), un ordre de votre code n'est pas jugé d'avance :
ib_expandedetof_move_nodepassent le véto sans poser la question, etof_get_last_errorle dit. Posez vos ordres hors de l'événement quand le véto compte. of_set_layoutremet un état — typiquement au démarrage — sans poser les questions deib_veto_selectionni deib_veto_toggle: c'est l'exception à la règle qui veut qu'un ordre du code pose la question.- Mode démonstration : sans clé, l'arbre dessine les 8 premiers nœuds de chaque niveau et 200 nœuds dans tout l'arbre (les premiers ajoutés), dans l'ordre du modèle — avant le tri, la recherche et le masquage : un nœud masqué compte, une recherche ou un tri ne montrent jamais le neuvième, lots et groupes compris, et un total ne compte jamais ce que le plafond cache ; les autres restent en mémoire, sans être affichés ni sélectionnables (voir le mode démo).
Hérité du socle commun #
Ces membres existent sur tous les composants visuels — ils ne sont pas propres à celui-ci. Ils sont détaillés une seule fois, dans les chapitres transverses ; cette table dit seulement où les lire.
| Membres | Rôle | Détaillé dans |
|---|---|---|
of_count · of_keys_at · of_has | Parcourir ce que le composant contient | 3.2 Les items |
of_reset | Remettre le composant à zéro | 3.6 Remettre un composant à zéro : of_reset() |
of_register_shortcut · of_clear_shortcuts | Raccourcis clavier du composant | 3.5 Les raccourcis clavier |
of_is_created · of_is_ready · of_get_last_error | S'il est né, s'il est prêt, ce qui a échoué | 3.7 Diagnostic |
of_save_as_png · of_save_as_jpg | Exporter le rendu en image | 3.8 Exporter le rendu en image |
of_set_redraw | Grouper les modifications en un seul repaint | 3.10 Bonnes pratiques |
of_preload_icons | Icônes affichées sans délai | Affichage instantané : of_icon |
of_set_translation | Traduire un libellé du composant | 5.2 Adapter un libellé : of_set_translation |
of_focus_webview | Donner le focus au composant | 6.4 Clavier et focus |
of_print · of_print_to_pdf | Imprimer, ou écrire un PDF | 6.9 Imprimer |
of_set_property · of_get_property · of_component_name | Piloter une propriété par son nom | 3.1 Le moteur de propriétés |
is_accessible_name · is_accessible_description | Le nom et la description que dit un lecteur d'écran | 3.4 Propriétés et events optionnels |
Deux aides ne sont pas héritées : of_icon et of_escape_markup vivent sur n_pbt_utils. Déclarez-en une — n_pbt_utils lnv_utils, rien à créer — et appelez-les dessus.