PowerBuilder

Un MessageBox moderno para toda la aplicación, sin reescribir sus pantallas

AutorLuis Avilan
Publicado
Un MessageBox moderno para toda la aplicación, sin reescribir sus pantallas, artículo de Luis Avilan
PB

0 visualizaciones

La idea no consiste en buscar y reemplazar cientos de llamadas. El overlay conserva la expresión MessageBox(...) que ya existe y cambia, durante el enlace de la aplicación, la función que atiende esa llamada.

El problema de una aplicación madura

Una aplicación PowerBuilder con años de evolución puede contener MessageBox en ventanas, menús, DataWindows, UserObjects y NVO. Cambiar cada llamada introduce trabajo repetitivo y un riesgo innecesario: se puede alterar una combinación de botones, perder un código de retorno o modificar una condición que ya funciona.

Este framework evita esa migración masiva. La aplicación conserva instrucciones como estas:

1MessageBox("Información", "Proceso terminado.")
2MessageBox("Confirmación", "¿Desea continuar?", Question!, YesNo!)
3li_respuesta = MessageBox("Advertencia", &
4 "Existen cambios sin guardar.", Exclamation!, OKCancel!, 2)

La llamada tradicional abre una ventana Response moderna, integrada con el tema activo. La pantalla consumidora no conoce los controles internos del nuevo mensaje.

Qué significa overlay en este proyecto

El overlay es una capa de compatibilidad formada por el objeto global messagebox.srf. Este declara el mismo nombre y las combinaciones de parámetros utilizadas por el MessageBox estándar: dos argumentos; título, texto e icono; icono y botones; y la firma completa con botón predeterminado.

Cuando los objetos de la aplicación se recompilan, PowerBuilder resuelve sus llamadas contra estas funciones globales disponibles en el target. La nueva función recibe exactamente la información que antes llegaba al diálogo estándar, la traduce a una solicitud y delega la presentación al framework.

Paso 1: replicar las firmas públicas

La transparencia comienza en los prototipos. El consumidor sigue compilando porque el nombre, los tipos y el orden de los argumentos coinciden con las formas habituales de llamada.

1forward prototypes
2global function integer messagebox (string as_titulo, string as_mensaje)
3global function integer messagebox (string as_titulo, string as_mensaje, icon ai_icono)
4global function integer messagebox (string as_titulo, string as_mensaje, &
5 icon ai_icono, button abotones)
6global function integer messagebox (string as_titulo, string as_mensaje, &
7 icon ai_icono, button abotones, integer ai_predeterminado)
8end prototypes

Las sobrecargas cortas desembocan en la implementación completa. Así se evita duplicar decisiones y se conserva un único camino para iconos, botones y respuesta predeterminada.

Paso 2: traducir tipos nativos sin cambiar el contrato

La firma completa convierte las enumeraciones nativas Icon y Button en valores internos. Por ejemplo, Question! se transforma en el tipo pregunta y YesNoCancel! en una disposición de tres botones. El botón predeterminado también viaja en la solicitud.

1Choose Case ai_icono
2 Case StopSign!
3 li_tipo = 4
4 Case Exclamation!
5 li_tipo = 3
6 Case Question!
7 li_tipo = 5
8 Case Else
9 li_tipo = 1
10End Choose
11
12Choose Case abotones
13 Case OKCancel!
14 li_botones = 2
15 Case YesNo!
16 li_botones = 3
17 Case YesNoCancel!
18 li_botones = 4
19 Case RetryCancel!
20 li_botones = 5
21 Case AbortRetryIgnore!
22 li_botones = 7
23 Case Else
24 li_botones = 1
25End Choose

Luego el overlay crea el servicio, construye una solicitud normalizada y devuelve un entero. Desde el punto de vista del evento original, nada ha cambiado.

1lnvo_servicio = Create nvo_servicio_mensajes
2lnvo_solicitud = lnvo_servicio.of_crear_solicitud( &
3 as_titulo, as_mensaje, li_tipo, li_botones)
4lnvo_solicitud.ii_boton_predeterminado = ai_predeterminado
5li_resultado = lnvo_servicio.of_mostrar_mensaje(lnvo_solicitud)
6Destroy lnvo_solicitud
7Destroy lnvo_servicio
8Return li_resultado

Paso 3: separar la solicitud, el servicio y la ventana

nvo_solicitud_mensaje transporta título, mensaje, tipo, botones, detalles técnicos, copia, cuenta regresiva e indicador de historial. nvo_servicio_mensajes abre la ventana modal mediante OpenWithParm; la ventana recupera el objeto desde Message.PowerObjectParm.

1If Not IsValid(anvo_solicitud) Then Return 0
2of_inicializar()
3OpenWithParm(w_mensaje_moderno, anvo_solicitud)
4ls_resultado = Message.StringParm
5li_resultado = of_normalizar_resultado(ls_resultado)
6If anvo_solicitud.ib_registrar_historial Then &
7 inv_historial.of_registrar(anvo_solicitud, li_resultado)
8Return li_resultado

La ventana moderna configura texto, icono, tema y botones a partir de la solicitud. Cuando el usuario responde, utiliza CloseWithReturn. El servicio normaliza el texto devuelto y entrega el mismo código entero que espera el código heredado.

1Timer(0)
2ls_retorno = String(ai_resultado) + "|" + as_texto
3CloseWithReturn(this, ls_retorno)
4Return ai_resultado

Paso 4: adoptar el tema activo de PowerBuilder

nvo_gestor_temas consulta GetTheme() y calcula una paleta clara u oscura. La ventana aplica fondo, texto, acento e iconografía cada vez que se abre. El mensaje parece una parte natural de la aplicación porque responde al tema que ya está activo, no a una apariencia fija.

La misma capa global bajo Flat Design Dark: contraste, botones, icono y foco se adaptan sin cambiar la llamada que originó el mensaje.

Apariencia

Paleta clara u oscura, color del tema, tipografía Segoe UI e iconos SVG por categoría.

Comportamiento

Botón predeterminado, Enter, Escape, retorno modal y sonido estándar de Windows.

Servicios

Historial en memoria, detalles técnicos, copia al portapapeles y cuenta regresiva opcional.

El escenario RetryCancel conserva los códigos tradicionales: Reintentar devuelve 4 y Cancelar devuelve 2.

Paso 5: integrar el overlay en una aplicación existente

• Importe messagebox.srf y los objetos de soporte: nvo_solicitud_mensaje, nvo_respuesta_mensaje, nvo_servicio_mensajes, nvo_gestor_temas, nvo_gestor_historial, u_icono_mensaje y w_mensaje_moderno.

• Guárdelos en una PBL del target o en una nueva PBL incluida en el LibList. La función global debe estar disponible para la resolución de todas las llamadas.

• Conserve recursos/svg y theme directamente bajo la raíz del demo. Las rutas absolutas se construyen en ejecución con GetCurrentDirectory(); no existen rutas fijas del equipo ni búsquedas en carpetas superiores.

• Ejecute un Full Build. Este paso recompila los objetos consumidores y vuelve a enlazar las llamadas existentes con la función global del overlay.

• Pruebe cada combinación utilizada por la aplicación: OK!, OKCancel!, YesNo!, YesNoCancel!, RetryCancel! y AbortRetryIgnore!, incluidos los botones predeterminados.

• Valide los flujos que comparan el resultado numérico. La compatibilidad visual no basta: las decisiones posteriores deben recibir 1, 2, 3, 4, 5, 6 o 7 según corresponda.

Antes y después, sin tocar el evento

Antes del overlay

PowerBuilder atiende MessageBox(...) con el diálogo estándar. El evento recibe un entero y continúa su lógica.

Después del overlay

La función global compatible crea la solicitud, abre la ventana Response moderna y devuelve el mismo tipo de resultado. El evento continúa exactamente igual.

1li_respuesta = MessageBox("Confirmación", &
2 "¿Desea aplicar la configuración seleccionada?", &
3 Question!, YesNo!)
4
5If li_respuesta = 6 Then
6 // Continúa el proceso existente.
7End If

Alcance real y límites

• El overlay cubre las firmas declaradas en messagebox.srf. Conviene inventariar variantes no contempladas antes del Full Build.

• Intercepta llamadas PowerScript que se resuelven durante la compilación del target.

• No reemplaza diálogos producidos internamente por el Runtime, Windows, DLL, ActiveX, COM, controladores de base de datos o componentes externos.

• Los recursos SVG deben formar parte del despliegue; el sonido usa MessageBeep de Windows y no necesita archivos de audio.

• La prueba debe incluir temas claros, oscuros y High DPI, además de teclado, cierre con la X y códigos de retorno.

Conclusión

La modernización más segura no siempre es la que reescribe más código. En este framework, una función global compatible actúa como overlay, conserva el contrato de MessageBox y desvía la presentación hacia una ventana Response moderna. El resultado es una actualización transversal: temas automáticos, iconos SVG, retornos compatibles, historial, detalles y sonido, mientras las ventanas y eventos existentes permanecen intactos.

La clave es combinar tres ideas sencillas: mismas firmas públicas, un servicio central y un Full Build que reenlace toda la aplicación. Así, un sistema ya terminado puede adoptar una experiencia visual moderna sin convertir la migración en una búsqueda manual de cientos de llamadas.