treeview — u_pbt_treeview #
← Referencia de componentes · Índice de la guía
treeview muestra datos en árbol: nodos que contienen otros, abiertos y cerrados por su chevron, con una imagen, una insignia, una casilla de tres estados y una selección simple o múltiple. En cuanto se le añade una columna, se convierte en una lista en árbol (TreeList): la primera columna lleva el árbol, las demás muestran los campos de cada nodo, ordenables con un clic en su encabezado. Una rama puede prometer hijos que solo lee al abrirse; el usuario renombra un nodo (F2) y lo arrastra a otro sitio, y su aplicación puede rechazarlo antes; una búsqueda solo deja lo que coincide. El árbol se llena a mano o desde un DataStore jerárquico (una fila nombra a su padre), y puede reescribir en él lo que el usuario cambia.
▶ Verlo en vivo — Aplicación de demostración, mosaico Tree view: la vista previa, el código que lo genera y esta página, uno al lado del otro.
De un vistazo #
| Userobject | u_pbt_treeview |
| Clases de elementos | n_pbt_treeview_node (of_node(keys)), n_pbt_treeview_column (of_column(key)) |
| Sirve para | Un árbol de carpetas, un organigrama, categorías de productos, permisos que marcar, una lista de materiales con sus cantidades |
| Principio | Un nodo tiene una clave única bajo su padre; su dirección une las claves de sus niveles con / ("europe/france") |
| Opciones 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 |
| Límite en modo demo | Los 8 primeros nodos de cada nivel dibujados, bajo cada padre, en el orden del modelo, y 200 nodos en todo el árbol, los primeros añadidos (un nodo oculto cuenta, lotes y grupos incluidos; un total nunca cuenta lo que el límite oculta) — véase el modo demo |
Inicio rápido #
// 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)
Una dirección por nodo #
Un nodo se designa por su dirección: las claves de sus niveles unidas por /. "europe" está arriba, "europe/france" dentro de "europe" — el padre se añade primero. Una clave es única bajo su padre: "europe/paris" y "usa/paris" son dos nodos. Una dirección ya ocupada, un padre desconocido, un nivel vacío, una clave que contiene | o empieza por __: la adición devuelve -5 y of_get_last_error dice por qué. of_insert_node coloca un nodo entre sus hermanos (posición contada desde 1), of_move_node lo mueve con su subárbol bajo otro padre ("" = arriba): su dirección cambia, y los handles tomados en la antigua dirección se liberan en el acto (un handle tomado después en la nueva sigue siendo válido). Para recorrer el árbol: of_count() y of_keys_at(n) para el primer nivel, of_count(dirección) y of_keys_at(dirección, n) para los hijos de un nodo — que devuelve la dirección completa, reutilizable tal cual.
// 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
Abrir, seleccionar, marcar #
Un nodo se abre con su chevron, un doble clic, el teclado o su código (ib_expanded de su handle, of_expand_all, of_collapse_all, of_expand_to_level, of_scroll_to_node, lo que abre of_select_node; of_clear_children cierra): cada uno lanza ue_node_toggled, luego ue_layout_changed. La selección sigue is_selection_mode: un nodo (SELECT_SINGLE, el predeterminado), varios con Ctrl y Mayús como en el Explorador (SELECT_MULTIPLE), o ninguno (SELECT_NONE: el teclado solo mueve un foco). of_select_node selecciona un nodo solo, abre lo que lo contiene y lo trae a la pantalla — un árbol abre para seleccionar, como el TreeView de Windows, pero juzga primero: un nodo oculto o contenido en uno oculto, más allá del límite demo o descartado por la búsqueda se rechaza (-5, of_get_last_error dice por qué) y nada se abre. ue_selection_changed recibe las direcciones seleccionadas en un array JSON — tanto si la cambió un clic, el teclado o su código, como si un nodo seleccionado salió de la pantalla (rama cerrada, nodo quitado u oculto, nodo escondido por la búsqueda). Cerrar una rama devuelve el foco a ella. Con ib_checkboxes, cada nodo tiene una casilla; con ib_check_cascade (el predeterminado), una marca del usuario en un padre marca su subárbol salvo un nodo desactivado y su subárbol, que se quedan como están (el padre queda entonces mixto); una marca de su código lo marca todo. Durante una búsqueda, la cascada toma todo el subárbol, nodos escondidos incluidos. Bajo la cascada, un padre es el estado de los hijos que el árbol puede dibujar (ni ocultos ni, en modo demo, más allá del límite): marcado cuando todos lo están, mixto cuando una parte lo está. Una marca puesta por el usuario lanza ue_node_checked; una marca puesta por su código (ib_checked, of_check_all) es un valor, mudo como SetItem. Los hijos recibidos bajo una hoja marcada toman su marca — todos, toda la respuesta a ue_children_needed — hasta que una marca (gesto o código) o un nodo movido dentro le pone fin. Una marca del usuario nunca toca un nodo más allá del límite demo, ni, con ib_write_back, un nodo oculto. of_select_nodes(as_keys_json) selecciona varios nodos a la vez en SELECT_MULTIPLE — el par de of_selected_keys — con una sola pregunta a los vetos y un solo ue_selection_changed; el foco va a la última dirección nombrada.
// 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
Preguntar antes: selección y apertura #
Una pantalla maestro-detalle no debe abandonar una ficha sin guardar. Con ib_veto_selection, ue_selection_changing recibe la selección actual y la pedida (arrays JSON de direcciones) antes de cualquier elección: un clic, Ctrl o Mayús + clic, el teclado, F3, of_select_node, of_clear_selection, of_search_next u of_search_prev. Devuelva FALSE para rechazar: nada se mueve, ni siquiera el foco del teclado, y el método devuelve -4; ue_node_clicked se lanza de todos modos, el clic tuvo lugar. Lo que sale de la selección como consecuencia — una rama cerrada, un nodo quitado, oculto o escondido por la búsqueda — no se pregunta. Del mismo modo, ib_veto_toggle plantea ue_node_toggling antes de cada apertura o cierre, por un gesto o por el código: un ib_expanded rechazado no envía nada (of_get_last_error lo dice), of_expand_all, of_collapse_all y of_expand_to_level aplican los demás nodos y devuelven -4, of_select_node y of_scroll_to_node devuelven -4 sin abrir nada. of_select_node pregunta primero las aperturas (ue_node_toggling), luego la selección: una aplicación nunca actúa sobre una selección aceptada para una apertura rechazada después. Lo que sale de la selección como consecuencia no se rechaza: para que una rama cerrada no abandone una ficha sin guardar, combine ib_veto_selection con ib_veto_toggle y rechace el cierre de la rama que la contiene. ib_single_expand deja una sola rama abierta bajo cada padre: abrir un nodo cierra sus hermanas abiertas, sin preguntar; ponerlo no cierra nada en el momento.
// 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
Ramas cargadas a petición #
Un árbol grande — un disco, un catálogo, una tabla de miles de filas — no tiene por qué leerse de una vez. ib_has_children = true en un nodo es una promesa: su chevron se muestra aunque no contiene nada. Cuando se abre — un clic, el teclado, su código, o of_select_node abriendo lo que contiene un nodo —, se lanza ue_children_needed: sus of_add_node hechos durante el evento están ahí cuando la rama se abre, después del retorno de la línea que la abrió (ib_expanded = true no los espera). La promesa vale hasta esa respuesta, aunque entretanto se haya añadido o soltado un nodo en ella; no añada nada, y se retira (el chevron desaparece). Volver a poner ib_has_children = true hace que la próxima apertura vuelva a preguntar. Una apertura hecha durante el evento lanza un solo ue_node_toggled. of_expand_all solo abre las ramas que ya tienen hijos: una rama cuya promesa no ha tenido respuesta se queda cerrada, no se hace ninguna pregunta en masa. Para una tabla, no hace falta llamar a of_add_node fila por fila: of_from_datastore(ads, as_parent_keys) hace de las filas de un DataStore los hijos del nodo, en un solo mensaje — el patrón ItemPopulate → Retrieve del TreeView de PowerBuilder. ROLE_PARENT nombra allí una fila del mismo lote (vacío o desconocido: directamente bajo el nodo); el mismo DataStore dado de nuevo bajo el mismo nodo sustituye su lote, otro DataStore añade el suyo. of_row de un nodo de un lote devuelve su fila en su DataStore, e ib_write_back escribe allí. of_clear_children quita los hijos de un nodo y le hace prometer de nuevo: su próxima apertura vuelve a preguntar (el «actualizar» de una carpeta). Dé a cada lote su propio DataStore (creado al abrirse su rama, conservado mientras se muestran sus nodos): un DataStore recargado para otro nodo — Reset, Retrieve, luego of_from_datastore bajo otro nodo — se lleva sus filas al nuevo lote, y PowerBuilder vuelve a dar los mismos RowID tras un Reset. Los nodos del lote anterior conservan entonces lo que muestran pero ya no tienen fila: of_row devuelve 0, un movimiento por código devuelve -5 ("loaded again"), un texto renombrado o una marca se rechaza y ue_write_back_failed dice por qué, y la carga que lo causó los cuenta (stale=N) en of_get_last_error. El mismo DataStore dado de nuevo bajo el mismo nodo sustituye su lote; para refrescar un lote desde otro objeto DataStore, llame primero a of_clear_children, si no se añade junto al primero. Una columna llamada has_children (ROLE_HAS_CHILDREN) hace que una fila prometa sus propios hijos, sin bucle. as_parent_keys vacío se rechaza (-5): la cima del árbol es 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
Renombrar y mover #
Con ib_editable, el usuario renombra un nodo: F2, o un clic en el nodo ya seleccionado (tras un breve retraso, como el Explorador). Intro (o salir del campo) guarda el texto, Esc lo devuelve, un texto vaciado se rechaza (la edición se cancela); ue_node_edited recibe el texto tecleado y el antiguo — un texto tecleado es texto, nunca etiquetas. Una orden de su código durante la edición conserva el campo y lo tecleado en él; si la fila editada sale de la pantalla sin un gesto del usuario (código, desplazamiento), la edición se cancela. Con ib_drag_drop, arrastra un nodo: sobre el cuarto superior de una fila va antes de ella, sobre el cuarto inferior después — como primer hijo si es una rama abierta —, en el centro dentro; una rama cerrada bajo el puntero se abre tras un momento, el árbol se desplaza cerca de sus bordes, Esc cancela, un nodo nunca va a su propio subárbol ni adonde su clave está ocupada, y nada se suelta sobre la fila de un nodo desactivado. Un arrastre cuyo botón soltado el árbol no ve — la ventana pierde el foco (Alt+Tab, un cuadro de mensaje) — se cancela: nada se mueve. Bajo una ordenación, o con ib_parents_first, una soltada solo va dentro. ue_node_moved recibe la nueva dirección, la antigua y el lugar bajo el nuevo padre; un nodo soltado donde ya está no pregunta, no escribe ni lanza nada. Con ib_veto_changes, ue_node_editing y ue_node_moving se plantean antes — ue_node_moving con el lugar final, el que dirá ue_node_moved: devuelva FALSE para rechazar — nada cambia, y of_move_node devuelve -4. Se arrastra un nodo a la vez, incluso en selección múltiple.
// 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
Su código también abre un nombre en edición: of_edit_node(as_keys) — el EditLabel de un TreeView de PowerBuilder, para una «Nueva carpeta» que se abre lista para nombrarla. Primero se selecciona el nodo (lo que lo contiene se abre), después se abre el campo; el final es del usuario, como arriba. Un bloqueo detiene al usuario, nunca a su código: funciona con ib_editable = false, en un nodo de solo lectura o atenuado. of_cancel_edit() cierra el campo y devuelve el texto, como Esc.
// 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")
Bloqueos, Supr y copia #
Tres bloqueos por nodo detienen al usuario, nunca a su código: ib_read_only (ni renombrado ni arrastrado, sigue siendo un destino), ib_drop_target = false (nada se suelta dentro de él, ni un nodo ni un archivo — antes o después de él sigue permitido) e ib_show_checkbox = false (sin casilla: el nodo no cuenta para su padre, no está en of_checked_keys, y la cascada lo atraviesa hacia sus hijos). Supr lanza ue_delete_requested con los nodos seleccionados (en SELECT_NONE, el del foco; sin selección, si no, no se lanza nada), salvo los desactivados y de solo lectura: el árbol no quita nada, su aplicación llama a of_remove_node para lo que borra. Ctrl+C (o Ctrl+Insert) lanza ue_copy con los nodos seleccionados (en SELECT_NONE, el del foco) en texto tabulado, un número bruto (un punto, sin agrupación ni símbolo): el texto tras tantas tabulaciones como su profundidad, luego las columnas de una lista en árbol alineadas, primero una línea de encabezado; el árbol intenta también el portapapeles del navegador, que se le puede negar a la página — ClipBoard(as_tsv) para estar seguro.
// 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)
Archivos soltados desde el Explorador #
Con ib_allow_drop, el árbol acepta archivos arrastrados desde el Explorador de Windows sobre un nodo: el nodo bajo el cursor se ilumina durante el arrastre, ue_drop_files recibe su dirección y las rutas completas. as_keys está vacío para una soltada junto a los nodos, sobre un nodo desactivado o sobre un nodo cuyo ib_drop_target vale false. ue_drag_enter y ue_drag_leave dicen que un arrastre de archivos entró y luego salió sin soltar nada.
// 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"))
Columnas, ordenación y disposición #
of_add_column convierte el árbol en una lista en árbol: la primera columna lleva el árbol (su título es is_tree_title), cada columna añadida muestra el campo de la misma clave de cada nodo — puesto con of_set_field, o una columna del DataStore. El handle de una columna (of_column) ajusta su título, su ancho (0 = automático), su alineación, su formato (una máscara numérica como "#,##0.00" con los separadores del idioma de visualización, o tokens de fecha para un valor "yyyy-mm-dd", los del datagrid), su visibilidad y su lugar. Un clic en un encabezado ordena los hermanos de cada nivel — ascendente, descendente, luego el orden de adición — y lanza ue_sort_changed; of_sort hace lo mismo desde el código. La ordenación solo cambia el orden mostrado: of_keys_at y las posiciones conservan el orden de adición. El usuario ensancha una columna por el borde de su encabezado y la mueve arrastrando el encabezado. Lo que ha dispuesto — anchos, orden, visibilidad, ordenación, nodos abiertos — se lee con of_get_layout y se devuelve con of_set_layout; ue_layout_changed lleva la disposición entera tras cada gesto que la cambia, y cuando su código escribe el ancho, el lugar o la visibilidad de una columna (ii_width, ii_index, ib_visible) y la disposición cambia. Los valores iguales conservan el orden del modelo, y la ordenación se rehace cuando cambia el idioma de visualización. Quitar la columna ordenada (of_remove_column, of_clear_columns) lanza ue_sort_changed con la clave siguiente de la ordenación — SORT_NONE cuando era la única —, luego ue_layout_changed. Los cinco colores del handle de una columna (il_accent, il_back_color, il_text_color, il_back_color_hover, il_text_color_hover) colorean su encabezado. En cuanto hay columnas, la columna del árbol queda fija al desplazarse en horizontal. La ordenación puede tener varias claves: of_sort(as_sort) lee la sintaxis del SetSort de un DataWindow («type A, text D», siendo «text» el texto de los nodos), of_sort(as_column, as_dir) acepta también un campo que ninguna columna muestra, y ue_sort_changed recibe la ordenación entera como tercer argumento. ib_parents_first pone en cada nivel los nodos que tienen (o prometen) hijos antes de las hojas — las carpetas antes de los archivos — sea cual sea la ordenación. Una columna no puede tomar la clave text, que nombra el texto de los nodos (-5): of_sort("text", as_dir) ordena por él, y of_sort acepta varios espacios entre una columna y su sentido, como 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")
Exportar el árbol con su jerarquía: of_export_csv(as_path) escribe un CSV (UTF-8, punto y coma) en el que el texto de un nodo está en la celda de su nivel — una celda más a la derecha por nivel —, las columnas de una lista en árbol después del nivel más profundo, primero una línea de encabezado; of_export_xlsx(as_path) escribe un libro de Excel en el que el texto está sangrado según su nivel y cada rama agrupada bajo su padre, plegable en Excel, y los números siguen siendo números. is_export_scope dice qué nodos: EXPORT_ALL (el predeterminado) todos los nodos, ramas cerradas incluidas, EXPORT_SHOWN las filas en pantalla. El árbol construye el archivo, la DLL lo escribe, ue_csv_saved / ue_xlsx_saved lo confirman; rechazado en modo demo.
// 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")
Totales por rama #
Una columna de una lista en árbol puede mostrar, en cada rama, el total de lo que contiene: is_summary en su handle vale SUMMARY_SUM, SUMMARY_AVG, SUMMARY_MIN, SUMMARY_MAX o SUMMARY_COUNT (los valores no vacíos). El cálculo baja hasta las hojas — una media es la de las hojas, nunca una media de medias — y el total se escribe en negrita, por is_format — un recuento siempre como número simple. Una rama que tiene su propio valor lo conserva y lo hace subir, salvo con ib_summary_over_value en la columna. Solo cuentan los nodos que el árbol puede dibujar (nunca uno oculto); con ib_summary_filtered, en el componente, solo lo que la búsqueda muestra. of_get_field devuelve el total bruto (un número con punto), una ordenación por esta columna usa los totales, y los totales siguen cada adición, retirada o arrastre. SUMMARY_MIN y SUMMARY_MAX comparan también fechas (yyyy-mm-dd, yyyy-mm-dd hh:mm:ss, hh:mm:ss), y una suma de enteros sigue exacta más allá 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")
Buscar #
is_filter solo muestra los nodos cuyo texto contiene la búsqueda (mayúsculas ignoradas), con los nodos que los contienen, abiertos, y el texto encontrado resaltado. "" muestra todo. Lo que contiene una coincidencia se muestra abierto sin cambiar ib_expanded, y los chevrons quedan inertes mientras dura la búsqueda. Con ib_toolbar, una barra encima del árbol lleva un campo de búsqueda (que escribe is_filter: una lectura lo devuelve al instante), y los botones Expandir todo y Contraer todo. Esc en el campo vacía la búsqueda, Flecha abajo pasa al árbol, Intro y F3 van a la coincidencia siguiente (Mayús: a la anterior) y el campo conserva el teclado. Un nodo seleccionado que la búsqueda esconde sale de la selección, y ue_selection_changed lo dice; el nodo que lo contiene no se selecciona en su lugar. of_select_node y of_scroll_to_node rechazan un nodo que la búsqueda descarta (-5). Para ir de coincidencia en coincidencia, of_search_next y of_search_prev seleccionan la siguiente o la anterior tras el nodo del foco, en bucle (F3 y Mayús+F3 con el teclado), y of_match_count dice cuántas encontró la búsqueda. of_find_node(as_field, as_value, as_after_keys) encuentra sin filtrar: la dirección del primer nodo cuyo campo ("" = su texto) vale exactamente el valor, en el orden que muestra el árbol, ramas cerradas incluidas; vuelva a dar la dirección encontrada para la siguiente. En SELECT_NONE, of_search_next y of_search_prev mueven allí el foco, como F3. of_find_node parte tras el lugar de as_after_keys en el orden mostrado — también un nodo oculto; uno desconocido devuelve "" y of_get_last_error lo dice. of_find_nodes(as_field, as_value) devuelve todas las coincidencias de una vez, como array JSON en el orden mostrado.
La búsqueda ignora los acentos por defecto, como la ordenación: «montreal» encuentra «Montréal», y la I con punto del turco cuenta como una I («izmir» encuentra «İzmir»); ib_filter_accents = true los hace contar. En selección múltiple, Ctrl+A selecciona todos los nodos mostrados (una sola pregunta con 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"))
Desde un DataStore #
of_from_datastore hace un nodo de cada fila de una tabla jerárquica: la columna ROLE_KEY da su clave (sin ella, el RowID de la fila), la columna ROLE_PARENT nombra la clave del nodo que lo contiene (vacía, desconocida, o un bucle: arriba) — con una columna ROLE_KEY, un valor de padre nombra una clave, nunca un RowID. Los demás roles: el texto (ROLE_TEXT, mostrado como texto, nunca como etiquetas), la imagen, la marca, la insignia y la apertura al cargar. Una columna desempeña un rol cuando se llama como él (key, parent, text…) o cuando of_map lo dice. Cada columna es un campo (of_get_field) — las columnas de la lista no se crean automáticamente: of_add_column con el nombre de la columna. Fechas y números se leen sea cual sea la configuración regional, en una sola forma: una fecha yyyy-mm-dd, una fecha-hora yyyy-mm-dd hh:mm:ss, un número con punto y sin ceros inútiles (1234,50 pasa a 1234.5) — una columna decimal se formatea y se ordena como un número. Dos filas con la misma clave: la segunda toma "clave~RowID". Lo que la carga tuvo que corregir (filas cuyo padre no está, bucles rotos, claves duplicadas, claves imposibles) lo dice of_get_last_error, y el retorno sigue siendo 0. of_reload_row vuelve a leer una fila cambiada por su código y actualiza su nodo en el sitio; una fila cuya clave o padre cambió mueve su nodo. El nodo de una fila quitado por of_remove_node sigue fuera hasta el próximo of_from_datastore; of_reload_row de su fila lo trae de vuelta. Con ib_write_back, un texto renombrado se escribe en la columna ROLE_TEXT y un nodo que cambia de padre lo escribe en la columna ROLE_PARENT (NULL arriba, sea cual sea su tipo; un movimiento entre los mismos hermanos no escribe nada), antes del evento; un nodo de fila no va entonces ni bajo un nodo añadido a mano ni bajo una fila sin valor de clave — su columna padre no sabría decirlo. Un valor que el DataStore rechaza, o un DataStore destruido desde la carga (no DataStore is bound), devuelve el nodo a su sitio y lanza ue_write_back_failed. Sin ib_write_back, un arrastre solo mueve el nodo: su fila conserva lo que dice el DataStore, y la siguiente relectura de las filas (of_map, is_group_by, of_reload_row, una nueva carga) devuelve el nodo a donde dice su fila — su antiguo handle se libera. El Update sigue siendo suyo. El handle de un nodo lee el número de su fila (of_row). of_from_datastore lee también las filas de un DataWindow o de un DataWindowChild — el que el usuario ve al lado: el árbol escribe entonces en ese. Con ib_write_back, una marca del usuario se escribe también en la columna ROLE_CHECKED de cada fila que cambió — cascada incluida, y las ramas de encima cuyo estado pasa a marcado o desmarcado (una rama que queda mixta conserva su valor) —, escrita como la columna ya la escribe (1/0, Y/N, T/F, O/N, -1/0…; una columna que solo muestra su no escribe el sí habitual: Y para N, 1 para 0 — O y -1 solo si la columna ya contiene uno); una columna cuyos valores no son ni un sí ni un no se rechaza, con su motivo. Cada valor se juzga primero y la escritura es todo o nada: un rechazo devuelve las marcas del gesto y lanza ue_write_back_failed. of_row_keys devuelve la dirección del nodo de una fila del DataStore principal: quite el nodo antes de un DeleteRow. Toda escritura de vuelta es todo o nada — cada valor se juzga antes de escribir uno; una fecha-hora conserva su hora, una columna time se escribe, se lee y se agrupa en hh:mm:ss. Un movimiento escrito por of_move_node se juzga de nuevo tras ue_node_moving, y lo escrito se repone si el nodo no se mueve. Con ib_write_back, un nodo de fila cuyo DataStore no tiene columna ROLE_TEXT no se renombra. Una nueva carga solo libera los handles de lo que sustituye: el handle de un nodo añadido a mano, un handle inerte o uno tomado en una dirección aún no creada siguen válidos; of_from_datastore desde una DataWindow comprueba que sus datos se pueden compartir (-5 con el motivo). Lo que una relectura de las filas tuvo que corregir se cuenta en of_get_last_error — incluidos los nodos añadidos a mano subidos arriba porque su grupo ya no existe (lifted=N) y los lotes que se fueron con su nodo (lots=N); of_map e is_group_by lo dicen para todas las fuentes.
// 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 rol se resuelve por DataStore: la columna que of_map(ads, as_role, as_column) dio a este DataStore, si no la de of_map(as_role, as_column) cuando este DataStore la tiene, si no la columna que lleva el nombre del rol. Un lote de empleados bajo un árbol de departamentos no necesita así ninguna columna de los departamentos. Una tabla cuyas raíces llevan 0 en su columna padre (una columna NOT NULL) lo dice con is_root_parent_value = "0" ("0|-1" para dos valores): esas filas están arriba sin contar como huérfanas, y un nodo movido arriba con ib_write_back escribe 0 en lugar de NULL. Las columnas ROLE_STATE_IMAGE y ROLE_OVERLAY_IMAGE dan la imagen de estado y la imagen superpuesta de un nodo, leídas como 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 árbol agrupado por columnas #
El estilo TreeView de un DataWindow, sin DataWindow: is_group_by = "region|country|city" hace de las filas de of_from_datastore las hojas de grupos construidos sobre los valores de esas columnas, un nivel por columna (ROLE_PARENT no desempeña ningún papel, ROLE_KEY nombra las hojas). La clave de un grupo es su valor (/, | y % escritos %2F, %7C, %25), su texto el valor escrito con el formato de la columna de la misma clave, «(vacío)» para un valor vacío; el handle de un nodo de grupo lee of_group_column() y of_group_value(). Puesto tras una carga, reagrupa; of_reload_row coloca una fila cuyo valor cambió en su nuevo grupo. of_set_level_image da una imagen a todos los nodos de un nivel, of_expand_to_level abre el árbol hasta un nivel, e is_summary da los totales de cada grupo. Con ib_write_back, una hoja soltada bajo un grupo del último nivel escribe todas sus columnas de grupo antes del evento; en otro lugar, y para un nodo de grupo, el movimiento se rechaza. El texto de un grupo sigue un formato puesto tras la carga, la llegada de su columna y el idioma de visualización; un valor que empieza por __ se escribe %5F_ en la clave; of_group_value de una fecha-hora vale yyyy-mm-dd hh:mm:ss, de una hora hh:mm:ss. Sin ib_write_back, una hoja arrastrada bajo otro grupo vuelve al suyo en la siguiente agrupación, ya que su fila no cambió; un nodo añadido a mano bajo un grupo que desaparece sube arriba.
// 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)
Propiedades #
| Propiedad | Tipo | Predeterminado | Función | ||
|---|---|---|---|---|---|
is_selection_mode | string | SELECT_SINGLE | Cómo selecciona el usuario: SELECT_SINGLE (un nodo), SELECT_MULTIPLE (Ctrl y Mayús, como el Explorador) o SELECT_NONE (el teclado solo mueve un foco, nada se selecciona). Otro valor se rechaza: el antiguo se queda, of_get_last_error dice por qué | ||
ib_checkboxes | boolean | false | Una casilla antes de cada nodo | ||
ib_check_cascade | boolean | true | Una marca del usuario en un nodo marca su subárbol, salvo un nodo desactivado y su subárbol; una marca del código lo marca todo. Un padre es el estado de los hijos que el árbol puede dibujar: marcado cuando todos lo están, mixto (CHECK_MIXED) cuando una parte lo está. false: cada nodo conserva su propia marca; una marca del usuario nunca toca un nodo más allá del límite demo, ni, con ib_write_back, un nodo oculto | ||
ib_editable | boolean | false | El usuario renombra un nodo: F2, o un clic en el nodo ya seleccionado. Intro guarda, Esc devuelve (ue_node_edited); un texto vaciado se rechaza | ||
ib_drag_drop | boolean | false | El usuario arrastra un nodo antes, después o dentro de otro (ue_node_moved); nunca a su propio subárbol; una soltada en el cuarto inferior de una rama abierta lo convierte en su primer hijo; la ventana que pierde el foco durante un arrastre lo cancela | ||
ib_veto_changes | boolean | false | Plantear ue_node_editing y ue_node_moving antes de que se guarde un texto tecleado o se mueva un nodo — por gesto como por of_move_node (desactivado por defecto, como todo evento cancelable) | ||
is_filter | string | "" | La búsqueda: solo se muestran los nodos cuyo texto la contiene, con los que los contienen, abiertos, el texto encontrado resaltado. "" muestra todo. El campo de la barra de herramientas también la escribe: una lectura la devuelve al instante; un nodo seleccionado que esconde sale de la selección (ue_selection_changed) | ||
ib_toolbar | boolean | false | Una barra encima del árbol: el campo de búsqueda, Expandir todo, Contraer todo | ||
ib_show_lines | boolean | false | Líneas finas unen cada nodo a su padre | ||
ii_indent | integer | 18 | La sangría de un nivel, en píxeles, de 8 a 64. Otro valor se rechaza: el antiguo se queda, of_get_last_error dice por qué | ||
is_tree_title | string | "" | El título de la columna del árbol de una lista en árbol. Acepta el texto enriquecido con etiquetas | ||
ib_write_back | boolean | false | Con un árbol alimentado por of_from_datastore: un texto renombrado se escribe en la columna ROLE_TEXT, un nodo que cambia de padre lo escribe en la columna ROLE_PARENT (NULL arriba; un movimiento entre los mismos hermanos no escribe nada), antes del evento. Un nodo de fila no va entonces ni bajo un nodo añadido a mano ni bajo una fila sin valor de clave. Un valor rechazado, o un DataStore destruido, devuelve el nodo a su sitio y lanza ue_write_back_failed. Sin ella, un arrastre solo mueve el nodo. El Update sigue siendo suyo. Una marca del usuario se escribe también en la columna ROLE_CHECKED de cada fila que cambia. Una marca escribe también las ramas de encima cuyo estado pasa a marcado o desmarcado; cada valor se juzga primero, todo o nada; sin columna ROLE_TEXT, un nodo de fila no se renombra | ||
ib_enabled | boolean | true | false desactiva el árbol: los nodos siguen visibles, ya nada responde al usuario y el árbol sale del orden de la tecla Tab. Su código sigue cambiándolo todo; ya no toma el foco | ||
ib_veto_selection | boolean | false | Preguntar ue_selection_changing antes de que cambie la selección: una elección del usuario, of_select_node, of_clear_selection (desactivado por defecto, como todo evento cancelable) | ||
ib_veto_toggle | boolean | false | Preguntar ue_node_toggling antes de que un nodo se abra o se cierre, por un gesto o por el código | ||
ib_single_expand | boolean | false | Una sola rama abierta bajo cada padre: abrir un nodo cierra sus hermanas abiertas (ue_node_toggled para cada una, sin pregunta); ponerlo no cierra nada en el momento; of_expand_all y of_expand_to_level lo ignoran | ||
ib_parents_first | boolean | false | En cada nivel, los nodos que tienen (o prometen) hijos antes de las hojas — las carpetas antes de los archivos —, sea cual sea la ordenación; una soltada solo va entonces dentro | ||
ib_summary_filtered | boolean | false | Los totales de las ramas (is_summary de una columna) solo cuentan lo que muestra la búsqueda; false: todo nodo que el árbol puede dibujar | ||
is_group_by | string | "" | Un árbol agrupado por columnas, como el estilo TreeView de un DataWindow: `"region | country" hace un nivel de grupos por columna, siendo las filas de of_from_datastore las hojas bajo el último. Puesto tras una carga, reagrupa; una columna que el DataStore no tiene se ignora. Lo que una agrupación tuvo que corregir, para todas las fuentes, se lee en of_get_last_error` | |
is_root_parent_value | string | "" | Los valores de padre que nombran la cima del árbol, unidos por ` | ("0", "0 | -1"): una fila así está arriba sin contar como huérfana, y un nodo movido arriba con ib_write_back escribe el primero en lugar de NULL. ""`: solo un padre vacío (NULL) nombra la cima |
ib_filter_accents | boolean | false | false: la búsqueda (is_filter) ignora los acentos, como la ordenación; true: cuentan | ||
ib_auto_tooltip | boolean | true | Una etiqueta cortada por el ancho muestra su texto entero en un tooltip — nunca encima de un tooltip que su aplicación dio al nodo | ||
is_export_scope | string | EXPORT_ALL | Lo que escriben of_export_csv y of_export_xlsx: EXPORT_ALL todos los nodos, ramas cerradas incluidas, EXPORT_SHOWN las filas en pantalla. Un nodo oculto nunca se escribe; otro valor se rechaza | ||
ib_allow_drop | boolean | false | Aceptar los archivos soltados desde el Explorador sobre un nodo: el nodo bajo el cursor se ilumina, ue_drop_files lo nombra con las rutas completas | ||
is_theme_style | string | "" | Estilo visual del componente (constantes THEME_STYLE_*); vacío = el de la aplicación, seguido en cada cambio | ||
is_theme_mode | string | "" | Variante clara u oscura (constantes THEME_MODE_*); vacío = la de la aplicación, seguida en cada cambio | ||
il_theme_accent | long | -1 | Color de acento de este componente (-1 = acento de la aplicación, o el del tema) | ||
is_tooltip | string | "" | Tooltip simple mostrado al pasar el ratón por el componente | ||
is_super_tooltip_title | string | "" | Título del tooltip enriquecido (prevalece sobre is_tooltip) | ||
is_super_tooltip_text | string | "" | Texto del tooltip enriquecido (se acepta el marcado enriquecido) | ||
is_super_tooltip_image | string | "" | Imagen del tooltip enriquecido |
Propiedades de un nodo — n_pbt_treeview_node #
Su handle, mediante of_node(dirección). Una lectura pregunta al árbol qué es el nodo ahora. Su of_count() cuenta sus hijos, su of_keys_at(n) devuelve la dirección de su n-ésimo hijo (desde 1), su of_has(clave) dice si tiene ese hijo, su of_key() devuelve su clave.
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
is_text | string | "" | El texto del nodo. Acepta el texto enriquecido con etiquetas. Vacío, el nodo muestra su clave |
is_image | string | "" | La imagen antes del texto: un archivo del puesto, un recurso "archivo.dll:nombre", un glifo "mono:…" / "tint:…" dibujado en el tema, una dirección https://. http:// se rechaza (ue_image_failed, REASON_INSECURE) |
is_expanded_image | string | "" | La imagen cuando el nodo está abierto (una carpeta abierta); "" conserva is_image |
is_state_image | string | "" | La imagen de estado del nodo, antes de su imagen: una bandera, un estado — la StatePicture de un TreeView de PowerBuilder. Un clic en ella lanza ue_state_clicked y no selecciona el nodo; mismas fuentes y rechazos que is_image |
is_overlay_image | string | "" | Una pequeña imagen dibujada encima de la esquina inferior de la imagen del nodo (una flecha de acceso directo, un candado) — la OverlayPicture de un TreeView de PowerBuilder |
is_selected_image | string | "" | La imagen del nodo mientras está seleccionado — la SelectedPicture de un TreeView de PowerBuilder. "" conserva is_image |
ib_expanded | boolean | false | true abre el nodo (sus hijos se muestran), false lo cierra; sigue ue_node_toggled, como con un clic en su chevron. Un nodo sin hijos se lee false; abrir un nodo que solo promete hijos los pide (ue_children_needed); llegan con la respuesta, después del retorno de esta línea; con ib_veto_toggle, se plantea primero ue_node_toggling; rechazado, no se envía nada y of_get_last_error lo dice |
ib_has_children | boolean | false | Una promesa de hijos: el chevron se muestra aunque todavía no se haya añadido nada. Abrir el nodo lanza ue_children_needed, donde su aplicación los añade. La promesa vale hasta la respuesta, aunque se haya añadido o soltado un nodo en ella; volver a ponerla a true hace preguntar de nuevo en la próxima apertura |
ib_checked | boolean | false | La marca del nodo (ib_checkboxes del árbol). Con ib_check_cascade, escribirla marca todo el subárbol (nodos desactivados incluidos), y se lee true cuando sus hijos que el árbol puede dibujar están todos marcados (of_check_state dice mixto); los hijos recibidos bajo una hoja marcada toman su marca. Una marca escrita por su código no lanza nada |
ib_enabled | boolean | true | false desactiva el nodo: el usuario no puede ni seleccionarlo, ni marcarlo, ni renombrarlo, ni arrastrarlo, nada se suelta sobre su fila, el teclado lo salta, y una marca del usuario en un padre lo deja como está, con su subárbol. Su código lo sigue seleccionando y marcando |
ib_visible | boolean | true | false quita de la pantalla el nodo y su subárbol; conserva su dirección |
is_badge | string | "" | Una pequeña insignia tras el texto (etiquetas aceptadas): un número de elementos sin leer; "" ninguna |
ib_read_only | boolean | false | true: el usuario no puede ni renombrarlo ni arrastrarlo (sigue siendo un destino), y Supr lo excluye; su código sigue pudiendo |
ib_drop_target | boolean | true | false: nada se suelta dentro de él, ni un nodo arrastrado ni un archivo del Explorador; antes o después de él sigue permitido |
ib_show_checkbox | boolean | true | false: sin casilla en este nodo (ib_checkboxes) — no cuenta para su padre, no está en of_checked_keys, y la cascada lo atraviesa hacia sus hijos |
of_keys ( ) → string | — | — | Devuelve la dirección del nodo: sus claves unidas por / |
of_level ( ) → long | — | — | Devuelve su profundidad: 1 para un nodo de arriba, 2 para un nodo dentro de él… 0 cuando el árbol no lo contiene |
of_position ( ) → long | — | — | Devuelve su lugar entre los hijos de su padre, desde 1, en el orden de adición (una ordenación solo cambia el orden mostrado); 0 cuando el árbol no lo contiene |
of_parent_keys ( ) → string | — | — | Devuelve la dirección de su padre; "" para un nodo de arriba |
of_check_state ( ) → string | — | — | Devuelve el estado de su casilla: CHECK_ON, CHECK_OFF o CHECK_MIXED (parte de sus hijos marcada, con ib_check_cascade); "" cuando el árbol no lo contiene |
of_row ( ) → long | — | — | Devuelve el número de fila de hoy, en el DataStore de of_from_datastore, de la fila de la que viene el nodo — sea cual sea la clave que tuvo que tomar, y tras una ordenación o un filtro del DataStore. 0 para un nodo añadido a mano o cuya fila ha desaparecido; un nodo de un lote devuelve su fila en su DataStore, un nodo de grupo 0; 0 también cuando el DataStore de su lote se recargó para otro nodo |
of_group_column ( ) → string | — | — | Para un nodo de grupo de is_group_by: la columna por la que agrupa su nivel ("region"); "" para cualquier otro nodo |
of_group_value ( ) → string | — | — | Para un nodo de grupo: el valor de su columna que representa, tal como lo contienen las filas (una fecha yyyy-mm-dd, un número con punto, "" para el grupo de valores vacíos); "" para cualquier otro nodo; una fecha-hora yyyy-mm-dd hh:mm:ss, una hora hh:mm:ss |
is_tooltip | string | "" | Tooltip simple mostrado al pasar el ratón por el item |
is_super_tooltip_title | string | "" | Título del tooltip enriquecido del item (prevalece sobre is_tooltip) |
is_super_tooltip_text | string | "" | Texto del tooltip enriquecido del item (se acepta el marcado enriquecido) |
is_super_tooltip_image | string | "" | Imagen del tooltip enriquecido del item |
il_accent | long | -1 | Acento del nodo: su selección (mientras el árbol tiene el foco) y su casilla marcada lo toman; la insignia conserva el color del tema (-1 = el del componente) |
il_back_color | long | -1 | Fondo de la fila del nodo, en RGB(r,g,b) (-1 = lo que da el tema). Una fila seleccionada toma los colores de la selección |
il_text_color | long | -1 | Color del texto de la fila del nodo (-1 = lo que da el tema) |
il_back_color_hover | long | -1 | Fondo de la fila del nodo bajo el puntero (-1 = lo que da el tema) |
il_text_color_hover | long | -1 | Color del texto de la fila del nodo bajo el puntero (-1 = lo que da el tema) |
Propiedades de una columna — n_pbt_treeview_column #
Su handle, mediante of_column(clave). Un valor escrito por su código es mudo, como SetItem — salvo su disposición: ii_width, ii_index e ib_visible escritos por su código lanzan ue_layout_changed cuando la disposición cambia, como un gesto. Una lectura devuelve lo que el usuario haya podido cambiar (ancho, lugar).
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
is_title | string | "" | El título en el encabezado (etiquetas aceptadas); "" muestra la clave |
ii_width | integer | 0 | El ancho en píxeles: 0 es automático (tan ancho como el título y los valores dibujados), si no de 40 a 2000. El usuario arrastra el borde del encabezado: una lectura lo devuelve al instante |
is_align | string | ALIGN_START | Dónde se sitúan los valores en sus celdas: ALIGN_START, ALIGN_CENTER, ALIGN_END — el inicio y el final de la lectura, que siguen una aplicación de derecha a izquierda. Otro valor se rechaza |
is_format | string | "" | Cómo se escribe un valor: una máscara numérica para un número ("#,##0.00", separadores del idioma de visualización), los tokens de fecha de un formato de visualización PowerBuilder para una fecha o una fecha-hora ("dd/mm/yyyy", "d mmm yyyy hh:mm" — mm tras una hora son los minutos —, AM/PM, s, f, literales "…", [shortdate], [longdate], [time]), los mismos que el datagrid; "" escribe el valor tal cual |
ib_visible | boolean | true | false quita la columna de la pantalla; conserva su lugar y su clave |
ii_index | integer | — | Su lugar entre todas las columnas, desde 1: escribirlo mueve la columna. El usuario también arrastra un encabezado: una lectura lo devuelve al instante |
ib_sortable | boolean | true | Un clic en su encabezado ordena el árbol por esta columna. El encabezado de la columna del árbol (is_tree_title) ordena siempre, por el texto de los nodos |
is_summary | string | "" | El total que cada rama muestra en esta columna: SUMMARY_SUM, SUMMARY_AVG, SUMMARY_MIN, SUMMARY_MAX, SUMMARY_COUNT (los valores no vacíos), de lo que aportan sus hijos hasta las hojas, en negrita; SUMMARY_NONE (""): ninguno. of_get_field lee el total, una ordenación lo usa; SUMMARY_COUNT se escribe como número simple, nunca por is_format; SUMMARY_MIN y SUMMARY_MAX comparan también fechas |
ib_summary_over_value | boolean | false | false: una rama que tiene su propio valor en la columna lo conserva (y lo hace subir); true: el total ocupa su lugar |
il_accent | long | -1 | Acento del encabezado: su flecha de ordenación y el anillo del teclado lo toman (-1 = el del componente) |
il_back_color | long | -1 | Fondo del encabezado, en RGB(r,g,b) (-1 = lo que da el tema) |
il_text_color | long | -1 | Color del texto del encabezado (-1 = lo que da el tema) |
il_back_color_hover | long | -1 | Fondo del encabezado bajo el puntero (-1 = lo que da el tema) |
il_text_color_hover | long | -1 | Color del texto del encabezado bajo el puntero (-1 = lo que da el tema) |
is_tooltip | string | "" | Tooltip simple mostrado al pasar el ratón por el encabezado de la columna |
is_super_tooltip_title | string | "" | Título del tooltip enriquecido del encabezado (prevalece sobre is_tooltip) |
is_super_tooltip_text | string | "" | Texto del tooltip enriquecido del encabezado (se acepta el marcado enriquecido) |
is_super_tooltip_image | string | "" | Imagen del tooltip enriquecido del encabezado |
Constantes #
Están en u_pbt_treeview: u_pbt_treeview.CHECK_MIXED.
| Constante | Valor | Significado |
|---|---|---|
SUMMARY_NONE | "" | Sin total — el predeterminado |
SUMMARY_SUM | "sum" | La suma |
SUMMARY_AVG | "avg" | La media de las hojas |
SUMMARY_MIN | "min" | El valor más pequeño |
SUMMARY_MAX | "max" | El valor más grande |
SUMMARY_COUNT | "count" | El número de valores no vacíos |
SELECT_SINGLE | "single" | Un nodo seleccionado a la vez — el predeterminado |
SELECT_MULTIPLE | "multiple" | Varios, con Ctrl y Mayús |
SELECT_NONE | "none" | Ninguno: solo se mueve un foco |
SORT_ASC | "asc" | Ascendente |
SORT_DESC | "desc" | Descendente |
SORT_NONE | "none" | Sin ordenación: el orden de adición |
CHECK_ON | "on" | Marcado (con la cascada: todo el subárbol) |
CHECK_OFF | "off" | No marcado |
CHECK_MIXED | "mixed" | Parte de los hijos marcada |
ALIGN_START | "start" | Al inicio de la lectura — el predeterminado |
ALIGN_CENTER | "center" | En el centro |
ALIGN_END | "end" | Al final de la lectura (los números) |
ROLE_KEY | "key" | La clave del nodo (un identificador); sin ella, el RowID |
ROLE_PARENT | "parent" | La clave del nodo que lo contiene; con una columna ROLE_KEY, nunca un RowID |
ROLE_TEXT | "text" | Su texto (mostrado como texto) |
ROLE_IMAGE | "image" | Su imagen |
ROLE_CHECKED | "checked" | Marcado cuando el valor dice sí (1, -1, true, y, yes, on, t, o; no: 0, false, n, no, off, f, sin distinguir mayúsculas); reescrito como la columna ya lo escribe; bajo la cascada, solo se lee para una hoja: un padre es allí el estado de sus hijos |
ROLE_BADGE | "badge" | Su insignia |
ROLE_EXPANDED | "expanded" | Abierto al cargar cuando el valor dice sí |
ROLE_HAS_CHILDREN | "has_children" | La fila promete hijos cuando el valor dice sí: un chevron, y ue_children_needed al abrirse el nodo; se lee una vez, al crear el nodo |
ROLE_STATE_IMAGE | "state_image" | Su imagen de estado |
ROLE_OVERLAY_IMAGE | "overlay_image" | Su imagen superpuesta |
EXPORT_ALL | "all" | Exportación: todos los nodos, ramas cerradas incluidas — el predeterminado |
EXPORT_SHOWN | "shown" | Exportación: las filas en pantalla |
REASON_INSECURE | "insecure" | Una dirección http:// |
REASON_NOT_FOUND | "notfound" | Un archivo no encontrado |
REASON_UNC | "unc" | Una ruta de red venida de una columna de DataStore, rechazada antes de toda petición |
Métodos #
| Método | Función | |
|---|---|---|
of_add_node (string as_keys, string as_text) | Añade un nodo en su dirección, al final de su padre: "europe" arriba, "europe/france" dentro de "europe" (añadido primero). as_text acepta etiquetas ("" muestra la clave). Devuelve 0 una vez añadido, -5 para una dirección con un nivel vacío, una clave con ` | o que empieza por __, una dirección ya ocupada, un padre desconocido (of_get_last_error dice cuál), -2` cuando el componente no está creado |
of_add_node (string as_keys, string as_text, string as_image) | Lo mismo con su imagen (is_image del handle). Devuelve 0 una vez añadido, -5 como arriba, -2 cuando el componente no está creado | |
of_insert_node (string as_keys, string as_text, string as_image, long al_position) | Añade un nodo en un lugar entre los hijos de su padre, desde 1 (más allá del último: al final). Devuelve 0 una vez añadido, -5 como of_add_node, -2 cuando el componente no está creado | |
of_remove_node (string as_keys) | Quita un nodo y todo lo que contiene (sus handles se liberan). Quitar el nodo seleccionado pasa la selección a lo que lo contenía (ue_selection_changed). El nodo de una fila de DataStore sigue fuera hasta el próximo of_from_datastore: ni of_map ni la relectura de otra fila lo traen de vuelta, of_reload_row de su fila sí. Devuelve 0 una vez quitado, -5 para una dirección que el árbol no contiene, -2 cuando el componente no está creado | |
of_move_node (string as_keys, string as_to_parent_keys, long al_position) | Mueve un nodo con su subárbol bajo otro padre ("" = arriba), a un lugar desde 1 (más allá del último: al final) — o a otro lugar entre sus hermanos. Su dirección cambia: los handles tomados en la antigua dirección se liberan con esta llamada, en el acto; un handle tomado después en la nueva sigue siendo válido (un movimiento entre los mismos hermanos no libera nada). Con ib_veto_changes, primero se plantea ue_node_moving, con el lugar final; con ib_write_back, un nodo de fila que cambia de padre lo escribe antes de moverse (un movimiento entre los mismos hermanos no escribe nada). Sigue ue_node_moved, como para un arrastre. Lo que escribe se juzga de nuevo tras ue_node_moving; si el nodo no se mueve, lo escrito se repone. Devuelve 0 (también cuando ya está ahí: no se pregunta, escribe ni lanza nada), -4 si la aplicación rechaza o si el DataStore rechaza el valor (ue_write_back_failed), -5 para un nodo o un padre desconocido, un movimiento a su propio subárbol, una clave ya ocupada bajo el nuevo padre, con ib_write_back un nodo de fila bajo un nodo añadido a mano o bajo una fila sin valor de clave, un nodo de un lote fuera de su lote o cuyo DataStore se recargó para otro nodo, una hoja de un árbol agrupado en otro lugar que bajo un grupo del último nivel, un nodo de grupo, un nodo que se movió o se fue durante ue_node_moving, -2 cuando el componente no está creado | |
of_clear ( ) | Vacía el árbol: nodos, handles y filas leídas (el DataStore sigue enlazado para un nuevo of_from_datastore); las columnas y las opciones se quedan. Sigue ue_selection_changed si había nodos seleccionados. Las columnas conservan sus colores y tooltips. Las imágenes de los niveles (of_set_level_image) también se quedan. Devuelve 0 una vez aplicado, -2 cuando el componente no está creado | |
of_node (string as_keys) | El handle n_pbt_treeview_node de un nodo, por su dirección (creado en el primer acceso): su texto, imagen, marca, estados, colores y tooltip; una dirección imposible (nivel vacío, ` | , __`) devuelve un handle inerte, que no lee ni escribe nada |
of_edit_node (string as_keys) | Abre el texto de un nodo en edición desde su código — el EditLabel de un TreeView de PowerBuilder. Primero se selecciona el nodo (en SELECT_NONE, solo se trae a la vista), después se abre el campo; el final es del usuario (Intro: ue_node_editing, luego ue_node_edited; Esc o of_cancel_edit devuelve el texto). Funciona con ib_editable = false, en un nodo de solo lectura o atenuado. Devuelve 0 una vez abierto el campo, -5 para un nodo que el árbol no tiene o no puede dibujar, un árbol atenuado, un nodo de grupo de is_group_by o una fila cuyo DataStore no tiene columna ROLE_TEXT con ib_write_back (of_get_last_error dice cuál), -4 cuando ue_selection_changing (o ue_node_toggling) rechazó, -2 cuando el componente no está creado | |
of_cancel_edit ( ) | Cierra el campo de una edición en curso (abierta por el usuario o por of_edit_node) y devuelve el texto, como Esc: no se lanza nada. Devuelve 0 una vez aplicado (ninguna edición en curso: 0, nada cambia), -2 cuando el componente no está creado | |
of_expand_all ( ) | Abre todos los nodos que tienen hijos (una rama solo prometida sigue cerrada: no se pide nada). Sigue ue_node_toggled para cada uno, luego ue_layout_changed una vez. Devuelve 0 una vez aplicado, -4 cuando ue_node_toggling rechazó alguno, -2 cuando el componente no está creado | |
of_collapse_all ( ) | Cierra todos los nodos. Sigue ue_node_toggled para cada uno de los que estaban abiertos, luego ue_layout_changed una vez. Devuelve 0 una vez aplicado, -4 cuando ue_node_toggling rechazó alguno, -2 cuando el componente no está creado | |
of_expand_all (string as_keys) | Abre un nodo y todo nodo bajo él que tiene hijos (el ExpandAll(handle) de PowerBuilder); "" = todo el árbol. Devuelve 0 una vez aplicado, -4 cuando ue_node_toggling rechazó alguno, -5 para un nodo que el árbol no contiene, -2 cuando el componente no está creado | |
of_collapse_all (string as_keys) | Cierra un nodo y todo nodo bajo él; "" = todo el árbol. Devuelve 0 una vez aplicado, -4 cuando ue_node_toggling rechazó alguno, -5 para un nodo que el árbol no contiene, -2 cuando el componente no está creado | |
of_expand_to_level (long al_level) | Muestra el árbol hasta un nivel: los niveles por encima de al_level se abren, este nivel y los siguientes se cierran (1: solo se ve la parte de arriba). Una rama cuya promesa no ha tenido respuesta se queda cerrada. ue_node_toggled para cada nodo cambiado, luego ue_layout_changed. Devuelve 0 una vez aplicado, -4 cuando ue_node_toggling rechazó alguno, -5 para un nivel por debajo de 1, -2 cuando el componente no está creado | |
of_set_level_image (integer ai_level, string as_image, string as_expanded_image) | La imagen de todo nodo de un nivel (1 = arriba) que no tiene una propia — el SetLevelPictures de PowerBuilder, práctico para un árbol agrupado: as_image, y as_expanded_image mientras el nodo está abierto ("" conserva as_image). Dos "" quitan las imágenes del nivel. Devuelve 0 una vez fijado, -5 para un nivel por debajo de 1, -2 cuando el componente no está creado | |
of_clear_children (string as_keys) | Quita los hijos de un nodo (sus handles se liberan; un nodo de fila sigue fuera hasta el próximo of_from_datastore) y conserva el nodo, que promete de nuevo: su próxima apertura lanza ue_children_needed — el «actualizar» de una carpeta. Abierto, se cierra (ue_node_toggled). Cierra sin preguntar ue_node_toggling, y sigue ue_layout_changed. Devuelve 0 una vez aplicado, -5 para un nodo que el árbol no contiene, -2 cuando el componente no está creado | |
of_scroll_to_node (string as_keys) | Muestra un nodo: lo que lo contiene se abre (ue_node_toggled para cada uno, del más exterior al más interior), luego el árbol se desplaza hasta que está a la vista. La selección no cambia. Un nodo que el árbol no podría dibujar se rechaza antes de que nada se abra. Devuelve 0 una vez aplicado, -5 para un nodo que el árbol no contiene o no dibuja (oculto o contenido en uno oculto, más allá del límite demo, descartado por la búsqueda; of_get_last_error dice cuál), -4 si ue_node_toggling rechaza abrir un nodo que lo contiene (ib_veto_toggle), -2 cuando el componente no está creado | |
of_select_node (string as_keys) | Selecciona un nodo solo, como un clic: lo que lo contiene se abre (una rama prometida plantea su pregunta), el foco va a él y entra en la vista; sigue ue_selection_changed (ya seleccionado solo: no se lanza nada). Un nodo desactivado también se selecciona: lo desactivado detiene al usuario, no a su código. El nodo se juzga primero: un árbol abre para seleccionar, como el TreeView de Windows, pero nada se abre para un nodo rechazado. Con los dos vetos, se preguntan primero las aperturas (ue_node_toggling), luego la selección (ue_selection_changing). Devuelve 0 una vez seleccionado, -5 para un nodo que el árbol no contiene o no dibuja (oculto o contenido en uno oculto, más allá del límite demo, descartado por la búsqueda; of_get_last_error dice cuál), o cuando is_selection_mode vale SELECT_NONE, -4 si ue_selection_changing rechaza la selección (ib_veto_selection) o ue_node_toggling un nodo que abre (ib_veto_toggle), -2 cuando el componente no está creado | |
of_select_nodes (string as_keys_json) | Selecciona varios nodos a la vez — el par de of_selected_keys: as_keys_json es un array JSON de direcciones, en cualquier orden (["europe/france","asia"], la misma dirección dos veces cuenta una). Cada nodo se juzga primero (presente, y dibujable una vez abierto lo que lo contiene); luego se abre lo que los contiene, el foco y el ancla van a la última dirección nombrada, y ue_selection_changed sigue una vez. Con ib_veto_toggle, se pregunta ue_node_toggling para cada nodo que abre, luego con ib_veto_selection ue_selection_changing una vez para toda la selección. "[]" no deja nada seleccionado; en SELECT_SINGLE, una dirección como máximo. Devuelve 0 una vez seleccionados (también cuando esa selección ya está: no se lanza nada), -4 rechazado, -5 para un texto que no es un array JSON de direcciones, una dirección que el árbol no contiene o no dibuja (of_get_last_error dice cuál), más de una dirección en SELECT_SINGLE, o SELECT_NONE, -2 cuando el componente no está creado | |
of_clear_selection ( ) | No deja ningún nodo seleccionado: sigue ue_selection_changed("[]") (ya nada seleccionado: no se lanza nada). Devuelve 0 una vez aplicado, -4 si ue_selection_changing rechaza, -2 cuando el componente no está creado | |
of_selected_key ( ) | La dirección del nodo seleccionado (el que tiene el foco cuando hay varios); si no, "". Leído en directo | |
of_selected_keys ( ) | Las direcciones de todos los nodos seleccionados, en un array JSON en el orden del árbol: ["europe/france","asia"]; "[]" si ninguno. Leído en directo; se lee con n_pbt_json | |
of_checked_keys ( ) | Las direcciones de todos los nodos marcados, en un array JSON en el orden del árbol. Con ib_check_cascade, un nodo cuyo subárbol está todo marcado forma parte, un nodo mixto no. Leído en directo | |
of_check_all (boolean ab_checked) | Marca (o desmarca) todos los nodos de una vez. Una marca escrita por el código es un valor: no se lanza nada. Devuelve 0 una vez aplicado, -2 cuando el componente no está creado | |
of_sort (string as_column, string as_dir) | Ordena los nodos mostrados, en cada nivel: por una columna (su clave) o por el texto de los nodos (as_column = ""). as_dir: SORT_ASC, SORT_DESC o SORT_NONE (el orden de adición). El orden del modelo (of_keys_at, of_position) no cambia. Siguen ue_sort_changed y luego ue_layout_changed, como con un clic en un encabezado. as_column puede nombrar también un campo que ninguna columna muestra; una columna resumida ordena por sus totales, y con ib_parents_first las ramas quedan antes de las hojas. as_column "text" es el texto de los nodos, como "". Devuelve 0 una vez aplicado (también cuando la ordenación ya es esa: no se lanza nada), -5 para un nombre que no lo es (letras, cifras y _) o un sentido desconocido, -2 cuando el componente no está creado | |
of_sort (string as_sort) | Ordena por varias claves, en su orden: la primera decide, las siguientes desempatan. as_sort se escribe como lo lee el SetSort de un DataWindow — "type A, text D" (también asc y desc, sin dirección = ascendente, text = el texto de los nodos, cualquier otro nombre una columna o un campo); "" quita la ordenación. Siguen ue_sort_changed y luego ue_layout_changed. Se aceptan varios espacios entre una columna y su sentido, como en SetSort. Devuelve 0 una vez ordenado (también cuando ya es esa ordenación: no se lanza nada), -5 para un nombre que no lo es, otra dirección o una clave nombrada dos veces, -2 cuando el componente no está creado | |
of_find_node (string as_field, string as_value, string as_after_keys) | La dirección del primer nodo cuyo campo vale exactamente as_value (las mayúsculas cuentan): as_field "" = el texto del nodo, cualquier otro nombre un campo (suyo, una columna del DataStore, el total de una columna resumida). En el orden que muestra el árbol, ramas cerradas y nodos descartados por la búsqueda incluidos, nunca un nodo oculto; as_after_keys "" empieza por el primero, si no tras ese nodo: vuelva a dar la dirección encontrada para el siguiente. "" cuando no hay ninguno (of_get_last_error dice por qué cuando se rechazaron los argumentos). Parte tras el lugar de as_after_keys en el orden mostrado — también un nodo oculto; un as_after_keys desconocido, o una llamada durante una espera, devuelve "" y of_get_last_error dice por qué (esta lectura lo vacía primero). of_find_nodes los devuelve todos de una vez | |
of_find_nodes (string as_field, string as_value) | Todos los nodos cuyo campo vale exactamente as_value (las mayúsculas cuentan), en una pasada: sus direcciones como array JSON, en el orden que el árbol muestra (["europe/france","asia"]); "[]" si no hay ninguno. as_field "" es el texto del nodo, cualquier otro nombre un campo. Se recorren las ramas cerradas y los nodos que la búsqueda descarta, nunca un nodo oculto (ni, en modo demo, un nodo más allá del límite). "[]" con of_get_last_error cuando el nombre de campo no lo es o durante una espera. Léalo con n_pbt_json | |
of_search_next ( ) | Selecciona el nodo siguiente que encontró la búsqueda (is_filter), tras el nodo del foco, en bucle; F3 hace lo mismo. Como of_select_node: sigue ue_selection_changed, y con ib_veto_selection se plantea primero ue_selection_changing. En SELECT_NONE, mueve allí el foco y devuelve 0; durante una espera, devuelve -5 y of_get_last_error dice por qué. Devuelve 0 una vez seleccionado, -4 rechazado, -5 sin búsqueda o sin coincidencias, -2 cuando el componente no está creado | |
of_search_prev ( ) | Selecciona el nodo anterior que encontró la búsqueda, antes del nodo del foco, en bucle; Mayús+F3 hace lo mismo. En SELECT_NONE, mueve allí el foco y devuelve 0; durante una espera, devuelve -5 y of_get_last_error dice por qué. Devuelve 0 una vez seleccionado, -4 rechazado, -5 sin búsqueda o sin coincidencias, -2 cuando el componente no está creado | |
of_match_count ( ) | Devuelve cuántos nodos encontró la búsqueda (is_filter), leído al instante; 0 sin búsqueda | |
of_add_column (string as_key, string as_title) | Añade una columna al final: el árbol se convierte en una lista en árbol, la primera columna lleva el árbol, esta muestra el campo de la misma clave de cada nodo (of_set_field, o la columna del DataStore). Su ancho es automático. La clave text se rechaza (-5): nombra el texto de los nodos. Devuelve 0 una vez añadida, -5 para una clave que no puede serlo (vacía, con / o ` | , que empieza por __) o una columna ya presente, -2` cuando el componente no está creado |
of_add_column (string as_key, string as_title, integer ai_width) | Lo mismo con un ancho en píxeles (0 = automático; de 40 a 2000). Devuelve 0 una vez añadida, -5 como arriba, -2 cuando el componente no está creado | |
of_remove_column (string as_key) | Quita una columna (su handle se libera); ida la última, la lista vuelve a ser un árbol. Quitar la columna ordenada lanza ue_sort_changed con la clave siguiente de la ordenación — SORT_NONE cuando era la única —, luego ue_layout_changed. Devuelve 0 una vez quitada, -5 para una columna que la lista no contiene, -2 cuando el componente no está creado | |
of_clear_columns ( ) | Quita todas las columnas (sus handles se liberan): la lista vuelve a ser un árbol. Quitar la columna ordenada lanza ue_sort_changed con la clave siguiente de la ordenación — SORT_NONE cuando era la única —, luego ue_layout_changed. Devuelve 0 una vez aplicado, -2 cuando el componente no está creado | |
of_column (string as_key) | El handle n_pbt_treeview_column de una columna (creado en el primer acceso): su título, ancho, alineación, formato, visibilidad, lugar y si un clic en su encabezado ordena | |
of_set_field (string as_keys, string as_field, string as_value) | Da a un nodo un campo suyo: of_set_field("europe/france", "population", "68000000"); la columna de clave population lo muestra. Un nodo de un DataStore ya tiene cada columna como campo; un campo suyo con el mismo nombre prevalece. Un nombre de campo: letras, cifras y _, sin cifra inicial. Devuelve 0 una vez fijado, -5 para un nodo desconocido o un nombre no válido, -2 cuando el componente no está creado | |
of_get_field (string as_keys, string as_field) | Lee un campo de un nodo, en directo: uno de los suyos (of_set_field), una columna del DataStore del que viene, o un campo integrado (key, keys, text, badge, level, position, count, image). "" cuando no lo tiene; para una columna resumida (is_summary), el total bruto de la rama, un número con punto; el campo integrado count cuenta los hijos que el árbol puede dibujar | |
of_from_datastore (datastore ads) | Alimenta el árbol desde un DataStore: una fila = un nodo (ver más arriba). Los nodos de una carga anterior se van (sus handles se liberan); los nodos añadidos a mano arriba se quedan, sus handles también. Dos filas con la misma clave: la segunda toma "clave~RowID"; una clave imposible (con / o ` | , o que empieza por __): el RowID — sus hijos la siguen encontrando por su valor. Con una columna ROLE_KEY, un valor de padre nombra una clave, nunca un RowID. Fechas y números se leen sea cual sea la configuración regional (fecha yyyy-mm-dd, hh:mm:ss, número con punto). Lo que la carga tuvo que corregir (padres ausentes, bucles, claves duplicadas o imposibles) lo dice of_get_last_error, y el retorno sigue siendo 0. Con is_group_by, las filas son las hojas de grupos (ROLE_PARENT no desempeña ningún papel). Una nueva carga se lleva los lotes colgados bajo sus filas y conserva los colgados bajo un nodo añadido a mano. Una nueva carga solo libera los handles de lo que sustituye (un nodo añadido a mano, un handle inerte, una dirección aún no creada conservan el suyo); un nodo de fila movido sin ib_write_back vuelve al lugar que dice su fila. El informe de of_get_last_error cuenta también los nodos añadidos a mano subidos arriba (lifted=N) y los lotes que se fueron con su nodo (lots=N). Devuelve 0 una vez cargado, -5 cuando el DataStore no es válido, no tiene ninguna columna o le falta una columna nombrada por of_map (of_get_last_error la nombra), -2` cuando el componente no está creado |
of_from_datastore (datawindow adw) | Lo mismo desde las filas de un DataWindow: el árbol escribe en ese DataWindow (ib_write_back), el que el usuario ve al lado. Sus datos se comparten con un DataStore de paso: una DataWindow que no puede compartirlos se rechaza (-5, con el motivo). Devuelve 0 una vez cargado, -5 como arriba, -2 cuando el componente no está creado | |
of_from_datastore (datawindowchild adwc) | Lo mismo desde las filas de un DataWindowChild (un DataWindow desplegable, un informe anidado): el árbol escribe en él. Devuelve 0 una vez cargado, -5 como arriba, -2 cuando el componente no está creado | |
of_from_datastore (datastore ads, string as_parent_keys) | Un lote: las filas de un DataStore se convierten en los hijos del nodo as_parent_keys, el resto del árbol no se mueve — lo que ue_children_needed hace en una sola llamada. Un rol se resuelve para cada DataStore: la columna de of_map(ads, …) para este, si no la de of_map cuando la tiene, si no la columna que lleva el nombre del rol; ROLE_PARENT nombra una fila del mismo lote (vacío o desconocido: el propio nodo). El mismo DataStore dado de nuevo bajo el mismo nodo sustituye su lote (sus handles se liberan), otro añade el suyo; of_row de un nodo del lote es su fila en ese DataStore, e ib_write_back escribe allí. Una clave ya ocupada bajo el nodo toma "clave~RowID". Un DataStore por lote: recargado para otro nodo (Reset, Retrieve — PowerBuilder vuelve a dar los mismos RowID), se lleva sus filas al nuevo lote, y los nodos del lote anterior conservan lo que muestran sin fila (of_row 0, un movimiento por código -5, una escritura rechazada con ue_write_back_failed; la carga cuenta stale=N). Para refrescar un lote desde otro objeto DataStore, primero of_clear_children. Devuelve 0 una vez cargado, -5 cuando el DataStore no es válido, no tiene ninguna columna, le falta una columna nombrada para él por of_map(ads, …), o as_parent_keys está vacío (la cima del árbol es of_from_datastore(ads)) o no es un nodo del árbol, -2 cuando el componente no está creado | |
of_from_datastore (datawindow adw, string as_parent_keys) | Un lote desde las filas de un DataWindow (ver arriba). Devuelve 0 una vez cargado, -5 como arriba, -2 cuando el componente no está creado | |
of_from_datastore (datawindowchild adwc, string as_parent_keys) | Un lote desde las filas de un DataWindowChild. Devuelve 0 una vez cargado, -5 como arriba, -2 cuando el componente no está creado | |
of_row_keys (long al_row) | La dirección del nodo de una fila del DataStore de of_from_datastore (el principal, no un lote), por su número de fila de hoy: quite el nodo (of_remove_node) antes del DeleteRow. "" cuando la fila no tiene nodo (quitado, nunca cargado, no hay tal fila). "" también una vez que el DataStore principal se dio de nuevo como lote, hasta la próxima carga principal | |
of_map (string as_role, string as_column) | Da un rol (ROLE_KEY, ROLE_PARENT, ROLE_TEXT…) a una columna del DataStore cuando su nombre no lo dice: of_map(ROLE_PARENT, "manager_id"). El rol vale para cada DataStore que tiene esa columna: un lote leído de un DataStore que no la tiene toma la columna que lleva el nombre del rol, y of_map(ads, …) da a un DataStore sus propios roles. Antes o después de of_from_datastore: después, las filas se vuelven a leer, y lo que se puso en los nodos se queda. "" como columna devuelve el rol a la columna que lleva su nombre. Un nuevo ROLE_KEY o ROLE_PARENT da nuevas direcciones: solo se liberan los handles de los nodos cuya dirección cambió, los demás siguen siendo válidos. Los roles dados se quedan para los siguientes of_from_datastore, incluso tras of_clear; solo of_reset los olvida. Su relectura de las filas dice lo que tuvo que corregir, para todas las fuentes, en of_get_last_error. Devuelve 0 una vez fijado, -5 cuando el rol no es una constante ROLE_ o la columna no es del DataStore del último of_from_datastore, -2 cuando el componente no está creado | |
of_map (datastore ads, string as_role, string as_column) | Da un rol a una columna solo para este DataStore: el lote de departamentos y el de empleados de un mismo árbol nombran cada uno su clave y su texto. Va antes de of_map(as_role, as_column) para este DataStore; "" devuelve el rol. Antes o después de of_from_datastore: después, las filas se vuelven a leer, lo que se puso en los nodos se queda. Devuelve 0 una vez fijado, -5 cuando el DataStore no es válido, el rol no es una constante ROLE_ o el DataStore no tiene esa columna, -2 cuando el componente no está creado | |
of_map (datawindow adw, string as_role, string as_column) | Lo mismo para las filas de un DataWindow dado a of_from_datastore. Devuelve 0 una vez fijado, -5 para un argumento rechazado, -2 cuando el componente no está creado | |
of_map (datawindowchild adwc, string as_role, string as_column) | Lo mismo para las filas de un DataWindowChild dado a of_from_datastore. Devuelve 0 una vez fijado, -5 para un argumento rechazado, -2 cuando el componente no está creado | |
of_reload_row (long al_row) | Vuelve a enviar al árbol una fila del DataStore de of_from_datastore, leída ahora: después de que su código la haya cambiado (SetItem, una ventana de edición). al_row es el número de fila de hoy; el nodo sigue a la fila en el sitio: lo que se le puso (abierto, desactivado, visible, campos, colores) se queda, no se lanza nada. Una fila cuya clave o padre cambió mueve su nodo (los handles de lo que se movió se liberan, los demás siguen siendo válidos); una fila que el árbol aún no tiene (InsertRow) llega también, en su rango entre sus hermanos; la fila de un nodo quitado por of_remove_node vuelve. Cada valor se escribe como lo escribe la carga. Solo se relee el DataStore principal, no un lote (vuelva a darlo); en un árbol agrupado, una fila cuyo valor de grupo cambió va a su nuevo grupo. Una vez que el DataStore principal se dio de nuevo como lote, devuelve -5 hasta la próxima carga principal; una fila cuyo padre o grupo cambia mueve su nodo en el sitio. Devuelve 0 una vez enviada, -5 cuando no hay ningún DataStore vinculado, el árbol se vació con of_clear desde la carga, o la fila no existe, -2 cuando el componente no está creado | |
of_export_csv (string as_path) | Escribe el árbol en un archivo CSV (UTF-8, punto y coma) con su jerarquía: el texto de un nodo en la celda de su nivel, las columnas después del nivel más profundo, primero una línea de encabezado; un número en bruto, con la marca decimal del idioma de visualización. is_export_scope dice qué nodos; ue_csv_saved lo confirma; una ruta relativa se escribe en la carpeta de inicio de la aplicación. Rechazado en modo demo. Devuelve 0 una vez pedido, -5 cuando la ruta está vacía, -2 cuando el componente no está creado | |
of_export_xlsx (string as_path) | Escribe el árbol en un libro de Excel (.xlsx): el texto de un nodo en la primera columna, sangrado según su nivel y agrupado bajo su padre (los niveles de esquema de Excel: cada rama se pliega con el + / - del margen, hasta 7 niveles, todo escrito abierto), las columnas después, los números siguen siendo números (con el formato de su columna cuando es una máscara numérica). is_export_scope dice qué nodos; ue_xlsx_saved lo confirma. Rechazado en modo demo. Devuelve 0 una vez pedido, -5 cuando la ruta está vacía, -2 cuando el componente no está creado | |
of_get_layout ( ) | Lo que el usuario ha dispuesto, en JSON: {"columns":[{"key":"","width":260,"visible":true},…],"sort":{"column":"","dir":"none"},"expanded":["europe"]} — primero la columna del árbol (clave ""), luego cada columna en su orden con su ancho (0 = automático) y su visibilidad, la ordenación, los nodos abiertos. Para guardar (archivo, registro, base de datos) y devolver luego a of_set_layout. Leído en directo. Lleva también "sorts" (todas las claves de la ordenación), "selected" (los nodos seleccionados) y "top" (el nodo arriba de la vista, nunca píxeles) | |
of_set_layout (string as_layout_json) | Vuelve a poner una disposición leída por of_get_layout o recibida por ue_layout_changed: anchos, orden y visibilidad de las columnas, ordenación, y qué nodos están abiertos (los que no nombra se cierran). Una columna o un nodo que nombra y que el árbol no contiene se ignora. ue_layout_changed se lanza una vez cuando algo ha cambiado (ni ue_node_toggled ni ue_sort_changed: vuelve a poner un estado). Devuelve también la selección (ue_selection_changed si cambió, no se pregunta nada) y desplaza hasta el nodo de arriba. Una dirección que pide abierta en una rama aún sin respuesta se recuerda: se abre sola cuando la respuesta de su rama la trae (ue_node_toggled, luego ue_layout_changed); ue_selection_changed se lanza una sola vez. Las preguntas de ib_veto_selection e ib_veto_toggle no se plantean: vuelve a poner un estado, normalmente al inicio. Una rama prometida que ya contiene un nodo no se abre sobre la mitad de su contenido: pide primero ue_children_needed. Devuelve 0 una vez aplicado, -5 cuando el texto está vacío o no es un objeto JSON, -2 cuando el componente no está creado |
Eventos #
| Evento | Se activa cuando |
|---|---|
ue_node_clicked (string as_keys) | Se hizo clic en un nodo (y se seleccionó, salvo en SELECT_NONE). Un clic en el chevron o en la casilla no lo lanza; un nodo desactivado no lanza nada |
ue_node_opened (string as_keys) | Un doble clic en un nodo, o Intro: abra su editor para él. Un doble clic en una rama también la abre o la cierra (ue_node_toggled) |
ue_node_rclicked (string as_keys, long al_x, long al_y) | Un clic derecho en un nodo (seleccionado primero, salvo si ue_selection_changing lo rechaza o en SELECT_NONE: actúe sobre as_keys, nunca sobre of_selected_key), o la tecla de menú (o Mayús + F10) en el nodo que tiene el foco. al_x, al_y son píxeles de pantalla — el punto del clic, o la esquina inferior izquierda del nodo para la tecla de menú —, los que toma un contextmenu: uo_menu.of_show(al_x, al_y); para un menú PowerBuilder, PopMenu(PointerX(), PointerY()) de su ventana |
ue_node_toggled (string as_keys, boolean ab_expanded) | Un nodo se abrió (ab_expanded = true) o se cerró: su chevron, un doble clic, el teclado, o su código (ib_expanded, of_expand_all, of_collapse_all, y lo que abren of_select_node u of_scroll_to_node); una apertura hecha durante ue_children_needed lo lanza una sola vez; of_expand_to_level, of_clear_children (que cierra) y una rama que of_set_layout recordó también lo lanzan |
ue_selection_changed (string as_keys_json) | La selección cambió: un clic, el teclado, su código (of_select_node, of_clear_selection), o nodos seleccionados que salieron de la pantalla (rama cerrada, nodo quitado u oculto, nodo escondido por la búsqueda — lo que lo contiene no se selecciona en su lugar). as_keys_json es el array JSON de las direcciones seleccionadas, en el orden del árbol: ["europe/france", "asia"] |
ue_node_checked (string as_keys, boolean ab_checked) | El usuario marcó (ab_checked = true) o desmarcó un nodo: su casilla, o Espacio. Con ib_check_cascade, todo su subárbol sigue, ya en su sitio cuando llega el evento. Una marca escrita por su código no lanza nada. Una marca del usuario salta un nodo desactivado y su subárbol |
ue_children_needed (string as_keys) | Una rama prometida por ib_has_children se abre y aún no contiene sus hijos: añádalos ahora (of_add_node); la rama se abre con ellos al retorno del evento, después del retorno de la línea que la abrió. La promesa vale hasta esta respuesta, aunque se haya añadido o soltado un nodo en ella; bajo una hoja marcada, cada hijo añadido toma su marca. No añada nada, y la promesa se retira (el chevron desaparece) |
ue_node_editing (string as_keys, string as_text) → boolean | Cancelable, planteado antes de que se guarde un texto tecleado por el usuario, solo cuando ib_veto_changes = true. Devolver FALSE rechaza: el nodo conserva su texto. Por defecto: TRUE |
ue_node_edited (string as_keys, string as_text, string as_old_text) | El usuario renombró un nodo (F2, o un segundo clic lento con ib_editable). El nodo ya muestra as_text; as_old_text es el que tenía. Con ib_write_back, el DataStore ya está escrito |
ue_node_moving (string as_keys, string as_to_parent_keys, long al_position) → boolean | Cancelable, planteado antes de que un nodo se mueva (un arrastre u of_move_node), solo cuando ib_veto_changes = true. as_to_parent_keys vale "" para arriba, al_position su lugar final allí, desde 1, limitado a los hermanos — el que dirá ue_node_moved. Un nodo que ya está en su lugar no pregunta nada. Devolver FALSE rechaza: nada se mueve, y of_move_node devuelve -4. Un of_move_node del mismo nodo hecho en el evento no se vuelve a preguntar: se aplica, y el of_move_node que planteaba la pregunta devuelve entonces -5; otro nodo se pregunta con normalidad. Por defecto: TRUE |
ue_node_moved (string as_keys, string as_old_keys, long al_position) | Un nodo se ha movido con su subárbol: un arrastre del usuario u of_move_node. as_keys es su nueva dirección, as_old_keys la que tenía, al_position su lugar bajo su nuevo padre (desde 1). Los handles tomados en la antigua dirección ya están liberados (of_move_node los libera en el acto, un arrastre antes de este evento); un handle tomado en la nueva sigue siendo válido |
ue_sort_changed (string as_column, string as_dir, string as_sort) | La ordenación cambió: un clic en un encabezado u of_sort. as_column es su primera clave ("" para el texto de los nodos), as_dir su dirección (una de las constantes SORT_), as_sort la ordenación entera escrita como la lee el SetSort de un DataWindow ("type A, text D", "" sin ordenación). Quitar la columna ordenada lo lanza con la clave siguiente de la ordenación, SORT_NONE cuando era la única |
ue_layout_changed (string as_layout_json) | La disposición ha cambiado: ancho u orden de una columna, ordenación, un nodo abierto o cerrado, u of_set_layout. as_layout_json es la disposición entera, como la devuelve of_get_layout. Un ancho, un lugar o una visibilidad de columna escritos por su código también lo lanzan, cuando la disposición cambia; título, formato, alineación, ordenación permitida y total siguen mudos |
ue_write_back_failed (string as_keys, string as_col, string as_value, string as_reason) | ib_write_back: el DataStore rechazó un valor (un tipo que no puede contener, una fila borrada desde la carga), o ya no hay DataStore (as_reason = no DataStore is bound). El nodo volvió (as_keys es la dirección que tiene de nuevo); el evento del gesto no se lanza. as_reason dice también cuando el lote del nodo se recargó para otro nodo, o cuando la columna de marca lleva valores que no son ni un sí ni un no |
ue_image_failed (string as_keys, string as_reason) | La imagen de un nodo no pudo mostrarse: as_reason vale REASON_INSECURE (una dirección http://), REASON_UNC (una ruta de red venida de una columna de DataStore) o REASON_NOT_FOUND (archivo no encontrado). Dicho una vez por nodo y por imagen |
ue_selection_changing (string as_from_keys_json, string as_keys_json) → boolean | Cancelable, planteado antes de que el usuario elija otra selección (un clic, el teclado, F3) y antes de of_select_node, of_clear_selection, of_search_next / of_search_prev, solo cuando ib_veto_selection = true. as_from_keys_json es la selección actual, as_keys_json la pedida (arrays JSON de direcciones). Devolver FALSE rechaza: nada se mueve, ni siquiera el foco del teclado, y el método devuelve -4. Lo que sale de la selección como consecuencia (rama cerrada, retirada, nodo oculto, búsqueda) no se pregunta. of_select_nodes pregunta una vez para toda la selección. Para llevar al usuario a otro sitio, seleccione dentro del evento y luego devuelva FALSE: una selección hecha dentro del evento no se vuelve a preguntar. Por defecto: TRUE |
ue_node_toggling (string as_keys, boolean ab_expanding) → boolean | Cancelable, planteado antes de que un nodo se abra (ab_expanding = true) o se cierre, solo cuando ib_veto_toggle = true: un gesto (chevron, doble clic, teclado, *, la barra de herramientas, una rama bajo un arrastre) y su código (ib_expanded, of_expand_all, of_collapse_all, of_expand_to_level — una pregunta por nodo —, of_select_node y of_scroll_to_node para los nodos que abren). Devolver FALSE rechaza: el nodo se queda como está, y un método devuelve -4. Las hermanas que cierra ib_single_expand no se preguntan. Por defecto: TRUE. of_clear_children cierra sin preguntar |
ue_delete_requested (string as_keys_json) | El usuario pulsó Supr: as_keys_json es el array JSON de los nodos seleccionados (en SELECT_NONE, el del foco; sin selección, si no, no se lanza nada), ni desactivados ni de solo lectura. El árbol no quita nada: llame a of_remove_node para lo que su aplicación borra |
ue_copy (string as_tsv) | El usuario pulsó Ctrl+C (o Ctrl+Insert): as_tsv contiene los nodos seleccionados (en SELECT_NONE, el del foco; sin selección, si no, no se lanza nada) en el orden del árbol, uno por línea, el texto tras tantas tabulaciones como su profundidad, luego las columnas de una lista en árbol alineadas (primero una línea de encabezado), un número bruto (un punto, sin agrupación ni símbolo). El árbol intenta también el portapapeles del navegador, que se le puede negar a una página: ClipBoard(as_tsv) para estar seguro |
ue_drop_files (string as_keys, string as_files[]) | Se soltaron archivos desde el Explorador sobre un nodo (ib_allow_drop): as_keys es la dirección del nodo bajo el cursor — vacía para una soltada junto a los nodos, sobre un nodo desactivado o sobre un nodo cuyo ib_drop_target vale false —, as_files las rutas completas |
ue_state_clicked (string as_keys) | El usuario hizo clic en la imagen de estado de un nodo (is_state_image): una bandera, un estado que su aplicación enciende y apaga. El nodo no se selecciona, como con su casilla; un nodo atenuado no lanza nada. Se lanza solo para un gesto |
ue_csv_saved (string as_path, boolean ab_ok, string as_error) | El CSV pedido por of_export_csv se escribió (ab_ok = true) — o no: as_error dice por qué (el modo demo, una ruta que no se puede escribir). as_path es la ruta escrita, una relativa resuelta |
ue_xlsx_saved (string as_path, boolean ab_ok, string as_error) | El libro pedido por of_export_xlsx se escribió (ab_ok = true) — o no: as_error dice por qué |
ue_drag_enter ( ) | Un arrastre de archivos desde el Explorador entró en el componente (ib_allow_drop) |
ue_drag_leave ( ) | El arrastre de archivos salió sin soltar nada — una soltada lanza solo ue_drop_files |
ue_ready ( ) | El componente ha terminado de cargarse; todo lo enviado antes se ha reproducido |
ue_runtime_missing ( ) | El runtime WebView2 está ausente: el componente permanece vacío |
ue_bg_color (long al_color) | El componente ha calculado el color de fondo de su tema; el userobject ya lo ha adoptado (backcolor) |
Teclado y ratón #
- Clic en un nodo: queda seleccionado (
ue_node_clicked); en su chevron: se abre o se cierra; en su casilla: queda marcado; doble clic:ue_node_opened, y una rama se abre o se cierra; clic derecho:ue_node_rclicked. EnSELECT_MULTIPLE, Ctrl + clic añade o quita un nodo, Mayús + clic toma el rango desde el último. - Arriba / Abajo: el nodo anterior, el siguiente; Inicio / Fin: el primero, el último; Re Pág / Av Pág: de una pantalla. Los nodos desactivados se saltan.
- Derecha abre el nodo, luego baja a su primer hijo; Izquierda lo cierra, luego sube a su padre — invertidas en una aplicación de derecha a izquierda.
*del teclado numérico abre todo el subárbol;+/-del teclado numérico abren y cierran — los del teclado principal se teclean, para llegar a «+1.2» o «-Débitos». - Espacio marca el nodo (con
ib_checkboxes), si no lo selecciona; Intro:ue_node_opened; F2: renombrar (conib_editable); tecla Menú o Mayús + F10:ue_node_rclicked. - En
SELECT_MULTIPLE, Mayús + flechas amplían la selección, Ctrl + flechas solo mueven el foco, Ctrl + Espacio añade o quita el nodo del foco, Ctrl + A selecciona todos los nodos mostrados (una sola pregunta conib_veto_selection). - Las primeras letras de un texto seleccionan el nodo mostrado que empieza por ellas, como una flecha (en
SELECT_NONE, solo llevan el foco a él). - Supr:
ue_delete_requested(el árbol no quita nada); Ctrl+C o Ctrl+Insert:ue_copy; F3 / Mayús+F3: la coincidencia siguiente / anterior de la búsqueda (enSELECT_NONE, el foco va allí), desde el árbol o desde el campo de búsqueda, donde Intro hace lo mismo. Supr y Ctrl+C actúan sobre el nodo del foco solo enSELECT_NONE. - El encabezado de una lista en árbol es una parada de la tecla Tab: Izquierda / Derecha van de encabezado en encabezado (invertidas en una aplicación de derecha a izquierda), Inicio / Fin al primero y al último, Intro o Espacio ordena, Ctrl + Izquierda / Derecha estrecha o ensancha la columna 10 píxeles, Ctrl + Mayús + Izquierda / Derecha la mueve, Abajo pasa a las filas.
- Arrastrar un nodo (con
ib_drag_drop): un fantasma sigue al puntero, una barra muestra dónde caerá antes o después, un marco cuando cae dentro; Esc cancela. Arrastrar el borde de un encabezado ensancha la columna, arrastrar el encabezado la mueve — un fantasma y una barra de inserción muestran dónde, Esc cancela —, hacer clic en el encabezado ordena. Un arrastre cuyo botón soltado el árbol no ve — la ventana pierde el foco (Alt+Tab, un cuadro de mensaje) — se cancela: nada se mueve, un ancho vuelve. - El árbol es una parada de la tecla Tab (más el encabezado de una lista en árbol, el campo y los botones de la barra de herramientas); un anillo punteado del color del texto marca el nodo que tiene el foco. Un árbol desactivado no toma el foco.
Ejemplos #
Permisos que marcar #
// 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
Recuperar la disposición en el próximo inicio #
// 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 menú sobre un nodo #
// 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
Buenas prácticas #
- Claves estables: un identificador, no una etiqueta — el texto se renombra, la clave se queda.
of_keys_atdevuelve direcciones completas, para pasar tal cual aof_node. Una disposición guardada de un inicio a otro (of_get_layout) exige una columnaROLE_KEY: sin ella, las claves de las filas son sus RowID, que un nuevoRetrieveda a otras filas. - Ramas a petición en cuanto el árbol es grande o costoso de leer:
ib_has_childrenyue_children_neededsolo leen lo que el usuario abre. - Un DataStore por lote: recargado para otro nodo, un DataStore se lleva sus filas — y PowerBuilder sus RowID — del lote anterior, cuyos nodos ya no tienen fila.
- Muchos nodos: solo se dibujan las filas visibles — diez mil nodos se desplazan como veinte. Añadirlos es otra cosa: cada
of_add_nodees un mensaje al árbol, unos 0,7 ms (2.000 nodos ≈ 1,3 s medidos, 10.000 ≈ 7 s esperados); un árbol grande se carga conof_from_datastore, en un solo mensaje, o se lee a petición, un lote por rama (of_from_datastore(ads, as_parent_keys)). - Las columnas de un DataStore son identificadores tanto como valores: elija las que muestra con
of_add_column, nada se crea solo. - Una marca es un valor: puesta por su código, no lanza nada; lea
of_checked_keyscuando el usuario confirme. of_get_last_errordice por qué se rechazó la última llamada; lo vacía todo método que actúa y toda propiedad escrita, yof_find_node/of_find_nodes, que dicen por él por qué no encontraron nada.- Una orden dada durante una espera (código PowerBuilder que se ejecuta mientras el árbol espera a su página, un temporizador por ejemplo) no se comprueba de antemano: la página decide sola, y una adición o un movimiento que rechaza devuelve igualmente
0. - Durante una espera (un evento del componente que se está respondiendo), una orden de su código no se juzga de antemano:
ib_expandedyof_move_nodepasan el veto sin plantear la pregunta, yof_get_last_errorlo dice. Dé sus órdenes fuera del evento cuando el veto cuenta. of_set_layoutrestituye un estado — normalmente al inicio — sin plantear las preguntas deib_veto_selectionni deib_veto_toggle: es la excepción a la regla de que una orden del código plantea la pregunta.- Modo demo: sin clave, el árbol dibuja los 8 primeros nodos de cada nivel y 200 nodos en todo el árbol (los primeros añadidos), en el orden del modelo — antes de la ordenación, la búsqueda y la ocultación: un nodo oculto cuenta, una búsqueda o una ordenación nunca muestran el noveno, lotes y grupos incluidos, y un total nunca cuenta lo que el límite oculta; los demás se quedan en memoria, ni mostrados ni seleccionables (véase el modo demo).
Heredado de la base común #
Estos miembros existen en todos los componentes visuales — no son propios de este. Se detallan una sola vez, en los capítulos transversales; esta tabla solo dice dónde leerlos.
| Miembros | Función | Detallado en |
|---|---|---|
of_count · of_keys_at · of_has | Recorrer lo que el componente contiene | 3.2 Los items |
of_reset | Poner el componente a cero | 3.6 Poner un componente a cero: of_reset() |
of_register_shortcut · of_clear_shortcuts | Atajos de teclado del componente | 3.5 Los atajos de teclado |
of_is_created · of_is_ready · of_get_last_error | Si ha nacido, si está listo, qué ha fallado | 3.7 Diagnóstico |
of_save_as_png · of_save_as_jpg | Exportar el render como imagen | 3.8 Exportar la representación como imagen |
of_set_redraw | Agrupar los cambios en un solo repintado | 3.10 Buenas prácticas |
of_preload_icons | Iconos mostrados sin retardo | Visualización instantánea: of_icon |
of_set_translation | Traducir una etiqueta del componente | 5.2 Adaptar una etiqueta: of_set_translation |
of_focus_webview | Dar el foco al componente | 6.4 Teclado y foco |
of_print · of_print_to_pdf | Imprimir, o escribir un PDF | 6.9 Imprimir |
of_set_property · of_get_property · of_component_name | Controlar una propiedad por su nombre | 3.1 El motor de propiedades |
is_accessible_name · is_accessible_description | El nombre y la descripción que dice un lector de pantalla | 3.4 Propiedades y eventos opcionales |
Dos ayudas no se heredan: of_icon y of_escape_markup viven en n_pbt_utils. Declare uno — n_pbt_utils lnv_utils, nada que crear — y llámelas sobre él.