# dockcontainer — `u_pbt_dockcontainer` #

← Referencia de componentes · Índice de la guía

> Paneles acoplables al estilo de Visual Studio: acoplamiento mediante arrastrar y soltar, apilamiento en pestañas, separadores redimensionables, ventanas flotantes, ocultación automática — y guardado/restauración de la disposición.

> ▶ Verlo en vivo — Aplicación de demostración, mosaico Dock container: la vista previa, el código que lo genera y esta página, uno al lado del otro.

## De un vistazo #

Userobject | `u_pbt_dockcontainer`
Clase de items | `n_pbt_dock_panel` (un panel)
Sirve para | Dar a una ventana PowerBuilder la ergonomía de un IDE moderno: el usuario organiza él mismo sus paneles, y la disposición reaparece en la sesión siguiente

Al igual que tab, cada panel aloja un control real de PowerBuilder (`dragobject`): userobject, DataWindow u otro componente PBToolboxAI. Véase Alojar controles reales de PowerBuilder.

## Inicio rápido #

    // event open de la ventana : los controles de panel ya estan colocados en ella
    uo_dock.of_add_panel(/*clave*/ "document", /*posicion*/ "", /*relativo_a*/ "", &
                         /*tamano*/ 0, /*titulo*/ "Documento", /*contenido*/ uo_editeur)

    uo_dock.of_add_panel(/*clave*/ "explorateur", /*posicion*/ uo_dock.POSITION_START, &
                         /*relativo_a*/ "document", /*tamano*/ 260, &
                         /*titulo*/ "Explorador", /*contenido*/ uo_arbre)

    uo_dock.of_add_panel(/*clave*/ "proprietes", /*posicion*/ uo_dock.POSITION_END, &
                         /*relativo_a*/ "document", /*tamano*/ 300, &
                         /*titulo*/ "Propiedades", /*contenido*/ uo_props)

    // La zona central : ni cerrable por el acoplamiento, ni flotante, ni ocultable
    uo_dock.is_main = "document"

## Propiedades #

Propiedad | Tipo | Predeterminado | Función
--- | --- | --- | ---
`is_main` | string | `""` | Clave del panel principal: la zona de documento central, que no puede ocultarse ni desacoplarse. El panel debe existir ya
`is_theme_style` | string | `fluent` | Estilo visual del componente (constantes `THEME_STYLE_*`)
`is_theme_mode` | string | `light` | Variante clara u oscura (constantes `THEME_MODE_*`)
`il_theme_accent` | long | `-1` | Color de acento de este componente (`-1` = acento 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

### Posiciones de acoplamiento #

Las constantes del componente alimentan `as_position` en `of_add_panel` y `of_move_panel`:

Constante | Valor | Efecto
--- | --- | ---
`POSITION_START` | `"start"` | El nuevo panel se acopla por el lado de inicio de lectura del panel de referencia (a la izquierda en escritura de izquierda a derecha)
`POSITION_END` | `"end"` | … por el lado de fin de lectura
`POSITION_TOP` | `"top"` | … encima
`POSITION_BOTTOM` | `"bottom"` | … debajo
`POSITION_STACK` | `"stack"` | El panel se apila como pestaña sobre el panel de referencia. Valor adoptado si `as_position` está vacío

### Propiedades de un panel — `n_pbt_dock_panel` #

Obtenidas mediante `of_item(clave)`.

Propiedad | Tipo | Predeterminado | Función
--- | --- | --- | ---
`is_title` | string | `""` | Título mostrado en la pestaña del panel. Acepta el texto enriquecido con etiquetas
`is_short_title` | string | `""` | Forma corta del título, para los lugares donde falta espacio: el raíl de un panel anclado (siempre — es una franja estrecha) y la pestaña de una pila, pero solo cuando el título completo ya no cabe, algo que se mide en lugar de adivinarse. La cabecera del panel conserva el título completo. `""` = sin forma corta
`ib_visible` | boolean | `true` | Muestra u oculta este panel
`ib_pinned` | boolean | `true` | `true` = fijado en su sitio; `false` = el panel se repliega en una lengüeta sobre el borde y solo se despliega al pasar el cursor (ocultación automática)
`is_header_color` | string | `""` | Color de la cabecera de este panel. Vacío = decide el tema; `HEADER_COLOR_ACCENT` sigue el acento del tema (y lo sigue tras un cambio de tema, cosa que un código fijo no haría); si no, un `#rrggbb`. El color de texto legible se calcula
`is_border_color` | string | `""` | Color del borde de este panel, misma gramática. Enmarca el marco y la cabecera, que tienen cada uno el suyo: colorear solo uno deja una costura visible. Acompaña al panel en su panel deslizante
`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

## Métodos #

Método | Función
--- | ---
`of_add_panel (string as_key, string as_position, string as_relative_to, integer ai_size, string as_title, dragobject ado_content)` | Añade un panel cerrable y aloja el control. `as_relative_to` = clave del panel contra el que se acopla (vacío = la raíz); `ai_size` = tamaño inicial en píxeles (`0` = automático)
`of_add_panel (…, boolean ab_closable)` | Ídem, con `ab_closable = false` para un panel sin botón de cierre
`of_select_panel (string as_key)` | Pone un panel en primer plano dentro de su grupo de pestañas
`of_move_panel (string as_key, string as_target, string as_position)` | Reorganiza desde el código, exactamente como si el usuario hubiera arrastrado la pestaña
`of_move_panel (string as_key, string as_target, string as_position, integer ai_index)` | Lo mismo, indicando el rango del panel en la pila del destino (0 = primero, `-1` = último). Solo una pila es una lista ordenada: el índice se ignora para `POSITION_START` / `END` / `TOP` / `BOTTOM`
`of_float_panel (string as_key)` | Desacopla el panel en una auténtica ventana flotante desplazable y redimensionable. Al cerrarla, el panel se vuelve a acoplar (`ue_panel_docked`)
`of_notify_panel (string as_key)` | Señala contenido nuevo: si el panel no está visible, su pestaña muestra un contador de elementos no vistos, que se borra al seleccionarlo
`of_clear_notify (string as_key)` | Borra ese contador sin mostrar el panel. Seleccionar la pestaña era la única otra forma, lo cual es incorrecto cuando su código sabe que el contenido en sí ha desaparecido
`of_remove_panel (string as_key)` | Retira el panel y devuelve el control a su ventana de origen
`of_get_layout ( )` | Devuelve la disposición actual (árbol de divisiones, proporciones, pestañas, visibilidad) en forma de cadena, para almacenarla en un archivo, una base de datos o el registro
`of_set_layout (string as_json)` | Restaura una disposición obtenida con `of_get_layout`. Los paneles deben haberse vuelto a crear antes de la llamada; los ausentes de la disposición se adjuntan al primer grupo
`of_item (string as_id)` | Handle `n_pbt_dock_panel` del panel (creado en el primer acceso)
`of_refresh_panel (string as_key)` | Actualiza la representación de un panel construido fuera de pantalla, sin parpadeo
`of_relayout ( )` | Recalcula y vuelve a publicar todas las zonas para que los controles alojados se reposicionen
`of_reset ( )` | Vacía el contenedor: cada control alojado vuelve a su ventana de origen, los handles de paneles se liberan y la disposición memorizada se borra
`of_set_redraw (boolean)` | Agrupa una ráfaga de modificaciones en una sola representación
`of_save_as_png (string)` · `of_save_as_jpg (string)` | Exporta la representación como imagen

## Eventos #

Evento | Se activa cuando
--- | ---
`ue_panel_selected (string as_key)` | Un panel pasa a ser el panel activo de su grupo
`ue_panel_closed (string as_key)` | El usuario cierra un panel
`ue_panel_pinned (string as_key, boolean ab_pinned)` | Un panel se fija (`true`) o se desfija en ocultación automática (`false`)
`ue_panel_floated (string as_key)` | Un panel se desacopla en ventana flotante
`ue_panel_docked (string as_key)` | Un panel flotante se vuelve a acoplar
`ue_layout_changed (string as_json)` | La disposición ha cambiado (arrastre, redimensionamiento, acoplamiento). El parámetro lleva la nueva disposición, lista para guardarse
`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`)

## Con el teclado #

El contenido de un panel es un verdadero control PowerBuilder: allí el teclado pertenece a su código, como en cualquier ventana. De lo que se encarga el componente es de su propio armazón — encabezados, pestañas, divisores:

Tecla | Efecto
--- | ---
Flechas sobre una pestaña | Pasan al panel anterior / siguiente del grupo y lo seleccionan. Una banda de pestañas es una sola parada de tabulación
Inicio / Fin sobre una pestaña | Primer / último panel del grupo
Flechas sobre un divisor | Desplazan la separación un 2 %, únicamente en el eje del divisor
Re Pág / Av Pág sobre un divisor | Lo mismo, en pasos del 10 %
Esc | Cierra el panel deslizante abierto desde un botón de borde

Un divisor es un `separator` enfocable que anuncia su posición; los botones del encabezado (desacoplar, ocultar, cerrar) llevan un nombre, y el panel activo de un grupo está marcado con `aria-selected`. Un desplazamiento con el teclado se informa en `ue_layout_changed` exactamente igual que un arrastre con el ratón.

## Ejemplos #

### Una ventana al estilo de un IDE #

    // event open : cada contenido es un control PB real colocado en la ventana
    uo_dock.of_add_panel("document", "", "", 0, "Documento", uo_editeur)
    uo_dock.of_add_panel("explorateur", uo_dock.POSITION_START,   "document", 260, "Explorador", uo_arbre)
    uo_dock.of_add_panel("proprietes",  uo_dock.POSITION_END,  "document", 300, "Propiedades",  uo_props)
    uo_dock.of_add_panel("sortie",      uo_dock.POSITION_BOTTOM, "document", 200, "Salida",      uo_console)

    // Un segundo panel apilado como pestana sobre "proprietes"
    uo_dock.of_add_panel("aide", uo_dock.POSITION_STACK, "proprietes", 0, "Ayuda", uo_aide)

    uo_dock.is_main = "document"

### Memorizar y restaurar la disposición del usuario #

    // event close de la ventana : guardar lo que el usuario ha organizado
    string ls_disposition
    ls_disposition = uo_dock.of_get_layout()
    of_enregistrer_preference("dock_principal", ls_disposition)

    // event open : VOLVER A CREAR primero los paneles, restaurar despues
    string ls_disposition

    of_creer_les_panneaux()          // las llamadas of_add_panel anteriores

    ls_disposition = of_lire_preference("dock_principal")
    if ls_disposition <> "" then uo_dock.of_set_layout(ls_disposition)

> El orden es obligatorio: `of_set_layout` no crea ningún panel, solo recoloca los que ya existen.

### Seguir los cambios de forma continua #

    // event ue_layout_changed de uo_dock : (string as_json)
    // Guardado inmediato, sin esperar al cierre de la ventana.
    of_enregistrer_preference("dock_principal", as_json)

### Controlar un panel mediante su handle #

    n_pbt_dock_panel lnv_panneau

    lnv_panneau = uo_dock.of_item("proprietes")
    lnv_panneau.is_title  = "Propiedades (3 modificadas)"
    lnv_panneau.ib_pinned = false        // se repliega en una lengueta sobre el borde

    // Ocultar un panel reservado a los administradores
    uo_dock.of_item("audit").ib_visible = gb_administrateur

### Llamar la atención sobre un panel en segundo plano #

    // Un proceso en segundo plano ha escrito en la consola : avisar sin robar el foco
    uo_dock.of_notify_panel("sortie")

### Reorganizar desde el código #

    // Mover un panel como si el usuario hubiera arrastrado su pestana
    uo_dock.of_move_panel(/*clave*/ "sortie", /*destino*/ "document", /*posicion*/ "bottom")

    // Apilarlo como pestana sobre otro panel
    uo_dock.of_move_panel(/*clave*/ "aide", /*destino*/ "proprietes", /*posicion*/ "stack")

### Desacoplar un panel en una segunda pantalla #

    // Ventana flotante nativa : el usuario puede colocarla en otra pantalla
    uo_dock.of_float_panel("proprietes")

    // event ue_panel_docked de uo_dock : (string as_key)
    // El usuario ha cerrado la ventana flotante : el panel ha vuelto.
    of_journaliser("Panel reacoplado : " + as_key)

### Cerrar correctamente un panel #

    // event ue_panel_closed de uo_dock : (string as_key)
    // Retirar tambien el panel del contenedor para liberar el control alojado.
    uo_dock.of_remove_panel(as_key)

## Buenas prácticas #

- Designe siempre un panel principal con `is_main`: sin zona central, el usuario puede ocultarlo todo y encontrarse ante una ventana vacía.
- Guarde la disposición en `ue_layout_changed` en lugar de únicamente al cerrar: así un cierre anómalo no pierde nada.
- `of_set_layout` va después de los `of_add_panel`, nunca antes.
- Utilice `of_notify_panel` para los procesos en segundo plano: es menos intrusivo que un cuadro de diálogo y la información permanece visible.
- Un control alojado es una ventana nativa: se dibuja por encima de la capa web, ningún efecto visual del componente pasa por delante de él.
- `of_reset()` antes de cualquier reconstrucción: sin él, los controles alojados anteriormente siguen reasignados al contenedor vaciado y reutilizar una clave falla.
- Para simples páginas exclusivas, sin acoplamiento ni flotación, tab es más ligero.

← Referencia de componentes · Índice de la guía