1 de abril de 2021

Un cuadro de diálogo genérico "Acerca de"

Artículo original: A Generic About Dialog
https://doughennig.com/Papers/Pub/201611adhen.pdf
Autor: Doug Hennig
Traductor: Luis María Guayán


Hace un tiempo, Doug discutió un par de diálogos dinámicos creados con la ayuda de Dynamic Form. En este artículo, presenta otro diálogo dinámico y genérico, esta vez para mostrar información de la aplicación.

La mayoría de las aplicaciones tienen una función "Acerca de" en el menú "Ayuda" que muestra información sobre la aplicación, como el nombre de la empresa, el número de versión, la carpeta actual, etc.

Como mencioné anteriormente, después de haber creado varios cuadros de diálogo "Acerca de" a lo largo de los años, decidí crear uno genérico que muestre dinámicamente la configuración que desee. Si bien este cuadro de diálogo se basa en datos como los ejemplos anteriores, no utiliza el proyecto Dynamic Form de VFPx para la representación de control. En su lugar, utiliza un control ListView ActiveX.

La Figura 1 muestra cómo se ve. Todo lo que ve en el cuadro de diálogo, excepto el enlace "Copiar configuración" y el botón "Aceptar", se personaliza pasando parámetros o agregando registros a una tabla. Este diálogo tiene las siguientes características:

  • ListView enumera tantos elementos como desee en pares de descripción/valor. El contenido de la lista proviene de una tabla llamada About.dbf la cual veremos luego.
  • Algunos de los elementos de la lista aparecen en texto azul que indica que tienen hipervínculos: al hacer clic en ellos, se realiza alguna acción. Por ejemplo, al hacer clic en el elemento "Carpeta del programa", aparece una ventana del Explorador de archivos que muestra el contenido de la carpeta del programa.
  • El botón "Copiar configuración" copia los elementos del ListView al Portapapeles de Windows para que se puedan pegar en algún otro lugar.
  • El título del formulario, la imagen, el nombre de la aplicación y el número de versión no están codificados, sino que se pasan como parámetros al formulario.
  • Cambiar el tamaño del cuadro de diálogo cambia automáticamente el tamaño del ListView y su segunda columna. Puede ajustar manualmente el tamaño de las columnas como lo haría normalmente con un control ListView.


Figura 1. Este cuadro de diálogo "Acerca de" es completamente genérico.

El método Init acepta tres parámetros: el nombre de la aplicación, el número de versión (como una cadena) y el nombre de una imagen para usar como la aplicación o el logo de la empresa. Utiliza estos parámetros para el título del formulario y las etiquetas para el nombre de la aplicación y el número de versión y para la imagen del logo. Luego llama al método LoadList para cargar la configuración. Aquí está el código del Init:

LPARAMETERS tcAppName, ;
  tcVersion, ;
  tcLogoImage
DODEFAULT()
WITH THIS
  .CAPTION = 'About ' + tcAppName
  .lblProduct.CAPTION = tcAppName
  .lblVersion.CAPTION = 'Version ' + ;
    TRANSFORM(tcVersion)
  .imgLogo.PICTURE = tcLogoImage
  .LoadList()
ENDWITH

LoadList comienza abriendo la tabla About.dbf. Esta tabla contiene los elementos que se mostrarán en el cuadro de diálogo "Acerca de". La Tabla 1 muestra la estructura de About.dbf y la Figura 2 muestra los registros en la tabla de ejemplo que acompaña a este artículo.

NombreTipoPropósito
OrderIEl orden del artículo en el diálogo
CaptionC (40)La descripción del artículo
ValueMEl valor como expresión a evaluar
HyperlinkL.T. si este elemento debe aparecer como un hipervínculo
LinkMUna expresión para evaluar la acción de hipervínculo; déjelo en blanco para usar el dato de Value

Tabla 1. La estructura de About.dbf.


Figura 2. El ejemplo de la tabla About.dbf.

LoadList revisa los registros de la tabla About.dbf para determinar el ancho de la descripción más larga y aumentar ese ancho en 10 píxeles para tener en cuenta el espacio en el ListView. Luego, establece algunas propiedades del control ListView y crea dos columnas: una para la descripción de cada elemento y otra para el valor. Dado que el valor suele ser más ancho que la descripción, la columna de descripción solo ocupa el ancho calculado anteriormente y el valor ocupa el resto del ancho del ListView. Finalmente, LoadList revisa los registros en la tabla About.dbf nuevamente, esta vez agregando cada elemento al ListView llamando al método AddSettingToList, que veremos mas adelante. Aquí está el código de LoadList:

LOCAL lnSelect, ;
  lnWidth, ;
  lnCurrWidth, ;
  luValue
lnSelect = SELECT()
SELECT 0
USE ABOUT ORDER ORDER AGAIN SHARED
lnWidth = 0
SCAN
  lnCurrWidth = TXTWIDTH(TRIM(CAPTION), ;
    THIS.FONTNAME, 8)
  lnCurrWidth = lnCurrWidth * ;
    FONTMETRIC(6, THIS.FONTNAME, 8)
  lnWidth = MAX(CEILING(lnCurrWidth), ;
    lnWidth)
ENDSCAN
lnWidth = lnWidth + 10
* Set some properties of the ListView.
WITH THIS.oList
  .VIEW = 3
  .LabelEdit = 1
  .GRIDLINES = .T.
  .OBJECT.FONT.NAME = THIS.FONTNAME
  .OBJECT.FONT.SIZE = 8
  .FullRowSelect = .T.
  * Create some columns for the ListView.
  .COLUMNHEADERS.ADD(, 'Description', ;
    'Description', lnWidth)
  .COLUMNHEADERS.ADD(, 'Value', ;
    'Value', .WIDTH - lnWidth)
ENDWITH
* Add the settings we want displayed.
SCAN
  luValue = TRANSFORM(EVALUATE(VALUE))
  THIS.AddSettingToList(TRIM(CAPTION), ;
    luValue, HYPERLINK, ;
    IIF(EMPTY(LINK), '', EVALUATE(LINK)))
ENDSCAN
USE
SELECT (lnSelect)

AddSettingToList acepta cuatro parámetros: la descripción del item, el valor del item, .T. si tiene un hipervínculo y el valor que se utilizará para el hipervínculo. Comprueba si el elemento ya está en el array aItems del formulario y, si no, agrega un nuevo elemento al ListView y al array. Establece el valor del elemento ListView y, si se supone que el elemento tiene un hipervínculo, cambia el color a azul para que parezca un hipervínculo y almacena la expresión del hipervínculo o el valor en la propiedad Tag del elemento (si la expresión está en blanco, se utiliza el campo Value). Aquí está el código de AddSettingToList:

LPARAMETERS tcDescription, ;
  tcValue, ;
  tlHyperlink, ;
  tcLink
LOCAL lnRow, ;
  loItem
WITH THIS
  IF VARTYPE(tcDescription) = 'C' AND ;
      NOT EMPTY(tcDescription) AND ;
      LEN(tcDescription) <= 100 AND ;
      NOT EMPTY(tcValue) AND ;
      LEN(tcValue) <= 255
    lnRow = ASCAN(.aItems, tcDescription, ;
      -1, -1, 1, 13)
    IF lnRow > 0
      loItem = .oList.ListItems(lnRow)
    ELSE
      loItem = .oList.ListItems.ADD(, ;
        SYS(2015), tcDescription)
      lnRow = IIF(EMPTY(.aItems[1]), ;
        1, ALEN(.aItems) + 1)
      DIMENSION .aItems[lnRow]
      .aItems[lnRow] = tcDescription
    ENDIF lnRow > 0
    loItem.SubItems(1) = tcValue
    IF tlHyperlink
      loItem.FORECOLOR = RGB(0, 0, 255)
      loItem.TAG = IIF(EMPTY(tcLink), ;
        tcValue, tcLink)
    ENDIF tlHyperlink
  ENDIF VARTYPE(tcDescription) = 'C' ...
ENDWITH
RETURN

Cuando el usuario hace clic en un elemento de la lista, se llama al método ItemClick del ListView. Este método comprueba si el elemento tiene algo en la propiedad Tag y, de ser así, utiliza la función ShellExecute de la API de Windows para abrir la aplicación predeterminada para el elemento (ExecuteFile.prg es un contenedor para ShellExecute). Entonces, si el valor del elemento es una ruta, el Explorador de archivos se abre con esa ruta. Si es una URL, el navegador predeterminado del usuario se abre con esa URL. En el caso de una dirección de correo electrónico, use algo como "'mailto:' + oApp.cSupportEmail" en el campo Link de la tabla About.dbf si oApp.cSupportEmail contiene la dirección de correo electrónico para usar.

LPARAMETERS toItem
IF NOT EMPTY(toItem.TAG)
  ExecuteFile(toItem.TAG)
ENDIF NOT EMPTY(toItem.TAG)

Cuando se cambia el tamaño del formulario, queremos que la columna Value del ListView cambie de tamaño también. El siguiente código en el evento Resize del formulario se encarga de eso:

LOCAL lnWidth
WITH THIS.oList
  lnWidth = .WIDTH - ;
    .COLUMNHEADERS.ITEM(1).WIDTH
  .COLUMNHEADERS.ITEM(2).WIDTH = ;
    MAX(lnWidth, 100)
ENDWITH

Main.prg es un programa de ejemplo que muestra cómo utilizar SFAbout. Crea un objeto de aplicación ficticio solo con fines de demostración. SFAbout no usa oApp, pero los registros de la tabla de ejemplo About.dbf sí lo hacen; por ejemplo, la expresión para el valor del elemento Nombre de Usuario es oApp.cUserName. Main.prg luego crea una instancia de SFAbout, pasándole "Mi aplicación de ejemplo" como el nombre de la aplicación, "1.0" como el número de versión y "KokoWhite.jpg" como la imagen a utilizar.

oApp = CREATEOBJECT('Empty')
ADDPROPERTY(oApp, 'cUserName', 'DHENNIG')
ADDPROPERTY(oApp, 'cWebSite', ;
  'http://www.stonefieldquery.com')
ADDPROPERTY(oApp, 'cSupportEmail', ;
  'websupport@stonefieldquery.com')
ADDPROPERTY(oApp, 'nLicenseCount', 5)
* Display the About dialog.
loForm = NEWOBJECT('SFAbout', 'SFAbout.vcx', ;
  '', 'My Sample Application', '1.0', ;
  'KokoWhite.jpg')
loForm.SHOW()

Resumen

Hay numerosos cuadros de diálogo que la mayoría de las aplicaciones tienen en común, incluido un cuadro de diálogo Opciones discutidos anteriormente y el cuadro de diálogo "Acerca de" discutido ahora. La creación de versiones genéricas y dinámicas de estos cuadros de diálogo significa que nunca tendrá que volver a crearlos.

Descarga de los ejemplos

https://doughennig.com/Papers/Pub/201611adhensc.zip


3 comentarios :

Los comentarios son moderados, por lo que pueden demorar varias horas para su publicación.