commandpalette — n_pbt_commandpalette #
← Referencia de componentes · Índice de la guía
Paleta de comandos: el usuario pulsa un atajo, escribe tres letras y alcanza cualquier acción de su aplicación — sin buscarla en los menús.
▶ Verlo en vivo — Aplicación de demostración, mosaico Command palette: la vista previa, el código que lo produce y esta página, uno al lado del otro.
En resumen #
| Objeto | n_pbt_commandpalette — no visual: nada que colocar en la ventana |
| Sirve para | Hacer que toda acción de la aplicación sea alcanzable desde el teclado, en tres letras |
| Retorno | No bloqueante: of_open() devuelve el control de inmediato; la elección vuelve como evento |
La paleta es una ventana desprendida, suya: flota sobre su aplicación, toma el foco mientras el usuario escribe y lo devuelve al cerrarse.
Inicio rápido #
Coloque n_pbt_commandpalette en su ventana como objeto no visual (aquí llamado inv_palette): sus eventos se programan en él, como los de un control.
// Una vez, al arrancar : las acciones de su aplicacion
inv_palette.ipo_owner = this
inv_palette.of_add_command(/*key*/ "new", /*label*/ "New project", /*group*/ "File")
inv_palette.of_add_command(/*key*/ "open", /*label*/ "Open file...", /*group*/ "File")
inv_palette.of_add_command(/*key*/ "save", /*label*/ "Save", /*group*/ "File")
inv_palette.of_register_shortcut()
// event ue_command_selected of inv_palette : (string as_key)
// parent is the window : the palette runs nothing by itself
choose case as_key
case "new"; parent.wf_new()
case "open"; parent.wf_open()
case "save"; parent.wf_save()
end choose
La conexión: la ventana anfitriona #
La paleta es un objeto no visual, pero no tiene ningún receptor ni mensaje que cablear: recoge ella misma sus eventos y los lanza en sí misma — ue_command_selected, ue_shortcut, ue_opened y ue_closed se programan en el objeto paleta colocado en la ventana (o en un descendiente). ipo_owner indica a qué ventana pertenece.
Dos líneas, una sola vez, al abrir la ventana:
// La ventana a la que la paleta pertenece
inv_palette.ipo_owner = this
// La paleta debe responder a su tecla
inv_palette.of_register_shortcut()
Eso es todo lo que hay que conectar. La elección del usuario, la apertura y el cierre le vuelven después como simples eventos del objeto paleta (no de
ipo_owner) — sin receptor, sin mensaje que mapear, sin temporizador. Un evento puede abrir una MessageBox o cerrar la ventana («Salir»): los siguientes esperan a que termine, y una paleta destruida con su ventana se detiene limpiamente.
Dónde escribir los eventos #
PowerBuilder ofrece los eventos de un objeto no visual en solo dos lugares: la paleta colocada en la ventana (en el pintor, Insert > Object, luego n_pbt_commandpalette, llamada inv_palette: sus eventos se programan como los de un control — es lo que suponen los ejemplos de esta página), o un descendiente de n_pbt_commandpalette (n_my_palette), cuyos eventos llevan sus scripts y que la ventana crea con create n_my_palette. Una variable n_pbt_commandpalette creada con create no tiene script: la paleta se abre, pero la elección del usuario no llega a nadie.
El atajo: es la DLL quien lo oye #
El atajo que abre la paleta no lo escucha la página: se registra en la DLL, la única que ve las teclas pulsadas mientras el foco está en otro control. Ahí está toda la diferencia entre una paleta que se encuentra y una que solo responde si ya se ha hecho clic en ella.
La DLL oye el atajo, pero no abre nada por sí misma: se lo avisa con ue_shortcut, y decide usted. Una paleta que se abre sobre un diálogo modal no ayudaría a nadie.
// event ue_shortcut : la tecla ha caido
if not ib_dialog_open then inv_palette.of_open()
is_shortcut elige el atajo; of_register_shortcut() lo entrega. Llámelo una vez al abrir la ventana — de lo contrario la paleta solo responde a su tecla después de haberse abierto una vez. of_open lo vuelve a entregar de paso, así que un atajo cambiado más tarde no necesita nada más.
// El atajo de siempre, el de los editores de codigo
inv_palette.is_shortcut = inv_palette.SHORTCUT_DEFAULT
// O el suyo
inv_palette.is_shortcut = "ctrl+shift+p"
// O ninguno : la paleta solo se abre con of_open()
inv_palette.is_shortcut = inv_palette.SHORTCUT_NONE
El atajo de la paleta solo se consulta después de los atajos de los demás componentes de la ventana, con foco o sin él: un botón de barra de herramientas con el mismo atajo gana. El atajo de esta ventana pasa antes que uno registrado sin
ipo_owner(toda la aplicación). Solo se aceptan las teclas que el gancho sabe nombrar — letras, dígitos, F1 a F24, Intro, Esc, Supr, Insert, Inicio, Fin, RePág, AvPág y, con Ctrl o Alt, las flechas, Espacio, Tab, Retroceso,+ - , .; cualquier otra devuelve-5. El capítulo del teclado lo detalla.
Dónde aparece la paleta #
is_position dice dónde se posa la ventana. Siempre se la trae de vuelta a la pantalla: una paleta anclada bajo un campo al pie de la ventana no desaparece tras la barra de tareas.
| Constante | Dónde |
|---|---|
POSITION_WINDOW_CENTER | Centrada en ipo_owner — el valor predeterminado, y lo que el ojo espera |
POSITION_SCREEN_CENTER | Centrada en la pantalla, sea cual sea la ventana |
POSITION_ABSOLUTE | En il_x / il_y, en píxeles de pantalla |
PowerBuilder trabaja en PBU, y la posición de un control es relativa a su ventana: para anclar la paleta bajo un control, of_anchor_under(control) hace la conversión y pone las tres propiedades. Con dos pantallas, se abre en la pantalla del punto pedido.
Su altura sigue al número de comandos mostrados y se reduce a medida que se filtra — sin que su esquina superior se mueva, o el cuadro de búsqueda se escaparía bajo los dedos. Está limitada a media pantalla: más allá, la lista se desplaza por dentro y el cuadro de búsqueda queda arriba.
Un clic en otro sitio de la aplicación cierra la paleta, y ese clic alcanza igualmente su objetivo — como al salir de un menú. No hay nada que hacer.
Propiedades #
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
ipo_owner | powerobject | — | La ventana a la que la paleta pertenece: posee la ventana emergente y le sirve de ancla, y su atajo responde en esa ventana. Póngala antes de of_open. Si se deja vacía, el atajo responde en todas las ventanas de la aplicación. Los eventos no se lanzan en ella sino en el propio objeto paleta. Dos objetos paleta sobre la misma ventana conservan cada uno su atajo y sus eventos: ninguno recibe los del otro |
ipo_receiver | powerobject | — | Opcional, heredado: una ventana cuyo pbm_custom02 suena en cada evento, para el código antiguo que llamaba ahí a of_process_events. Déjelo vacío — la paleta entrega sus eventos sola, en sí misma |
is_shortcut | string | "ctrl+k" | Atajo que abre la paleta, desde cualquier sitio de la ventana. Constantes SHORTCUT_DEFAULT (ctrl+k) y SHORTCUT_NONE (ninguno). Surte efecto en of_register_shortcut |
is_position | string | window-center | Dónde se posa la ventana (constantes POSITION_*) |
il_x · il_y | long | 0 | Posición en píxeles de pantalla, leída solo por POSITION_ABSOLUTE |
is_placeholder | string | "" | Texto gris en el cuadro de búsqueda mientras no se escribe nada |
is_recent | string | "" | Memoria de uso: los ids lanzados más recientemente, el más reciente primero, separados por comas. La paleta los sube arriba; al filtrar, la recencia solo desempata resultados que coinciden más o menos igual de bien — nunca pone una coincidencia más débil por delante de una mejor, sea cual sea il_max_recent. Los espacios alrededor de los ids y los duplicados se limpian, y la lista limpia vuelve aquí. Reléala tras el uso y persístala; vuelva a ponerla al arrancar. Una paleta que empieza de cero cada mañana no aprende nada |
il_max_recent | long | 8 | Cuántos guarda el bloque « Usados recientemente ». 8 por defecto. Un límite más bajo recorta is_recent en la apertura siguiente. 0 lo apaga: una aplicación cuyos usuarios prefieren sus grupos intactos puede decirlo — is_recent se conserva entonces tal cual, sin usarse. Una entrada del bloque se queda en su grupo y lleva su nombre — un atajo no mueve lo que abrevia |
Métodos #
| Método | Función | |
|---|---|---|
of_add_command (string as_key, string as_label, string as_group) | Declara una acción: su identificador, su etiqueta y el grupo bajo el que aparece. Devuelve 0 una vez añadida, -5 si la clave está vacía, contiene /, ` | o una coma (is_recent es una lista separada por comas), o ya está ocupada. Decenas de miles de comandos siguen fluidos: la paleta solo dibuja las líneas visibles. Un comando con grupo vacío va **primero**, sin encabezado; of_get_last_error` dice por qué se rechazó una clave |
of_add_command (string as_key, string as_label, string as_group, string as_hint, string as_shortcut, string as_keywords) | Lo mismo, con la explicación a la derecha, el atajo a mostrar, que lanza su comando mientras la paleta está abierta — así es como se aprende ; fuera, su aplicación conserva sus propios aceleradores, y al escribir Ctrl+C, Ctrl+V, Ctrl+Z y Ctrl+A siguen siendo del cuadro de búsqueda — y palabras clave que la búsqueda lee sin mostrarlas. Devuelve 0 una vez añadida, -5 si la clave está vacía, contiene /, ` | o una coma (is_recent es una lista separada por comas), o ya está ocupada. Un comando con grupo vacío va **primero**, sin encabezado; of_get_last_error` dice por qué se rechazó una clave |
of_insert_command (string as_key, string as_label, string as_group, long al_index) | Declara una acción en una posición elegida (1 = la primera) en lugar de al final: un módulo compartido coloca sus comandos donde corresponde. 0 o menos, o más allá del final, añade al final. Explicación, atajo, palabras clave e icono se ponen después con of_command. Devuelve 0 una vez añadida, -5 para las mismas claves que of_add_command | |
of_insert_command (string as_key, string as_label, string as_group, string as_hint, string as_shortcut, string as_keywords, long al_index) | La forma completa, como la toma of_add_command: la explicación, el atajo que mostrar y las palabras clave llegan con el comando, en su posición. Mismos valores devueltos | |
of_remove_command (string as_key) | Quita una acción; las demás quedan. Devuelve 0 una vez quitada, -5 si ningún comando tiene esa clave | |
of_command (string as_key) → n_pbt_commandpalette_command | El handle de un comando, para renombrarlo, cambiar su atajo, atenuarlo u ocultarlo mediante sus propiedades. Atenuar en lugar de quitar: quitar lo que el usuario no puede hacer ahora le quita también toda posibilidad de descubrir que existe. El estado viaja con los comandos: un cambio hecho con la paleta abierta se ve en la siguiente apertura. Una clave que ningún comando lleva da un handle que no designa nada: sus booleanos se leen FALSE, sus textos "", y una escritura se pierde — of_get_last_error lo dice | |
of_key ( ) → string | En el handle que devuelve of_command: la clave del comando que designa — lo que of_command recibió para obtenerlo, y lo que se guarda cuando el handle pasa de mano en mano | |
of_clear_commands ( ) | Vacía la paleta, incluidos los comandos leídos de un menú (of_load_menu). Devuelve 0 | |
of_count ( ) → long | Devuelve el número de comandos que lleva la paleta | |
of_keys_at ( long al_index ) → string | El identificador del comando en la posición al_index (desde 1), o "" más allá de cualquiera de los extremos. Con of_count, esto permite recorrer una paleta que uno no ha llenado — un módulo compartido añade los suyos | |
of_has ( string as_key ) → boolean | ¿Existe un comando bajo este identificador? Preguntar es mejor que adivinar: of_add_command rechaza (-5) un identificador ya ocupado | |
of_anchor_under ( dragobject ado_control ) | Ancla la paleta bajo un control — un campo, un botón: pone is_position en POSITION_ABSOLUTE e il_x / il_y en la esquina inferior izquierda del control, en píxeles de pantalla. Llámelo antes de of_open; la paleta sigue trayéndose de vuelta a la pantalla. Devuelve 0, o -5 si el control no es válido. Un control (o una ventana) que se lee de derecha a izquierda da su esquina inferior derecha: la paleta se alinea en ese borde y se abre hacia la izquierda | |
of_open ( ) | Abre la paleta: una ventana propia, poseída por ipo_owner, colocada por is_position. Toma el foco y lo devuelve al cerrarse. Devuelve 0 una vez pedida — le sigue siempre ue_opened (en pantalla) o ue_closed (con el motivo por el que no apareció) —, -6 si falta el runtime WebView2, -4 si su ventana no pudo crearse. Los comandos leídos de un menú (of_load_menu) toman el estado de su elemento en ese momento | |
of_is_open ( ) | VERDADERO mientras la paleta está en pantalla. Es lo que permite al atajo alternar: pulsado una segunda vez una paleta se cierra — volver a llamar a of_open destruiría la ventana para reconstruirla idéntica, lo que se ve como un parpadeo, no como un cierre. La DLL sigue sin decidir nada: informa. Una vez abierta, la paleta tiene el foco en su propia ventana: el atajo pulsado allí la cierra por sí solo. Responde por la paleta de este objeto: cuando otro objeto paleta abre la suya, sustituye a esta y of_is_open responde FALSO aquí | |
of_close ( ) | Cierra la paleta que este objeto abrió — nunca la que otro objeto paleta abrió después. Perder el foco también la cierra, como un menú. Devuelve 0 | |
of_register_shortcut ( ) | Entrega el atajo de is_shortcut a la DLL. Llámelo una vez al abrir la ventana. Un solo atajo por objeto paleta: volver a llamarlo tras cambiar is_shortcut sustituye al anterior, que deja de responder de inmediato — nunca hay nada que quitar antes. Devuelve 0 si se puso, 1 si sustituyó a uno, 2 si un is_shortcut vacío no deja ningún atajo (quitado, o no había), -5 si la tecla es de las que el gancho no ve (véase arriba) — el atajo anterior se conserva entonces. Sin ipo_owner, el atajo responde en todas las ventanas de la aplicación. Dos objetos paleta de una misma ventana conservan cada uno el suyo; el mismo atajo registrado por un segundo objeto pasa a este (1). Destruir el objeto quita su atajo — nunca el que tiene otro objeto paleta. El atajo tomado por un segundo objeto vuelve al primero cuando el segundo se destruye. Mientras una ventana está activa, el atajo de la paleta pasa antes que los aceleradores de su menú PowerBuilder: un elemento de menú en la misma tecla ya no lo oye | |
of_process_events ( ) | Recoge los eventos en espera y los lanza en el propio objeto paleta. El componente lo llama solo mientras la paleta vive: no tiene que hacerlo. Un evento que abre una MessageBox no ve los siguientes lanzados en medio, y un evento que cierra la ventana de la paleta detiene la recogida limpiamente | |
of_reset ( ) → long | Vacía los comandos y la memoria de uso (is_recent), devuelve las propiedades a sus valores predeterminados, cierra una paleta abierta y devuelve un atajo registrado a SHORTCUT_DEFAULT. ipo_owner e ipo_receiver quedan intactos: son el cableado, no el contenido. Los comandos leídos de un menú se van también Devuelve 0 una vez hecho. | |
of_load_menu ( menu am_menu ) | Llena la paleta desde un menú PowerBuilder: cada elemento sin subelementos se vuelve un comando, sin declarar sus acciones dos veces — pase this.MenuID o uno de sus elementos. Clave = el ClassName del elemento, etiqueta = su texto sin & ni el atajo escrito tras un tabulador, grupo = los textos de los elementos de encima, atajo = el que muestra, palabras clave = su MicroHelp. El menú sigue siendo el maestro: releído en cada of_open, un elemento desactivado, oculto o renombrado se muestra tal como está (un padre arrastra a sus elementos). Elegir un comando lanza ue_command_selected y no ejecuta nada. Una segunda llamada reemplaza los comandos de la primera; los de of_add_command se quedan. Devuelve 0, -5 si el menú no es válido | |
of_loaded_item ( string as_key ) → menu | El elemento de menú PowerBuilder del que viene un comando (of_load_menu): en ue_command_selected, of_loaded_item(as_key).TriggerEvent(Clicked!) ejecuta lo que ejecuta el menú. Una clave que no viene de un menú da una referencia no válida: compruébela con IsValid | |
of_get_last_error ( ) → string | Por qué la última llamada devolvió -5 (una clave rechazada, un menú no válido, un atajo que el teclado no sabe notificar), o la última escritura de un handle de comando que no llegó a ningún comando. "" cuando nada falló: cada llamada que actúa lo vacía primero |
Propiedades de un comando — n_pbt_commandpalette_command #
Obtenida con of_command(clave). La paleta reconstruye su ventana desde su lista en cada of_open: una propiedad cambiada mientras está abierta se ve en la siguiente apertura.
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
is_label | string | — | El texto de la fila |
is_shortcut | string | "" | El atajo mostrado a la derecha de la fila, y activo mientras la paleta está abierta (Ctrl+Shift+S) |
is_group | string | — | El grupo bajo el que figura el comando; cambiarlo lo mueve sin quitarlo (conserva su posición entre los comandos) |
is_hint | string | "" | La pequeña línea bajo la etiqueta |
is_keywords | string | "" | Las palabras que la búsqueda lee sin mostrarlas — las palabras del usuario |
is_icon | string | "" | Un icono a la izquierda de la fila: un archivo, una imagen de biblioteca, o mono: / tint: para uno que sigue el tema |
ib_enabled | boolean | true | Comando atenuado: visible, buscable e inerte — ni clic, ni Intro, ni su atajo |
ib_visible | boolean | true | Comando oculto: fuera de la lista y de los atajos, sin ser eliminado; vuelve tal cual |
Eventos #
| Evento | Se dispara cuando |
|---|---|
ue_command_selected (string as_key) | El usuario ha elegido una acción. La paleta ya se ha cerrado: hacer lo que anuncia le toca a usted. El botón izquierdo, Intro o el atajo mostrado en una fila eligen; un clic derecho o central no hace nada. El evento puede abrir una MessageBox o cerrar la ventana |
ue_shortcut ( ) | Se ha pulsado el atajo. La DLL avisa, PB decide. Una paleta alterna con su propia tecla: if of_is_open() then of_close() else of_open() — pulsado dentro de la paleta abierta, el atajo la cierra por sí solo. También puede negarse |
ue_opened ( ) | La paleta está en pantalla — mediante of_open |
ue_closed (string as_reason) | Acaba de cerrarse, se haya elegido algo o no. Sigue a cada of_open que devolvió 0: as_reason está vacío para una paleta que estaba en pantalla, cancelled si se cerró — o fue sustituida por otra paleta — antes de aparecer, failed si su ventana no pudo nacer, blocked bajo depuración remota sin licencia |
La paleta no hace nada por sí misma. Informa del identificador elegido y se cierra. Es su aplicación la que actúa — la misma acción, lanzada desde un menú o desde la paleta, pasa por el mismo código.
Desde el teclado #
| Tecla | Efecto |
|---|---|
El atajo de is_shortcut | Avisa a su código con ue_shortcut; es él quien abre |
| Escritura | Filtra sobre la marcha: las letras no tienen por qué seguirse, nva encuentra « Nuevo archivo », y los acentos no cuentan (preferences encuentra « Préférences ») |
| Flechas arriba / abajo | Mueven la selección por la lista |
| Intro | Elige la acción seleccionada (ue_command_selected) |
| El atajo mostrado en una fila | Lanza ese comando, sin tener que seleccionarlo |
| Escape | Cierra sin elegir nada |
| Re Pág / Av Pág | Mueven la selección una pantalla |
| Inicio / Fin | Con texto escrito: al principio / al final de la búsqueda. Campo vacío: al primer / último comando. Ctrl+Inicio / Ctrl+Fin: siempre el primer / último comando; Mayús+… selecciona en el campo |
| Tab | Se queda en el campo de búsqueda (la paleta es un diálogo modal) |
| Un clic derecho o central en una fila | No hace nada: solo el botón izquierdo elige |
Mientras un método de entrada (japonés, chino, coreano) compone, Intro y las flechas le pertenecen: confirmar una conversión nunca lanza un comando.
Ejemplos #
Alimentar la paleta desde su menú #
// Every action of your menu becomes a command : nothing declared twice
inv_palette.of_load_menu(/*menu*/ this.MenuID)
// The palette answers its key from the window's opening
inv_palette.of_register_shortcut()
// Local variables
menu lm_item
// event ue_command_selected of inv_palette : run what the menu item runs
lm_item = inv_palette.of_loaded_item(/*key*/ as_key)
if IsValid(lm_item) then lm_item.TriggerEvent(Clicked!)
Las palabras que lee la búsqueda #
// Las palabras clave no se ven, pero la busqueda las lee :
// escribir "pdf" encuentra la exportacion aunque la etiqueta no lo diga
inv_palette.of_add_command(/*key*/ "export", /*label*/ "Export", /*group*/ "File", /*hint*/ "PDF, CSV or xlsx", /*shortcut*/ "Ctrl+E", /*keywords*/ "pdf csv xlsx")
Elegir otro atajo #
// Ctrl+K ya lo usa su aplicacion ? Elija otro.
// of_register_shortcut lo entrega, y el anterior se va solo.
inv_palette.is_shortcut = "ctrl+shift+p"
inv_palette.of_register_shortcut()
Anclarla bajo un campo #
// Anclada bajo un campo, en pixeles de pantalla
// La paleta se trae de vuelta a la pantalla si se salia
inv_palette.of_anchor_under(/*control*/ sle_1)
inv_palette.is_placeholder = "Type a command..."
inv_palette.of_open()
// Remove one command, empty the list, close the palette
inv_palette.of_remove_command(/*key*/ "print")
inv_palette.of_clear_commands()
inv_palette.of_close()
Buenas prácticas #
- ¿Ya tiene un menú PowerBuilder?
of_load_menu(this.MenuID)lo convierte en comandos, y el menú sigue siendo el maestro. - Dé a cada comando el mismo identificador que en su menú: una sola función trata ambos, y el usuario obtiene exactamente lo mismo.
- Llame a
of_register_shortcut()al abrir la ventana, no en el primerof_open: una paleta que solo responde a su tecla después de abrirse con el ratón no sirve de nada. - Rellene las palabras clave: es lo que separa una paleta que se usa de una en la que nunca se encuentra nada. Piense en las palabras del usuario, no en las suyas.
- Muestre el atajo de la acción en
as_shortcut: la paleta se convierte así en la manera de aprenderlos. - Ponga solo acciones inmediatas. Un comando que abre un diálogo de configuración, sí; uno que necesita tres parámetros, no.
- Quite los comandos que ya no tienen sentido en lugar de dejarlos fallar: una paleta que ofrece lo imposible pierde la confianza de una vez.