Messagebox con etiquetas personalizadas

El problema:

Con la llegada de Windows Vista, los clásicos mensajes de dialogo en Windows serían -según muchos- cosa del pasado. Estoy hablando de la llegada de los nuevos TaskDialogs. Siendo muy potentes tienen unos inconvenientes que nos impide acogerlos al cien por ciento. Primero: como desarrollares responsables, no podemos -por el momento- desarrollar exclusivamente para Windows Vista y versiones posteriores. Además, desde Delphi y su implementación de los TaskDialogs mediante la clase TTaskDialog no puedes mostrar este tipo de mensajes cuando los temas del sistema están deshabilitados. Por último, al ser muy potentes tienen cierta complejidad que para tareas sencillas sería más cómodo hacer una simple llamada a la función Messagebox.

Sin embargo, los viejos MessageBox de Windows tienen un problema de usabilidad: El usuario tiene que leer todo el mesaje para poder tomar una decisión. La solución a este problema está en usar etiquetas descriptivas en los botones y dejar a un lado los viejos «SÍ/NO/CANCELAR/etc.». Obviamente surge la pregunta: » ¿Cómo puedo cambiar las etiquetas de este tipo de dialogo desde Delphi? Es muy sencillo y pasa por utilizar Hooks proporcionados por la misma API de Windows.

La solución:

Lo primero es obtener copia de la unidad que he escrito [ACTUALIZACIÓN: La unidad ahora está en Dropbox] que es una capa para trabajar con la API de Windows. Ésta gestiona el código necesario para instalar el Hook y quitarlo cuando ya no sea necesario. La unidad proporciona una sola función CBTMessagebox, muy similar a la clásica MessageBox de la API de Windows. El único parámetro que introduce la función CBTMessagebox está en último lugar y de tipo TCBTCustomBtnLabels, este último tipo también está incluido en la unidad. TCBTCustomBtnLabels es un Record que específica la etiqueta personalizada que tendrá algunos o todos los botones del mensaje de dialogo que se mostrará.

Veamos un ejemplo: Supongamos que el usuario ha hecho algunos cambios en un documento y luego intenta cerrar la ventana de trabajo. Entonces queremos mostrar un típico mensaje de confirmación con los botones «Guardar/No Guardar/Cancelar» en el evento OnCloseQuery del formulario. El código sería el siguiente:

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
    MyCustomLabels: TCBTCustomBtnLabels;
begin
    MyCustomLabels.YES := 'Guardar';
    MyCustomLabels.NO := 'No guardar';
    // la etiqueta predeterminada de IDCANCEL es adecuada en este caso,
    // así que no definimos una etiqueta personalizada para este botón.

    // ( no definimos una etiqueta personalizada si queremos
    //   dejar el botón con su etiqueta predeterminada )
    case CBTMessagebox(Self.Handle,
                       '¿Guardar cambios antes de salir?',
                       '¿Guardar?',
                       (MB_YESNOCANCEL or MB_ICONINFORMATION or MB_DEFBUTTON1),
                       MyCustomLabels) of
        IDYES: GuardarModificaciones;
        IDNO: DeshacerModificaciones;
        IDCANCEL: CanClose := False;
    end;
end;

El código anterior mostrará un mensaje de dialogo como el siguiente antes de cerrar la ventana de trabajo.

Segundo ejemplo: El usuario ha elegido eliminar un registro de la base de datos. Procedemos a confirmar esta operación con un mensaje de dialogo más descriptivo y usable:

procedure TForm1.DatasetBeforeDelete(Dataset: TDataset);
var
    MyCustomLabels: TCBTCustomBtnLabels;
begin
    MyCustomLabels.YES := 'Eliminar';
    MyCustomLabels.NO := 'No eliminar';
    case CBTMessagebox(Self.Handle,
                       '¿Realmente desea eliminar este registro?',
                       '¿Eliminar?',
                       (MB_YESNO or MB_ICONINFORMATION or MB_DEFBUTTON2),
                       MyCustomLabels) of
        IDYES: inherited {no hacer nada. Dejar que el dataset elimine el registro};
        IDNO: Abort;
    end;
end;

Espero que el este consejo sea puesto en practica por ustedes desarrollares Delphi. Estaré muy atento a contestar alguna interrogante que tengan con respecto a lo que se ha discutido aquí.

ADVERTENCIA: Evita especificar una etiqueta muy larga para un botón porque la unidad no puede cambiar el tamaño del botón para acomodarla.

Etiquetado , , ,

10 pensamientos en “Messagebox con etiquetas personalizadas

  1. Aristo Diaz dice:

    Buenas.

    La unidad de descarga no sirve, o no se si es que lo estoy haciendo mal, la estoy agregando como una unidad en USES en un proyecto de prueba.

    Tiene otro enlace donde se puedea descargar. (bio_custom_msgbox).

    Gracias de antemano.

  2. Hola Aristo! ¿Qué tipo de problema te está dando la unidad? Solo por mencionar, aparte de agregarla al proyecto, también la tienes que agregar en la sección USES de la unidad dónde vallas a hacer uso de ella.

  3. He actualizado la entrada, ahora pueden descargar una copia de la unidad desde mi cuenta de Dropbox para que sea más fácil acceder a ella.

    Saludos!

  4. Gracias por el aporte Christopher Ramírez :) ahora a darle código

  5. raizen994 dice:

    Como implemento esto para equipos móviles?

  6. Oscar Julian dice:

    Gracias por compartir la unidad.

  7. Five Threads dice:

    Hola, el enlace de descarga de «https://dl.dropbox.com/u/11734896/bio_custom_msgbox.pas» no funciona, me ayudas por favor?

Deja un comentario