form — u_pbt_form #
← Referencia de componentes · Índice de la guía
form es una pantalla de entrada de datos entera en un solo control: campos tipados — texto, número, lista, botones de opción, fecha, hora, color, casilla, contraseña, correo, texto largo, imagen, etiquetas, estrellas — dispuestos en columnas y en secciones que se pliegan, cada uno con su etiqueta que sube a su borde. Las reglas de cada campo (obligatorio, límites, patrón, máscara…) y sus errores de negocio se comprueban juntos;
of_is_dirtydice qué ha cambiado desde la carga,of_load_row/of_save_rowleen y escriben una fila de un DataWindow. Su propio botón Aceptar llama aof_validate.
▶ Verlo en vivo — Aplicación de demostración, mosaico Form: la vista previa, el código que lo genera y esta página, uno al lado del otro.
De un vistazo #
| Userobject | u_pbt_form |
| Clases de items | n_pbt_form_section (sección) → n_pbt_form_field (campo) |
| Sirve para | Sustituir una pantalla de entrada hecha de decenas de controles colocados a mano por un formulario con tema que se maqueta solo y comprueba lo que se escribe: ficha de cliente, pedido, ajustes, un paso de un asistente |
| Valores | Siempre texto, uno a uno (of_field(dirección).is_value); todos a la vez y tipados con of_values; una fila de DataWindow con of_load_row / of_save_row |
| Opciones opt-in | ib_veto_changes |
Inicio rápido #
// Two columns ; a name at the top, then a section
uo_form.ii_columns = 2
uo_form.of_add_field(/*keys*/ "name", /*label*/ "Name", /*type*/ u_pbt_form.TYPE_STRING, /*value*/ "")
uo_form.of_field(/*keys*/ "name").ib_required = true
uo_form.of_add_section(/*key*/ "order", /*title*/ "Order")
uo_form.of_add_field(/*keys*/ "order/qty", /*label*/ "Quantity", /*type*/ u_pbt_form.TYPE_NUMBER, /*value*/ "1")
uo_form.of_add_field(/*keys*/ "order/due", /*label*/ "Due on", /*type*/ u_pbt_form.TYPE_DATE, /*value*/ "")
// event clicked of cb_ok
// Local variables
n_pbt_json lnv_json
// Every error shown at once, the keyboard on the first
if uo_form.of_validate() > 0 then return
// Valid : read the values, typed, along the same addresses
lnv_json.of_load(/*json*/ uo_form.of_values())
of_save_order(lnv_json.of_get_string(/*path*/ "name"), lnv_json.of_get_number(/*path*/ "order/qty"))
Una dirección por campo #
Un campo se designa por su dirección: su clave sola en el primer nivel ("name"), la sección y luego el campo unidos por / dentro de una sección ("order/qty") — un nivel, nunca más. Una sección se designa por su clave sola. En el primer nivel, una clave nombra una sola cosa: una sección y un campo de arriba no pueden compartirla. Los eventos llevan la misma dirección, la que usted escribió; la clave de un campo (su último nivel) es también el nombre de la columna que leen of_load_row y of_save_row.
// A section by its key, a field by its address
uo_form.of_section(/*key*/ "order").ib_collapsed = true
uo_form.of_field(/*keys*/ "order/qty").is_value = "3"
Los tipos de campo #
El tipo se elige una vez, en of_add_field, y da el control. El valor, en cambio, es siempre texto — dado, leído, entregado por los eventos — escrito igual sea cual sea el idioma del equipo. Una lista, una fecha y un color se abren en las ventanas nativas compartidas por toda la biblioteca, con los colores del tema.
| Constante | Control | El valor, como texto |
|---|---|---|
TYPE_STRING | Cuadro de texto; una máscara (is_mask, sintaxis de un EditMask) muestra sus literales mientras se teclea; un botón «…» (ib_ellipsis) abre su búsqueda | El texto tal cual; enmascarado, sin sus literales (5551234567) |
TYPE_TEXTAREA | Texto en varias líneas; Intro salta de línea | El texto, saltos de línea incluidos |
TYPE_NUMBER | Cuadro de texto que lee un número en el idioma de visualización: su separador decimal o un punto, su agrupación de miles bien formada (1,000 vale mil en inglés, 1.500 mil quinientos en alemán, 1 234,5 en francés). Una entrada ambigua (1,5 en inglés, 1 2) o que no es un número se queda en pantalla con el mensaje Not a number traducido, y el valor vigente no se mueve; Arriba / Abajo lo suben o lo bajan en su paso (id_step) | Con punto: "12.5"; "" = vacío. Conservado cifra a cifra; 12.50 retecleado por 12.5 no es un cambio |
TYPE_BOOLEAN | Un interruptor (por defecto) o una casilla (is_boolean_style), con su etiqueta al lado | "true" · "false" |
TYPE_ENUM | Botón que abre la lista compartida; sus opciones se añaden una a una (of_add_option) | El valor de la opción elegida, nunca su texto; un valor que ninguna opción ofrece se conserva y se muestra tal cual, como un DataWindow sin tabla de códigos |
TYPE_RADIO | Un botón de opción por opción, uno al lado del otro; las flechas pasan de uno a otro | El valor de la opción elegida |
TYPE_DATE | Botón que abre el calendario compartido; la fecha se muestra en el formato del idioma de visualización | "yyyy-mm-dd" |
TYPE_TIME | Cuadro de texto: 9:5 pasa a 09:05; lo que no es una hora de 24 h se queda en pantalla con su mensaje | "hh:mm" |
TYPE_COLOR | Botón con la muestra del color, que abre el selector compartido | El long RGB escrito como texto: String(RGB(255, 0, 0)) = "255" |
TYPE_PASSWORD | Cuadro de texto oculto | El texto tal cual |
TYPE_EMAIL | Cuadro de texto que comprueba la forma de una dirección | El texto tal cual |
TYPE_IMAGE | Una imagen, no una entrada: nunca validada, nunca en of_values; con ii_rowspan cubre varias filas (la foto de una ficha) | Su origen: un archivo, o mono: / tint: seguido de una ruta (con los colores del tema); una dirección http:// se rechaza |
TYPE_TAGS | Etiquetas en píldoras dentro de un cuadro: se teclea una palabra y luego Intro, una coma o Tab; Retroceso en la entrada vacía quita la última, cada píldora tiene su cruz, Izquierda / Derecha las recorren. Las opciones del campo (of_add_option) son sugerencias filtradas al teclear; ib_options_only las vuelve las únicas opciones, ii_max_tags limita su número | Las etiquetas unidas por una coma y un espacio: "vip, b2b" (el valor de la opción para una sugerencia elegida). La coma es el separador: nunca dentro de una etiqueta; escrita por el código separa, los espacios alrededor desaparecen, la misma etiqueta dos veces (sin distinguir mayúsculas) se guarda una vez |
TYPE_RATING | Estrellas para hacer clic, ii_star_count (5 por defecto), medias estrellas con ib_half_stars. Pasar el ratón previsualiza sin mover nada; un clic en el valor actual lo borra. Con el teclado: flechas, Inicio / Fin, un dígito, 0 o Supr. Una estrella llena toma el acento del componente | El número de estrellas: "4", "3.5"; "" = sin valoración (0 también). Escrito por el código, redondeado al paso y mantenido dentro de las estrellas; un texto o un negativo se rechaza |
La validación #
Cada campo lleva sus reglas: ib_required (una casilla obligatoria debe estar marcada), is_min / is_max (un número, una fecha, una hora), ii_max_length, is_pattern (una expresión regular que el valor entero debe seguir), is_mask (una máscara rellena), is_match (igual a otro campo), y la forma de un correo, de un número o de una hora. Su aplicación añade sus errores de negocio (is_error: ya existe), que se quedan hasta que el usuario modifica el campo. Nada se muestra en rojo mientras el usuario no ha salido de un campo: un formulario nuevo no está en rojo. of_is_valid y of_invalid_keys responden sin mostrar nada; of_validate lo muestra todo a la vez y pone el teclado en el primer campo con error. Un campo oculto, desactivado o de solo lectura no se juzga por sus reglas: el usuario no podría corregirlo.
// A customer code : two capital letters, then four digits
uo_form.of_field(/*keys*/ "code").is_pattern = "[A-Z]{2}[0-9]{4}"
uo_form.of_field(/*keys*/ "code").is_pattern_message = "Two capital letters, then four digits"
// A rule only your database knows
if of_email_taken(uo_form.of_field(/*keys*/ "email").is_value) then
uo_form.of_field(/*keys*/ "email").is_error = "Already used by another customer"
end if
Propiedades #
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
ii_columns | integer | 1 | Número de columnas, de 1 a 12 (un valor fuera de rango se devuelve dentro). Cada sección sigue. Un campo abarca más con ii_colspan, empieza en una columna dada con ii_col, cubre varias filas con ii_rowspan; los demás campos rellenan las celdas libres |
ib_readonly | boolean | false | El formulario entero de solo lectura: cada valor se lee, ninguno se cambia — una ficha que se consulta. Su código puede seguir escribiendo los valores |
ib_veto_changes | boolean | false | Opt-in: preguntar antes de escribir un valor del usuario (lanza ue_value_changing, que puede rechazarlo: el campo vuelve a mostrar el valor anterior). Un valor escrito por su código nunca pregunta |
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 una sección — n_pbt_form_section #
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
is_title | string | "" | Título del encabezado. Acepta el texto enriquecido con etiquetas. Vacío, el encabezado muestra la clave |
ib_collapsed | boolean | false | true pliega la sección: su encabezado se queda, sus campos se ocultan — conservan sus valores y siguen juzgados. Sigue ue_section_toggled, como con un clic en el encabezado. Leída en directo |
ib_visible | boolean | true | false quita la sección, y todos sus campos, del formulario; conservan sus valores (of_values los sigue devolviendo) y no se juzgan |
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 encabezado de la sección: la línea bajo su título lo toma (-1 = el del componente). Sus campos conservan el suyo |
il_back_color | long | -1 | Fondo del encabezado de la sección, en RGB(r,g,b) (-1 = lo que da el tema) |
il_text_color | long | -1 | Color del texto del encabezado de la sección (-1 = lo que da el tema) |
il_back_color_hover | long | -1 | Fondo del encabezado de la sección bajo el puntero (-1 = lo que da el tema) |
il_text_color_hover | long | -1 | Color del texto del encabezado de la sección bajo el puntero (-1 = lo que da el tema) |
Propiedades de un campo — n_pbt_form_field #
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
is_value | string | "" | El valor, como texto (ver los tipos). Escribirlo no lanza nada, como SetItem; leerlo da el valor actual, quienquiera que lo haya escrito — lo que se está tecleando cuenta. Un valor que el tipo no puede contener (una fecha que no existe, un texto en un número) se rechaza: el anterior se queda y of_get_last_error dice por qué |
is_label | string | "" | La etiqueta, dentro del campo: sube al borde cuando el campo tiene un valor o el teclado. Acepta el texto enriquecido con etiquetas. Una estrella sigue a la etiqueta de un campo obligatorio. Vacía, la clave |
is_placeholder | string | "" | Una indicación dentro de un campo de texto vacío mientras tiene el teclado |
is_help | string | "" | Una línea de ayuda bajo el campo (texto enriquecido con etiquetas); se oculta mientras un error ocupa su lugar |
is_error | string | "" | Un error de negocio de su aplicación (ya existe): mostrado enseguida, el formulario no válido, hasta que el usuario modifica el campo o of_clear_errors; "" lo borra. Leído, da el mensaje que el campo muestra — o mostrará cuando el usuario salga de él: el error de negocio, si no el de sus reglas, "" si es válido. En un campo que el usuario no puede alcanzar (oculto, desactivado) se conserva y se relee, pero no cuenta: el formulario sigue siendo válido hasta que el campo vuelve |
is_min | string | "" | El valor más pequeño aceptado para un número (con punto), una fecha (yyyy-mm-dd) o una hora (hh:mm); el mensaje dice Minimum y el límite. Un límite que el tipo no lee se ignora; "" = ninguno — para un número, el extremo inferior de la SpinRange de su columna de DataWindow (of_load_row). Leído, da el límite vigente |
is_max | string | "" | El valor más grande aceptado, leído como is_min; el mensaje dice Maximum y el límite |
is_pattern | string | "" | Una expresión regular (sintaxis JavaScript) que el valor entero debe seguir: [A-Z]{2}[0-9]{4} acepta AB1234, no xAB1234. Un valor vacío se deja a ib_required |
is_pattern_message | string | "" | El mensaje cuando is_pattern falla; vacío: Invalid format, traducido |
is_mask | string | "" | Una máscara de entrada. En un TYPE_STRING, la sintaxis de un EditMask de PowerBuilder: # un dígito, ! cualquier carácter en mayúscula, ^ cualquier carácter en minúscula, a una letra o un dígito, X cualquier carácter, el resto escrito para el usuario mientras teclea ((###) ###-####); el cursor se queda tras lo tecleado. El valor solo conserva lo tecleado en las casillas, como un EditMask (5551234567, listo para una columna de dígitos); un valor del código es el valor en bruto, sin sus literales (312345678 bajo +33 # ## ## ## ##), los literales iniciales se escriben en cuanto el campo toma el teclado, un valor que no rellena todas las casillas es Incomplete, y poner una máscara después de un valor no cambia nada de lo que hizo el usuario. Tras of_load_row, una máscara vacía toma el EditMask de la columna. En un TYPE_NUMBER: una máscara numérica en la sintaxis de PowerBuilder (EditMask, formato DataWindow): # un dígito opcional, 0 un dígito obligatorio, , la agrupación, . el separador decimal, % el número mostrado por 100, literales ($, un texto entre comillas, \x) y secciones positivo;negativo ("$#,##0;($#,##0)"). La coma y el punto designan los separadores del idioma de visualización. Al teclear, la agrupación aparece a medida que llegan los dígitos, los decimales se limitan a la máscara, las letras se rechazan, el cursor conserva su lugar entre los dígitos y un número pegado se lee en el idioma de visualización; al salir del campo la máscara completa (12 pasa a 12,00). El valor conserva el número tal como lo escribe el código ("1234.5"), sin agrupación ni símbolo. Un límite inferior (is_min) de 0 o más rechaza el signo menos; los límites se aplican al salir del campo, y su mensaje los muestra a través de la máscara; vacío en un TYPE_NUMBER (por defecto): el campo se teclea según su is_format sin sus literales ($#,##0.00 se teclea #,##0.00, #,##0 "px" se teclea #,##0; un % se queda, es una escala) |
is_format | string | "" | Un TYPE_NUMBER: su formato de visualización, cómo se muestra el número mientras el campo no tiene el teclado — la misma sintaxis que is_mask, con sus literales: #,##0 "px" muestra 575 px, $#,##0.00;($#,##0.00) un precio, 0.0% una tasa (0,125 muestra 12,5%). Cuando el campo toma el teclado su texto pasa a ser el de is_mask (575), el cursor conserva su lugar entre los dígitos; al salir vuelve el texto de visualización. El cambio nunca modifica el valor y no lanza nada: ue_value_changed solo informa de lo que el usuario tecleó, el número desnudo. Vacío: el campo muestra su is_mask |
is_boolean_style | string | "switch" | Un TYPE_BOOLEAN: cómo se dibuja. BOOLEAN_SWITCH (por defecto): un interruptor, una pista y un círculo que se desliza hacia el final, en el color de acento del componente, cuando está encendido — un ajuste de encendido / apagado. BOOLEAN_CHECKBOX: la casilla clásica — una aceptación, una elección entre opciones. Ambos responden a Espacio y a un clic en su etiqueta, dan el mismo valor y los mismos eventos; desactivados o de solo lectura siguen siendo legibles. El círculo se desliza en un cuarto de segundo, nada cuando Windows pide menos animaciones; en un idioma escrito de derecha a izquierda se desliza hacia la izquierda |
ii_max_tags | integer | 0 | Un TYPE_TAGS: el número máximo de etiquetas (0 = sin límite). Una más tecleada por el usuario se rechaza: se queda en la entrada con el mensaje At most N; una lista más larga escrita por el código se conserva, y el campo no es válido (of_is_valid, is_error) — se muestra una vez tocado el campo o tras of_validate, nunca de entrada |
ib_options_only | boolean | false | Un TYPE_TAGS: true limita sus etiquetas a las opciones del campo (of_add_option) — un texto que no nombra ninguna (por su texto o su valor, sin mayúsculas ni acentos) se rechaza con Not in the list. false: todo texto es una etiqueta, las opciones solo son sugerencias |
ii_star_count | integer | 5 | Un TYPE_RATING: el número de estrellas, de 1 a 10 (un número fuera se devuelve dentro). El valor actual se mantiene dentro, sin evento: poner el número antes de un valor por encima de cinco |
ib_half_stars | boolean | false | Un TYPE_RATING: true permite las medias estrellas — la primera mitad de la estrella bajo el puntero (en el sentido de lectura), Izquierda / Derecha de media estrella — y el valor se escribe "3.5". Desactivado, el valor actual se redondea a una estrella entera, sin evento: activarlo antes de un medio valor |
is_match | string | "" | La dirección de otro campo al que este debe ser igual — repetir una contraseña, un correo. El mensaje sigue cada cambio de uno u otro |
is_prefix | string | "" | Un texto corto dentro del campo, antes del valor (un símbolo de moneda); no forma parte del valor |
is_suffix | string | "" | Un texto corto dentro del campo, después del valor (una unidad); no forma parte del valor |
ii_max_length | integer | 0 | El texto más largo aceptado (0 = sin límite) por un TYPE_STRING, TYPE_TEXTAREA, TYPE_PASSWORD o TYPE_EMAIL — un número o una hora no tiene longitud, se ignora; 0 toma el Limit de su columna de DataWindow (of_load_row), leído da la longitud vigente: el tecleo se detiene ahí, un contador aparece bajo un campo de texto; un valor más largo escrito por el código es Too long. En un TYPE_TAGS: la etiqueta más larga — un pegado de varias etiquetas nunca se corta, cada una se juzga |
ii_colspan | integer | 1 | Cuántas columnas abarca el campo (como mucho ii_columns); -1 = todo el ancho |
ii_rowspan | integer | 1 | Cuántas filas cubre el campo — una imagen junto a varios campos; los siguientes rellenan las celdas libres a su lado |
ii_col | integer | 0 | La columna donde el campo empieza, desde 1; 0 = donde lo pone el flujo. La tecla Tab sigue el orden de la pantalla — primero los campos de arriba, luego cada sección —, sea cual sea la columna |
ib_required | boolean | false | El campo debe rellenarse — una casilla debe estar marcada (una casilla Acepto), un campo de etiquetas contener una, una valoración tener una estrella. Una estrella sigue a su etiqueta; el error Required aparece cuando el usuario sale del campo o con of_validate. Una columna cuyo estilo de edición dice Required lo vuelve obligatorio también (of_load_row); leído, da el estado vigente |
ib_readonly | boolean | false | Muestra el valor sin dejar cambiarlo: un texto aún puede seleccionarse y copiarse; una lista, una fecha, un color, un interruptor o botones de opción conservan el teclado (Tab los alcanza, un lector de pantalla dice solo lectura) pero ni se abren ni cambian. No se juzga por sus reglas; su código puede seguir escribiendo is_value |
ib_enabled | boolean | true | false atenúa el campo: sin teclado (sale del orden de tabulación), sin clic, no se juzga por sus reglas |
ib_visible | boolean | true | false quita el campo del formulario; conserva su dirección y su valor (of_values lo sigue devolviendo) y no se juzga |
is_column | string | "" | La columna del DataWindow que of_load_row y of_save_row leen y escriben para este campo; "" (por defecto) = su clave, el último nivel de su dirección. Dos secciones pueden así llevar la misma clave (billing/town, shipping/town) ligada a dos columnas, y un campo conservar una clave legible para una columna llamada cust_nm |
id_step | double | 0 | Un TYPE_NUMBER: lo que Arriba / Abajo (y sus botones, ib_spin) añaden o quitan, mantenido entre is_min e is_max; 0 (por defecto) = el SpinIncr de su columna de DataWindow (of_load_row), si no 1. Un paso es un gesto del usuario: se lanza ue_value_changed (y antes se plantea ue_value_changing con ib_veto_changes). Un campo vacío parte de is_min, si no de 0; un paso negativo se rechaza |
ib_ellipsis | boolean | false | Un campo de texto (TYPE_STRING, TYPE_NUMBER, TYPE_EMAIL…): true muestra un botón … en su extremo — su búsqueda, un cliente, un artículo. Un clic en él, o Ctrl+Intro en el campo, lanza ue_ellipsis_clicked; queda fuera del orden de Tab. Funciona también en un campo de solo lectura (un valor elegido solo por la búsqueda), nunca en uno desactivado |
ib_spin | boolean | false | Un TYPE_NUMBER: true muestra dos pequeños botones en su extremo, arriba y abajo, que añaden o quitan id_step entre is_min e is_max — un gesto del usuario (ue_value_changed). La rueda del ratón también lo hace mientras el campo tiene el teclado; los botones quedan fuera del orden de Tab (Arriba / Abajo en el campo hacen lo mismo) y se ocultan en un campo de solo lectura. Una columna cuyo EditMask dice Spin los da con of_load_row, con su SpinIncr como paso y su SpinRange como límites. Ignorado por los demás tipos; leído, da el estado vigente |
of_type ( ) → string | — | — | El tipo dado a of_add_field (una constante TYPE_*). Solo lectura: un tipo se elige una vez |
of_is_dirty ( ) → boolean | — | — | TRUE cuando este campo difiere de su referencia (ver of_is_dirty del formulario) |
of_is_valid ( ) → boolean | — | — | TRUE cuando este campo no tiene ningún error; is_error dice cuál |
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 campo: su borde lo toma cuando tiene el teclado, y su etiqueta una vez subida (-1 = el del componente) |
il_back_color | long | -1 | Fondo del campo, en RGB(r,g,b) (-1 = lo que da el tema) |
il_text_color | long | -1 | Color del texto del campo (-1 = lo que da el tema) |
il_back_color_hover | long | -1 | Fondo del campo bajo el puntero (-1 = lo que da el tema) |
il_text_color_hover | long | -1 | Color del texto del campo bajo el puntero (-1 = lo que da el tema) |
Métodos #
En el componente #
| Método | Función | |
|---|---|---|
of_add_section (string as_key, string as_title) → long | Añade una sección al final: un encabezado que se pliega, subrayado con el acento, bajo el cual se añaden luego los campos "clave/nombre". Un título vacío muestra la clave. Devuelve 0 una vez añadida, -5 para una clave vacía, que contiene / o ` | , o ya tomada por una sección o un campo de arriba, -2` si el componente no está creado |
of_add_field (string as_keys, string as_label, string as_type, string as_value) → long | Añade un campo en su dirección, al final de lo que lo contiene: su sección o la parte de arriba del formulario. as_type es una constante TYPE_*, as_value su valor como texto (el origen de una imagen). Devuelve 0 una vez añadido, -5 para una dirección ya tomada (un campo, o una sección en el primer nivel), un nivel vacío, más de dos niveles, una sección nunca añadida, una clave que contiene ` | , un tipo desconocido o un valor que el tipo no puede contener (of_get_last_error dice por qué), -2` si el componente no está creado |
of_add_option (string as_keys, string as_value, string as_text) → long | Añade una opción, al final, a una lista TYPE_ENUM, a botones TYPE_RADIO o a las sugerencias de un TYPE_TAGS: as_value es lo que contiene el campo (y lo que da ue_value_changed), as_text lo que lee el usuario, como texto plano ("" muestra el valor). Devuelve 0 una vez añadida, -5 para una dirección que no es una lista, botones de opción ni etiquetas, un valor ya ofrecido, un valor que contiene ` | o / (of_keys_at lo une a la dirección del campo) — y para etiquetas un valor vacío o con una coma —, -2` si el componente no está creado |
of_remove_option (string as_keys, string as_value) → long | Quita una opción de una lista, de botones de opción o de etiquetas, por su valor; el valor del campo se queda como está. Devuelve 0 una vez quitada, -5 para una dirección que no es una lista, botones de opción ni etiquetas, o un valor que no ofrece, -2 si el componente no está creado | |
of_clear_options (string as_keys) → long | Quita todas las opciones de una lista, de botones de opción o de etiquetas, para cargar otra lista sin perder el campo, su handle ni su estado; su valor se queda como está. Devuelve 0 una vez vaciada, -5 para una dirección que no es una lista, botones de opción ni etiquetas, -2 si el componente no está creado | |
of_remove_field (string as_keys) → long | Quita un campo por su dirección, con su handle; el resto del formulario conserva su estado. Devuelve 0 una vez quitado, -5 para una dirección nunca añadida, -2 si el componente no está creado | |
of_remove_section (string as_key) → long | Quita una sección y todos sus campos, con sus handles. Devuelve 0 una vez quitada, -5 para una sección nunca añadida, -2 si el componente no está creado | |
of_clear ( ) → long | Vacía el formulario: secciones, campos y sus handles. A diferencia de of_reset, las columnas, la solo lectura y la pregunta se quedan. Devuelve 0 una vez vaciado, -2 si el componente no está creado | |
of_section (string as_key) → n_pbt_form_section | El handle de una sección, por su clave: título, pliegue, visibilidad, colores y tooltip. Creado en el primer acceso | |
of_field (string as_keys) → n_pbt_form_field | El handle de un campo, por su dirección: of_field("order/qty").is_value = "3". Creado en el primer acceso | |
of_values ( ) → string | Todos los valores a la vez, leídos en directo, en un objeto JSON: los campos de arriba, luego cada sección como un objeto propio — ocultos incluidos, imágenes excluidas; lo que el usuario aún teclea se valida primero, como hace AcceptText: ue_value_changing planteado con ib_veto_changes, luego ue_value_changed lanzado — ambos antes de la lectura, nunca en medio: su Aceptar lee lo que está en pantalla. Tipados: un número es un número (escrito cifra a cifra, null si está vacío), un booleano un booleano, un color su long RGB, el resto texto. Se lee con n_pbt_json, por la misma dirección: lnv_json.of_get_number("order/qty") | |
of_load (string as_json) → long | Carga un registro: un objeto JSON de valores por dirección — los campos de arriba, luego un objeto por sección, o claves "order/qty" —, la forma que devuelve of_values; números y booleanos pueden ir tipados — un número de más de 15 dígitos se lee cifra a cifra, un booleano vale true, false, 1 o 0 (cualquier otro valor se rechaza). Los valores se escriben en silencio y pasan a ser la referencia de of_is_dirty; los errores mostrados y los errores de negocio se borran. Un campo que el objeto no nombra conserva su valor. Devuelve 0 una vez cargado, -5 para un texto que no es un objeto JSON, o un valor que su campo no puede contener (abc para un número) — entonces no se escribe nada, of_get_last_error nombra los campos —, -2 si el componente no está creado | |
of_load_row (powerobject apo_data, long al_row) → long | Carga una fila de un DataWindow, un DataStore o un DataWindowChild: cada campo toma el valor de su columna — la que nombra is_column, si no su clave (el último nivel de su dirección) —, tipado — una fecha yyyy-mm-dd, una hora hh:mm, un número con punto, un booleano leído por el valor On de una columna casilla (si no, 1, Y, true…). Lo que el DataWindow dice de la columna llega con ella, releído en cada carga: un campo sin etiqueta muestra el texto de encabezado de su columna, un campo sin máscara ni formato toma su EditMask y su Format (un número $#,##0), una lista o botones de opción sin opciones propias ofrecen su tabla de códigos o las filas de su DropDownDataWindow; un campo sin reglas propias pasa a ser obligatorio cuando el estilo de edición dice Required y limitado a su Limit, y un número cuyo EditMask dice Spin recibe sus botones (ib_spin), su paso (SpinIncr) y sus límites (SpinRange). La fila siguiente del mismo DataWindow no vuelve a dibujar ningún campo: el que tiene el teclado lo conserva. Como con of_load, los valores pasan a ser la referencia. Devuelve 0 una vez cargada, -5 para un objeto que no es ni un DataWindow, ni un DataStore, ni un DataWindowChild, una fila que no existe, o un valor que su campo no puede contener (entonces nada cambia: ni un valor ni lo que dice el DataWindow), -2 si el componente no está creado | |
of_save_row (powerobject apo_data, long al_row) → long | Escribe los valores que el usuario ha cambiado (desde la referencia: of_load_row, of_reset_update) en una fila de un DataWindow, un DataStore o un DataWindowChild: cada campo cambiado en su columna (is_column, si no su clave), con SetItem, tipado para la columna (fecha, datetime, hora, número, texto; un booleano como valor On / Off de una columna casilla, 1 / 0 en una columna numérica, true / false en una columna de texto; un campo vacío escribe un NULL — un texto vacío, un NULL donde su columna dice NilIsNull, una cadena vacía si no, como el DataWindow). Un campo que el usuario no ha cambiado no se escribe: la fila conserva su estado, su Update solo envía lo que cambió. Un TYPE_DATE conserva la hora de una columna datetime, un TYPE_TIME su fecha. Lo que el usuario aún teclea se valida primero, y se lanza ue_value_changed, antes de cualquier lectura; el Update sigue siendo suyo. Devuelve 0 una vez escrita, -5 para un objeto que no es ni un DataWindow, ni un DataStore, ni un DataWindowChild, o una fila que no existe, -4 cuando una columna se quedó como estaba — un SetItem rechazado, un campo cuyo tipo la columna no puede contener (un TYPE_STRING en una columna de fecha), o un valor con decimales para una columna entera (3.5 estrellas en un long: SetItem lo redondearía): of_get_last_error nombra la primera, los demás campos cambiados se escriben igualmente —, -2 si el componente no está creado | |
of_is_valid ( ) → boolean | TRUE cuando ningún campo mostrado tiene un error: cada campo obligatorio relleno (una casilla obligatoria marcada), cada regla seguida, ningún error de negocio. Leído en directo, sin mostrar nada; un error de negocio solo cuenta en un campo que el usuario puede alcanzar (mostrado y activo) | |
of_invalid_keys (ref string as_keys[]) → long | Rellena as_keys[] con las direcciones de los campos con error, en el orden de la pantalla, sin mostrar nada, y devuelve su número (0 = el formulario es válido) | |
of_validate ( ) → long | Muestra todos los errores a la vez y pone el teclado en el primer campo con error (ue_focus_changed) — lo que llama su botón Aceptar antes de guardar. El teclado deja el botón por el formulario: la tecla siguiente va al campo; lo que el usuario aún teclea se valida primero, y un lector de pantalla lee los mensajes enseguida. Devuelve el número de campos con error (0 = el formulario es válido, nada se mueve), -2 si el componente no está creado | |
of_clear_errors ( ) → long | Borra todos los errores de negocio (is_error escrito por su código); los errores de las reglas se quedan. Devuelve 0 una vez aplicado, -2 si el componente no está creado | |
of_is_dirty ( ) → boolean | TRUE cuando al menos un campo difiere de su referencia: el valor dado al añadirlo, o lo que hicieron de él of_load, of_load_row u of_reset_update; lo que el usuario aún teclea se valida primero. Un número escrito de otra forma (12.50 por 12.5) es el mismo valor | |
of_dirty_keys (ref string as_keys[]) → long | Rellena as_keys[] con las direcciones de los campos modificados desde la referencia, en el orden de la pantalla, y devuelve su número | |
of_reset_update ( ) → long | Los valores en pantalla pasan a ser la referencia: of_is_dirty vuelve a responder FALSE. Llámelo una vez que su Update haya funcionado, como ResetUpdate de un DataWindow. Devuelve 0 una vez aplicado, -2 si el componente no está creado | |
of_revert ( ) → long | Devuelve cada campo a su valor de referencia, en silencio, y oculta los errores — el Cancelar del usuario. Devuelve 0 una vez aplicado, -2 si el componente no está creado | |
of_focus_field (string as_keys) → long | Pone el teclado en un campo, como un clic: su sección plegada se abre primero (ue_section_toggled), sigue ue_focus_changed. Devuelve 0 una vez hecho, -5 para una dirección nunca añadida o un campo que el usuario no puede alcanzar (oculto, desactivado — incluido el que tenía el teclado —, una imagen, más allá del límite de la demo), -2 si el componente no está creado | |
of_current_key ( ) → string | Dirección del campo que tiene el teclado — o lo tuvo el último, mientras el teclado está en otra parte de la ventana: "order/qty", "" si aún ninguno. Siempre la actual, leída del componente; también lo que da ue_focus_changed | |
of_get_last_error ( ) → string | Por qué se rechazó la última escritura: un valor que el tipo no puede contener (is_value no tiene código de retorno; una imagen http://, un número infinito como 1e400), un is_pattern que el formulario no sabe leer, un valor que of_load rechazó, una columna que of_save_row dejó. Vacío cuando ha pasado; si no, el último error de la biblioteca, como en todo componente | |
of_reset ( ) → long | Vacía el formulario y luego devuelve cada propiedad del componente a su valor por defecto: una columna, ni solo lectura ni pregunta. Devuelve 0 una vez aplicado, -2 si el componente no está creado |
En una sección y en un campo #
Una sección contiene campos; una lista o unos botones de opción contienen sus opciones, designadas por su valor. Los tres métodos los recorren.
| Método | Función |
|---|---|
of_count ( ) → long | Número de campos de la sección, ocultos incluidos; número de opciones de una lista, de botones de opción o de etiquetas (0 para los demás tipos) |
of_keys_at (long al_index) → string | Dirección del campo de rango al_index (desde 1) — "order/qty", reutilizable tal cual en of_field; en una lista, la dirección seguida del valor de la opción. "" fuera de rango |
of_has (string as_key) → boolean | ¿Contiene la sección este campo? ¿Ofrece la lista este valor? |
Eventos #
| Evento | Se activa cuando |
|---|---|
ue_value_changed (string as_keys, string as_value) | El usuario ha cambiado un valor: una entrada validada al salir del campo o con Intro, una casilla marcada, un botón de opción, una opción, una fecha o un color elegidos (Arriba / Abajo recorren una lista, Supr vacía una lista, una fecha o un color). as_keys es la dirección del campo, as_value su nuevo valor como texto; ya está escrito. Un valor escrito por su código no lanza nada, como SetItem. Lo que el usuario aún teclea cuando su código lee el formulario (of_values, of_save_row, is_value…) se valida en ese momento, como hace AcceptText: el evento se lanza ahí, antes de la lectura |
ue_value_changing (string as_keys, string as_value) → boolean | Cancelable, planteado antes de escribir un valor del usuario, y solo cuando ib_veto_changes = true (desactivado por defecto). Devolver FALSE lo rechaza: el campo vuelve a mostrar el valor anterior, que of_field(as_keys).is_value sigue devolviendo durante el evento. Devuelva TRUE para aceptar. Cuando su código lee el formulario (of_values, of_validate, is_value…) mientras el usuario aún teclea en un campo, la pregunta se plantea enseguida, antes de la lectura: la lectura devuelve el valor que usted aceptó |
ue_focus_changed (string as_from_keys, string as_keys) | El campo que tiene el teclado ha cambiado: un clic, la tecla Tab, su código (of_focus_field, of_validate — una orden también lo lanza, como SetColumn), o el campo se ha ido: quitado, ocultado, vaciado (as_keys vale entonces ""). El teclado que deja el formulario por otro control de la ventana no lanza nada |
ue_section_toggled (string as_key, boolean ab_collapsed) | Una sección se ha plegado (ab_collapsed = TRUE) o desplegado: un clic en su encabezado (Intro o Espacio cuando tiene el teclado), su ib_collapsed fijado por su código, u of_focus_field sobre un campo de una sección plegada |
ue_ellipsis_clicked (string as_keys) | Se ha hecho clic en el botón … de un campo (ib_ellipsis), o se ha pulsado Ctrl+Intro en el campo: abra su búsqueda (un cliente, un artículo) y escriba lo que eligió el usuario en of_field(as_keys).is_value. Lo tecleado ya está validado (ue_value_changing planteado antes con ib_veto_changes, ue_value_changed lanzado). Nunca se lanza para un campo desactivado |
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 #
| Gesto | Efecto |
|---|---|
| Tab, Mayús+Tab | Pasan de un campo a otro, en el orden de la pantalla: los campos de arriba, luego cada sección, primero su encabezado; un campo desactivado se salta; los botones de opción son una parada, las flechas eligen |
| Intro en un campo de una línea | Valida la entrada y luego pasa a la ventana: su botón por defecto (su Aceptar) lee un formulario al día. Con ib_veto_changes, la página no pregunta nada: la entrada queda pendiente, y la lectura del botón por defecto la valida (ue_value_changing se plantea entonces) — sin botón por defecto, la valida la salida del campo |
| Esc | En un campo que el usuario ha modificado, devuelve su valor; si no, pasa a la ventana: su botón Cancelar |
| Lista, fecha, color: Intro, Espacio, F4, Alt+Abajo | Abren la ventana compartida (lista, calendario, selector de color); Intro se queda ahí, no pasa al botón por defecto de la ventana — tampoco en un encabezado de sección, que pliega o despliega |
| Lista: Arriba / Abajo | Opción anterior / siguiente, sin abrir la lista |
| Lista, fecha, color: Supr, Retroceso | Vacían el valor |
| Etiquetas: Intro, coma, Tab | Añaden lo tecleado (Tab mantiene el teclado en el campo); Retroceso en la entrada vacía quita la última etiqueta; Izquierda / Derecha recorren las etiquetas, Supr quita la marcada; Abajo abre las sugerencias, Esc las cierra |
| Estrellas: flechas, Inicio / Fin, dígitos, Supr | Derecha / Arriba una estrella más (media con ib_half_stars), Izquierda / Abajo una menos — invertidas en un idioma escrito de derecha a izquierda; Inicio una estrella, Fin todas; un dígito tantas estrellas; 0, Supr o Retroceso borran la valoración |
| Número: Arriba / Abajo | Añaden o quitan el paso del campo (id_step, 1 por defecto), mantenido entre is_min e is_max: sigue ue_value_changed. Con ib_spin, sus dos botones hacen lo mismo, y la rueda mientras tiene el teclado |
| Ctrl+Intro, clic en … | Un campo con ib_ellipsis: valida lo tecleado y luego lanza ue_ellipsis_clicked — su búsqueda |
| Clic en un encabezado de sección | Pliega o despliega la sección (ue_section_toggled) |
Ejemplos #
Una ficha de cliente #
// The whole form in one paint, two columns
uo_form.of_set_redraw(/*on*/ false)
uo_form.ii_columns = 2
// Identity : two required names, an e-mail, a phone with its mask
uo_form.of_add_section(/*key*/ "identity", /*title*/ "Identity")
uo_form.of_add_field(/*keys*/ "identity/first_name", /*label*/ "First name", /*type*/ u_pbt_form.TYPE_STRING, /*value*/ "")
uo_form.of_field(/*keys*/ "identity/first_name").ib_required = true
uo_form.of_add_field(/*keys*/ "identity/last_name", /*label*/ "Last name", /*type*/ u_pbt_form.TYPE_STRING, /*value*/ "")
uo_form.of_field(/*keys*/ "identity/last_name").ib_required = true
uo_form.of_add_field(/*keys*/ "identity/email", /*label*/ "E-mail", /*type*/ u_pbt_form.TYPE_EMAIL, /*value*/ "")
uo_form.of_add_field(/*keys*/ "identity/phone", /*label*/ "Phone", /*type*/ u_pbt_form.TYPE_STRING, /*value*/ "")
uo_form.of_field(/*keys*/ "identity/phone").is_mask = "(###) ###-####"
// Account : a credit limit with a bound, shown as a price and typed without the
// dollar sign ; a list ; a switch
uo_form.of_add_section(/*key*/ "account", /*title*/ "Account")
uo_form.of_add_field(/*keys*/ "account/credit_limit", /*label*/ "Credit limit", /*type*/ u_pbt_form.TYPE_NUMBER, /*value*/ "2500")
uo_form.of_field(/*keys*/ "account/credit_limit").is_format = "$#,##0.00"
uo_form.of_field(/*keys*/ "account/credit_limit").is_max = "50000"
uo_form.of_add_field(/*keys*/ "account/country", /*label*/ "Country", /*type*/ u_pbt_form.TYPE_ENUM, /*value*/ "gb")
uo_form.of_add_option(/*keys*/ "account/country", /*value*/ "gb", /*text*/ "United Kingdom")
uo_form.of_add_option(/*keys*/ "account/country", /*value*/ "fr", /*text*/ "France")
uo_form.of_add_field(/*keys*/ "account/vip", /*label*/ "VIP customer", /*type*/ u_pbt_form.TYPE_BOOLEAN, /*value*/ "false")
// Shown at once, the keyboard on the first field
uo_form.of_set_redraw(/*on*/ true)
uo_form.of_focus_field(/*keys*/ "identity/first_name")
Editar una fila de un DataWindow #
La clave de cada campo es el nombre de su columna: el formulario lee la fila, el usuario la modifica, el formulario la escribe.
// The current row of dw_customers fills the form ; nothing is dirty yet
uo_form.of_load_row(/*data*/ dw_customers, /*row*/ dw_customers.GetRow())
// event clicked of cb_save
if uo_form.of_validate() > 0 then return
// Write the values back into the row, then save it
if uo_form.of_save_row(/*data*/ dw_customers, /*row*/ dw_customers.GetRow()) < 0 then
MessageBox("Save", uo_form.of_get_last_error())
return
end if
// Saved : what is on screen is the new reference
if dw_customers.Update() = 1 then
COMMIT USING SQLCA;
uo_form.of_reset_update()
end if
Etiquetas y estrellas #
Una opinión sobre un producto: una nota sobre cinco con medias estrellas, y etiquetas libres con sugerencias. Los dos valores siguen siendo texto, que of_save_row escribe en una columna numérica y en una columna de texto.
// Local variables
string ls_score, ls_tags
// The score : five stars, half stars set BEFORE a half value
uo_form.of_add_field(/*keys*/ "score", /*label*/ "Overall", /*type*/ u_pbt_form.TYPE_RATING, /*value*/ "")
uo_form.of_field(/*keys*/ "score").ib_half_stars = true
uo_form.of_field(/*keys*/ "score").is_value = "3.5"
// Tags : free text, the options are suggestions, five at most
uo_form.of_add_field(/*keys*/ "tags", /*label*/ "Tags", /*type*/ u_pbt_form.TYPE_TAGS, /*value*/ "office, led")
uo_form.of_add_option(/*keys*/ "tags", /*value*/ "eco", /*text*/ "Eco-friendly")
uo_form.of_add_option(/*keys*/ "tags", /*value*/ "usb", /*text*/ "USB powered")
uo_form.of_field(/*keys*/ "tags").ii_max_tags = 5
// Read back : "3.5" and "office, led"
ls_score = uo_form.of_field(/*keys*/ "score").is_value
ls_tags = uo_form.of_field(/*keys*/ "tags").is_value
Avisar antes de perder cambios #
// event closequery of the window
if not uo_form.of_is_dirty() then return 0
// Changes since the load : ask, and put them back if the user gives up
if MessageBox("Customer", "Discard your changes ?", Question!, YesNo!) = 2 then return 1
uo_form.of_revert()
return 0
Buenas prácticas #
- Un valor es un texto: un número se escribe con punto (
"12.5"), un booleano"true"/"false", un colorString(RGB(…)), una fecha"yyyy-mm-dd", una hora"hh:mm"— sea cual sea el idioma del equipo. Para valores tipados,of_valuesyn_pbt_json. - Su botón Aceptar decide:
of_validatemuestra los errores y devuelve su número; el formulario no guarda nada por sí mismo. - Llame a los campos como a las columnas:
of_load_rowyof_save_rowhacen entonces todo el trabajo; si no,is_columnnombra la columna de un campo. ib_readonlymejor queib_enabled = falsepara un valor que el usuario debe leer: un texto de solo lectura se selecciona y se copia.- Modo de demostración: sin clave, el formulario dibuja 6 campos, los primeros mostrados en el orden de la pantalla — un campo de una sección plegada también cuenta, desplegarla no redibuja nada; los demás quedan en memoria y en
of_values, pero ni se dibujan ni se juzgan (ver Licencia).
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.