21 de octubre de 2016

Desglosar cadenas separadas por comas en matrices de Visual FoxPro

Artículo original: Parsing comma-delimited strings into a Visual Foxpro array
http://www.ml-consult.co.uk/foxst-15.htm  
Autor: Mike Lewis
Traducido por: Ana María Bisbé York


Un modo sencillo de desglosar datos en una cadena separada por comas.

En Visual FoxPro (y otros lenguajes de programación) las cadenas delimitadas por comas son una vía sencilla para guardar pequeñas colecciones de datos. Es habitual el uso de estas cadenas para pasar parámetros a procedimientos o funciones, o para guardar valores en propiedades de usuarios o clases. Puede además, importar datos de algunas aplicaciones en forma de un archivo de texto delimitado por comas.

He aquí una vía sencilla para desglosar una cadena separada por comas en VFP 6.0. Utilizando esta sencilla línea de código, puede extraer rápidamente cada elemento separado por la coma y colocarlo en un elemento independiente de la matriz.

nRows = ALINES(laData, STRTRAN(cTest,",",CHR(13)))

En este caso, la cadena delimitada por comas se llama cTest y la matriz se llama laData. Si no existe la matriz, la crea. Luego de ejecutar el código, la variable nRows contendrá la cantidad de elementos en la matriz.

El código realiza dos sencillas operaciones. Primero, la función STRTRAN() convierte cada una de las comas en un carácter de fin de cadena (ASCII 13). La función ALINES() coloca cada "línea" que se ha formado en un elemento de la matriz. ALINES(), que se introdujo en VFP 6.0, está diseñada para extraer párrafos de cadenas de texto muy largas; pero funciona también en el contexto mostrado aquí.

En VFP 7.0 y superior, el código es incluso más sencillo. VFP 7.0 introdujo un parámetro adicional a ALINES(), el que le permite especificar un carácter fin de línea personalizado. Entonces, en lugar de tener que utilizar STRTRAN() para convertir las comas en ASCII 13, puede sencillamente estipular que la coma marca el fin de línea. El código entonces, es el siguiente:

nRows = ALINES(laData, cTest, .F., ",")

El tercer parámetro de ALINES() es un indicador que dice si la "línea" debe ser recortada cuando es copiada en la matriz.

Si desea convertir un archivo de texto entero en una matriz simplemente conviértalo en una cadena de caracteres antes con el código que se muestra a continuación. En VFP 6.0 y superior, la forma más fácil de convertir un archivo en una cadena es con la función FILETOSTR(). Entonces, teniendo un archivo de texto delimitado por comas llamado CLIENTS.TXT, he aquí cómo lo puede desglosar en una matriz llamada aClients:

cClients = FILETOSTR("clients.txt")
nRows = ALINES(aClients,STRTRAN(cClients,",",CHR(13)))

Vea que esta técnica no trabaja si las variables como tal contienen comas. Cuando se almacenan, por ejemplo, nombres y direcciones como variables separadas por comas, por ejemplo, lo habitual es encerrarlas entre comillas, para indicar que al desglosar trate todo este texto entre comillas como un único elemento. Desafortunadamente el código mostrado en este artículo no puede controlar esta situación.

Mike Lewis Consultants Ltd. Julio 2000. Revisado Noviembre 2001.

17 de octubre de 2016

Pedir un nombre de carpeta o archivo a los usuarios

Artículo original: Prompt your users for a file or directory name
http://www.ml-consult.co.uk/foxst-24.htm
Autor:Mike Lewis
Traducido por: Ana María Bisbé York


Esta sencilla clase facilita aún más esta tarea.

Las aplicaciones Visual Foxpro a veces necesitan preguntar al usuario un nombre de archivo o directorio. Habitualmente lo mejor es hacer una combinación de cuadros de texto y botones de comandos. Si el usuario ya conoce el nombre requerido, puede escribirlo en el cuadro de texto. Si no lo conoce. Puede hacer clic en el botón para invocar el diálogo Seleccionar Directorio o Abrir archivo, desde el que puede navegar a la carpeta o archivo en cuestión.

No es difícil crear este tipo de mecanismos. Pero es incluso más fácil si utiliza la clase cmpSelDir de Bárbara Peisch, la que realiza todo el trabajo por usted.

La clase cmpSelDir es una clase compuesta, que contiene un cuadro de texto y un botón de comandos como he descrito antes. Para utilizarla, arrástrela a un formulario. De forma predeterminada, el botón abrirá el diálogo Seleccionar Carpeta. Para abrir en su lugar el diálogo Abrir fichero, cambie la propiedad WhichGet a la palabra File (Vea que es sensible a mayúsculas y minúsculas). Con ambos tipos de diálogo, el nombre de archivo o el directorio que el usuario selecciona será agregado en el cuadro de texto, sobre-escribiendo cualquier texto que estuviese escrito antes. Si el usuario cancela el diálogo, se preserva lo que existía en el cuadro de texto.

La clase ofrece varias propiedades que permiten personalizar el diálogo de formas diferentes. Por ejemplo: se puede asignar a PromptText un texto con una pregunta que puede aparecer en el diálogo, en OpenButtonCaption el texto que va a aparecer en el botón OK en el diálogo Abrir fichero. Aún más interesante, la propiedad FileExtensions puede ser utilizada para llenar el control Tipos de archivos en el diálogo Abrir Archivo. Puede establecer esta lista de extensiones de archivos, con caracteres comodines opcionales, acompañados opcionalmente por descripciones cortas (Ejemplo: "Tablas:DBF; Archivos de texto :TXT, CSV").

Todas estas propiedades tienen parámetros de configuración, por tanto puede ignorar aquellos en los que no está interesado. Para mayor información vea el método ZReadMe.

Y esto es todo lo que hay sobre esta clase. La clase cmpSelDir es una clase elegante, fácil de utilizar, y un ejemplo excelente de una herramienta que realiza un trabajo y lo hace bien.

Sobre la desarrolladora

Barbara Peisch dirige Peisch Custom Software Inc., una consultoría VFP en Carlsbad, CA (USA). Fue editor técnico del libro: "WebRAD: Building Database Websites with Visual FoxPro and Web Connection", y es co-autora de la columna de la revista CoDe "Customers vs Code: Keeping Your Cool with the Essential Component". Barbara es la autora original de la columna KitBox de la revista FoxTalk, y es Microsoft MVP, así como miembro activo del Microsoft Application Developers Forum en Compuserve. Se le puede contactar en barbara@peisch.com o visitando www.peisch.com.

Cómo descargar cmpSelDir

Haga clic en el enlace más abajo para descargar CMPSELDIRFILE.ZIP. Este archivo ZIP contiene una biblioteca de clases, que a su vez contiene la clase cmpSelDir. Contiene además, otra clase llamada cmdFileFind, que es la clase padre de los botones de comandos empleados en la clase compuesta. El tamaño de la descarga es 5 KB.

Descargar ahora http://www.ml-consult.demon.co.uk/cmpseldirfile.zip

Mike Lewis Consultants Ltd. Abril 2002

14 de octubre de 2016

¿Es el Usuario un Administrador?

Rutina para determinar si el Usuario actual de Windows es Administrador.

#DEFINE NO_ERROR 0
 
DECLARE INTEGER IsUserAnAdmin IN shell32
 
DECLARE INTEGER WNetGetUser IN mpr;
    INTEGER lpName, STRING @lpUserName, INTEGER @lpnLength
 
LOCAL lcUser, lnBufsize
lnBufsize = 250
lcUser = Repli(Chr(0), lnBufsize)
 
IF WNetGetUser(0, @lcUser, @lnBufsize) = NO_ERROR
    ? "Nombre de Usuario:", SUBSTR(lcUser, 1, AT(Chr(0),lcUser)-1)
    ? "Es Administrador:", Iif(IsUserAnAdmin()=0, "No", "Si")
ENDIF

Saludos.

Jesus Caro V

10 de octubre de 2016

Tooltiptext multilinea

La propiedad Tooltiptext que ya conocemos pero mostrando varias líneas de texto.

LOCAL CRLF
CRLF = CHR(13) + CHR(10)
This.ToolTipText = "TITULO:" + CRLF + ;
     "Este es un ejemplo de la propiedad tooltiptext" + CRLF + ;
     "que ya conocemos pero con esto la habilitamos" + CRLF + ;
     "para mostrar varias lineas."

Ahora un formulario de ejemplo con tres controles CommandButton con la propiedad ToolTip "multilinea".

PUBLIC oMiForm
oMiForm = NEWOBJECT("MiForm")
oMiForm.SHOW
RETURN

DEFINE CLASS MiForm AS FORM
  AUTOCENTER = .T.
  SHOWTIPS = .T.
  CAPTION = "Ejemplo de tooltip multilinea"
  NAME = "MiForm"

  ADD OBJECT Command1 AS COMMANDBUTTON WITH ;
    TOP = 36, LEFT = 132, HEIGHT = 27, WIDTH = 84, ;
    CAPTION = "Boton 1", NAME = "Command1"

  ADD OBJECT Command2 AS COMMANDBUTTON WITH ;
    TOP = 96, LEFT = 132, HEIGHT = 27, WIDTH = 84, ;
    CAPTION = "Boton 2", NAME = "Command2"

  ADD OBJECT command3 AS COMMANDBUTTON WITH ;
    TOP = 156, LEFT = 132, HEIGHT = 27, WIDTH = 84, ;
    CAPTION = "Boton 3", NAME = "Command3"

  PROCEDURE Command1.INIT
    LOCAL CRLF
    CRLF = CHR(13) + CHR(10)
    THIS.TOOLTIPTEXT = "Ud. esta sobre el Boton 1." + CRLF + ;
      "Esto es un ejemplo de un" + CRLF + ;
      "ToolTip multilineas."
  ENDPROC

  PROCEDURE Command2.INIT
    LOCAL CRLF
    CRLF = CHR(13) + CHR(10)
    THIS.TOOLTIPTEXT = "Ahora el cursor esta sobre el Boton 2." + CRLF + ;
      "Esto es un ejemplo de un ToolTip multilineas."
  ENDPROC

  PROCEDURE Command3.INIT
    LOCAL CRLF
    CRLF = CHR(13) + CHR(10)
    THIS.TOOLTIPTEXT = "Este es el ultimo boton." + CRLF + ;
      "Esto es un ejemplo de un" + CRLF + ;
      "ToolTip multilineas."
  ENDPROC
ENDDEFINE

Saludos.

Jesus Caro V

Problema con HAVING

Artículo original: HAVING gotcha
http://www.foxpert.com/knowlbits_200712_1.htm
Autor: Christof Wollenhaupt
Traducido por: Ana María Bisbé York


Sin la cláusula GROUP BY, HAVING opera de forma similar que una cláusula WHERE, excepto en que el filtro opera en el conjunto resultante:

Create Cursor curSrc (Fld1 I, Fld2 I)
Insert into curSrc values (1, 1)
Insert into curSrc values (2, 2)

Select Fld1, fld1 + 1 as Fld3 ;
  From curSrc ;
  having Fld3 = 2

En este ejemplo, la consulta solamente devuelve aquellos registros donde la expresión "FLD+1" es 2. La capacidad de consultar campos en el conjunto resultante es limitada. Puede consultar solamente los campos que no aparecen en una de las tablas origen. Volviendo a escribir la consulta como esta obtenemos un resultado diferente. La única diferencia en la sentencia es que FLD3 ahora se llama FLD2:

Select Fld1, fld1 + 1 as Fld2 ;
  From curSrc ;
  having fld2 = 2

FLD2 se utiliza solamente en un alias en la lista de campos, todavía la cláusula HAVING opera sobre curScr.Fld2 en lugar de FLD2 del conjunto resultante. Esto puede ocasionar cambios de comportamiento del programa cuando agregue un campo a la tabla con el mismo nombre que una columna calculada.

Una vez que agrega el conjunto resultante con GROUP BY, las reglas cambian ligeramente. Refiriéndose al nombre del campo en el conjunto resultante, si existe un campo con el mismo nombre en cualquiera de las tablas origen, provoca un mensaje de error. En la siguiente consulta, FLD1 + 1 = 2 trabaja en la cláusula HAVING, FLD2=2 no podría:

Select Fld1, fld1 + 1 as Fld2 ;
  From curSrc ;
  group by 1, 2 ;
  having fld1 + 1 = 2

La misma consulta es válida si el nombre del campo no existe en cualquiera de las tablas origen. La siguiente consulta utiliza FLD3 en lugar de FLD2 como nombre del campo:

Select Fld1, fld1+1 as Fld3 ;
  From curSrc ;
  group by 1, 2 ;
  having fld3 = 2

Esta es una situación que podría encontrar cuando hace refactorización y se renombran los campos. Cambiar el nombre del campo local sorprendentemente causa error cuando se ejecuta la consulta.

3 de octubre de 2016

Convertir informe a BMP

La siguiente rutina envía el resultado de un informe a un mapa de bit por página.

Local oListener As ReportListener, nPageIndex
oListener = Createobject("ReportListener")
oListener.ListenerType = 3

cRutaReporte = Home(2)+"Solution\Reports\invoice.frx"

Report Form (cRutaReporte) Preview Object oListener

For nPageIndex=1 To oListener.PageTotal
    cOutputFile = "c:\tmp"+Trans(nPageIndex)+".bmp"
    oListener.OutputPage(nPageIndex,;
    cOutputFile, 105, 0,0,768,1024) && 105=bitmap
Next

Saludos.

Jesus Caro V