# 6. Funciones transversales #

← Idioma y RTL · Índice · FAQ →

Este capítulo reúne los servicios disponibles sea cual sea el componente: tooltips, alojamiento de controles PowerBuilder, arrastrar y soltar desde el Explorador, foco de teclado, exportación de imagen y los objetos de utilidad no visuales.

## 6.1 Tooltips simples y enriquecidos #

### Tooltip del componente #

    uo_bouton.is_tooltip = "Guardar el expediente (Ctrl+S)"

El texto acepta el texto enriquecido con etiquetas: `[b]`, `[br]`, `[color=…]`, `[picture=…]`…

### Tooltip enriquecido (título + texto + imagen) #

Para una ayuda contextual al estilo de la cinta de opciones de Office:

    uo_bouton.is_super_tooltip_title = "Guardar"
    uo_bouton.is_super_tooltip_text  = "Escribe las modificaciones en el servidor." &
                                       + "[br][br][size-=15]Atajo: Ctrl+S[/size-=15]"
    uo_bouton.is_super_tooltip_image = "img\help_save.png"

Las tres propiedades son independientes: un título solo, o un título más texto sin imagen, son válidos. En cuanto se establece una propiedad `is_super_tooltip_*`, esta prevalece sobre `is_tooltip`.

### Tooltip de un item #

Toda clase de item (`n_pbt_item` y sus descendientes) lleva las mismas cuatro propiedades:

    uo_toolbar.of_bar("main").of_item("save").is_tooltip = "Guardar"

    uo_tab.of_item("clients").is_super_tooltip_title = "Clientes"
    uo_tab.of_item("clients").is_super_tooltip_text  = "128 fichas, última sincronización a las 09:12"

### Comportamiento #

- El tooltip es una ventana nativa con tema, idéntica en todos los componentes (no está limitada por las fronteras de la webview).
- No se muestra si su aplicación no tiene el foco: pasar el ratón por encima de una ventana en segundo plano no activa nada.
- Desaparece cuando usted cambia a otra aplicación, y como muy tarde al cabo de 10 segundos.
- `of_reset()` elimina los tooltips establecidos sobre la instancia y sobre sus items.

## 6.2 Alojar controles reales de PowerBuilder #

Los componentes contenedores no muestran HTML en lugar de sus pantallas: alojan controles reales de PowerBuilder (userobjects, DataWindows, grupos de controles), reasignados como ventanas Win32 hijas. Sus pantallas existentes se reutilizan tal cual.

    // Pestanas: cada pagina es un userobject PB
    uo_tab.of_add_page("clients",   "Clientes",   uo_page_clients)
    uo_tab.of_add_page("factures",  "Facturas",  uo_page_factures, /*cerrable*/ true)

    // Paneles acoplables: lo mismo
    uo_dock.is_main = "doc"                       // zona central
    uo_dock.of_add_panel("doc",      uo_dock.POSITION_STACK, "", 0,   "Documento",    uo_editeur)
    uo_dock.of_add_panel("explorer", uo_dock.POSITION_START, "", 240, "Explorador", uo_arbre)
    uo_dock.of_add_panel("props",    uo_dock.POSITION_END,   "", 260, "Propiedades",  uo_props)

Lo que se gestiona por usted:

- el posicionamiento y el redimensionamiento del control alojado cuando la pestaña o el panel cambia de tamaño;
- la visualización / ocultación al cambiar de pestaña o de panel activo;
- los paneles flotantes, acoplados u ocultados automáticamente (dockcontainer);
- la destrucción limpia al cerrarse la ventana.

> ⚠️ Un control alojado es una ventana nativa: se dibuja por encima de la capa web. Es intencionado (su DataWindow se mantiene nítida y rápida), pero significa que ningún efecto web — sombra, transparencia, animación — puede pasar por encima de él.

## 6.3 Recibir archivos desde el Explorador de Windows #

Un componente puede convertirse en destino de soltado para archivos arrastrados desde el Explorador. La biblioteca instala un destino de soltado nativo: usted recibe las rutas completas, algo que un soltado HTML no permite.

    uo_editeur.ib_allow_drop = true

    // event ue_drop_files de uo_editeur: (string as_files[])
    long ll_i

    for ll_i = 1 to UpperBound(as_files)
        of_ouvrir_fichier(as_files[ll_i])
    next

Evento | Se activa cuando
--- | ---
`ue_drag_enter ( )` | Un arrastre de archivos entra en el componente
`ue_drag_leave ( )` | Sale de él sin soltar
`ue_drop_files (string as_files[])` | Los archivos se sueltan — rutas completas

El propio componente proporciona la respuesta visual al pasar el cursor (resaltado de la zona de soltado). Publicado por los componentes en los que soltar tiene sentido: `statictext`, `codeeditor`.

## 6.4 Teclado y foco #

Un componente PBToolboxAI participa en la navegación por teclado de su ventana igual que un control nativo:

- la tecla Tab lo alcanza en el orden de tabulación de la ventana;
- las teclas (flechas, Intro, Esc, entrada de datos) las trata el componente que tiene el foco;
- los atajos de ventana (Intro = botón predeterminado, Esc = cancelar) siguen funcionando incluso cuando el foco está dentro de un componente.

Para dar explícitamente el foco al contenido de un componente (por ejemplo, después de abrir un panel de búsqueda):

    uo_editeur.of_focus_webview()

## 6.5 Exportar la representación como imagen #

Recordatorio de la base común: todo componente se exporta tal como se muestra.

    uo_pivot.of_save_as_png("C:\temp\tableau.png")
    uo_pivot.of_save_as_jpg("C:\temp\tableau.jpg")

Útil para adjuntar un gráfico a un correo electrónico, alimentar un informe o documentar una incidencia de usuario.

## 6.6 Cuadros de diálogo y notificaciones #

Dos servicios sin ningún control que colocar en la ventana:

    // Cuadro de dialogo modal con tema (retorno sincrono)
    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox
    lnv_mb.is_title   = "Eliminación"
    lnv_mb.is_message = "¿Eliminar definitivamente [b]12 expedientes[/b]?"
    lnv_mb.is_icon    = lnv_mb.ICON_QUESTION
    lnv_mb.of_add_button("Eliminar", /*predeterminado*/ false, /*cancelacion*/ false)
    lnv_mb.of_add_button("Cancelar",   /*predeterminado*/ true,  /*cancelacion*/ true)

    if lnv_mb.of_show(Handle(this)) = 1 then of_supprimer()
    destroy lnv_mb

    // Notificacion "toast" en una esquina de la pantalla, no bloqueante
    n_pbt_toaster lnv_toast

    lnv_toast = create n_pbt_toaster
    lnv_toast.is_title = "Importación finalizada"
    lnv_toast.is_text  = "1 240 filas integradas."
    lnv_toast.is_kind  = lnv_toast.KIND_SUCCESS
    lnv_toast.of_show()
    destroy lnv_toast

Detalles completos: messagebox y toaster.

## 6.7 Objetos de utilidad no visuales #

Entregados en la misma PBL, sin webview ni representación: son simples envoltorios alrededor de la DLL. Créelos, úselos, destrúyalos.

### Codificación Base64 — `u_pbt_base64` #

    u_pbt_base64 lnv_b64
    string ls_encode

    lnv_b64 = create u_pbt_base64
    ls_encode = lnv_b64.of_encode("Hola")        // texto -> UTF-8 -> Base64
    ls_texte  = lnv_b64.of_decode(ls_encode)     // "" si la entrada no es valida
    destroy lnv_b64

### Huellas — `u_pbt_hash` #

    u_pbt_hash lnv_hash

    lnv_hash = create u_pbt_hash
    ls_empreinte = lnv_hash.of_sha256("contrasena")              // hexadecimal en minusculas
    ls_fichier   = lnv_hash.of_file("SHA256", "C:\livraison.zip")
    destroy lnv_hash

Método | Función
--- | ---
`of_string (string as_algo, string as_texte)` | Huella de una cadena — `MD5`, `SHA1`, `SHA256`, `SHA384`, `SHA512`
`of_file (string as_algo, string as_chemin)` | Huella del contenido de un archivo (`""` si es ilegible)
`of_md5` · `of_sha1` · `of_sha256` · `of_sha512` | Atajos

### Expresiones regulares — `u_pbt_regex` #

Sintaxis ECMAScript, ausente de PowerScript.

    u_pbt_regex lnv_re
    string ls_trouves[]

    lnv_re = create u_pbt_regex

    if lnv_re.of_is_match("^[\w.]+@[\w.]+\.\w{2,}$", ls_email) then …

    ls_annee = lnv_re.of_match("(\d{4})-(\d{2})-(\d{2})", ls_date, /*grupo*/ 1)
    ls_propre = lnv_re.of_replace("\s+", ls_saisie, " ")
    ll_nb = lnv_re.of_match_all("[A-Z]{2}\d{6}", ls_texte, ls_trouves)

    destroy lnv_re

Método | Función
--- | ---
`of_is_match (patrón, texto [, ab_ignore_case | al_flags])` | ¿Coincide el texto?
`of_match (patrón, texto, ai_groupe [, al_flags])` | Primera coincidencia (`0` = todo, `1..` = grupo de captura)
`of_match_all (patrón, texto [, ai_groupe, al_flags], ref as_res[])` | Todas las coincidencias; devuelve el número
`of_replace (patrón, texto, sustitución)` | Sustituye todas las apariciones (`$1`… permitidos)

Opciones combinables: `FLAG_IGNORE_CASE` (1), `FLAG_SINGLELINE` (2, el `.` atraviesa los saltos de línea).

### Identificadores únicos — `u_pbt_guid` #

    u_pbt_guid lnv_guid

    lnv_guid = create u_pbt_guid
    ls_id = lnv_guid.of_new()          // 1b4e28ba-2fa1-11d2-883f-0016d3cca427
    ls_id = lnv_guid.of_new_braces()   // {1b4e28ba-...}
    ls_id = lnv_guid.of_new_plain()    // 1b4e28ba2fa111d2883f0016d3cca427
    destroy lnv_guid

### Archivos ZIP — `u_pbt_zip` #

    u_pbt_zip lnv_zip

    lnv_zip = create u_pbt_zip
    lnv_zip.of_compress("C:\temp\livraison.zip", "C:\appli\export")   // archivo O carpeta
    lnv_zip.of_extract("C:\temp\livraison.zip",  "C:\appli\import")   // carpeta creada si falta
    destroy lnv_zip

Los dos métodos devuelven un `boolean`.

## 6.8 Información sobre la biblioteca #

    // Version de la DLL
    string ls_version

    ls_version = Space(32)
    PBT_GetVersion(ls_version, 32)

Función global | Función
--- | ---
`PBT_GetVersion (ref string, long)` | Versión de la biblioteca
`PBT_CheckRuntime (ref string, long)` | Versión del runtime WebView2 instalado (`≤ 0` = ausente)
`PBT_GetLastErrorMessage (ref string, long)` | Último mensaje de error del proceso
`PBT_LicenseStatus ( )` | Estado de la licencia — véase Licencia

## 6.9 Imprimir #

Todo componente sabe imprimirse, tal como se muestra, sin DataWindow intermedia.

    // Silencioso: un PDF en disco, nada que pulsar
    uo_grille.of_print_to_pdf("C:\etats\ventes.pdf")

    // Horizontal, para una cuadricula ancha
    uo_grille.of_print_to_pdf(/*fichier*/ "C:\etats\ventes.pdf", /*paysage*/ true)

    // Con dialogo: el usuario elige su impresora y ve la vista previa
    uo_grille.of_print()

    // Directamente el dialogo de impresion del sistema
    uo_grille.of_print(/*dialogue systeme*/ true)

Método | Función
--- | ---
`of_print_to_pdf (string as_path)` · `of_print_to_pdf (string, boolean ab_landscape)` | Escribe un PDF sin mostrar nada. Solo devuelve el control una vez escrito el archivo (`0` = hecho)
`of_print ( )` · `of_print (boolean ab_system_dialog)` | Abre el diálogo de impresión. Devuelve el control en cuanto el diálogo está abierto: lo que el usuario haga con él es cosa suya

> ⚠️ Se imprime lo que está RENDERIZADO. Una cuadrícula virtualizada solo imprime las filas que tiene: para un informe completo, pase antes a una disposición que las muestre todas (paginación), o exporte los datos en lugar del renderizado.

El código de retorno `-6` señala un runtime WebView2 demasiado antiguo para imprimir (1.0.1108 para el PDF, 1.0.1587 para el diálogo). Todo lo demás sigue los códigos de retorno comunes.

← Idioma y RTL · Índice · FAQ →