26 de enero de 2006

WAIT WINDOWS maneja implícitamente cualquier tipo de datos

WAIT WINDOWS se ha mejorado en VFP 8 para trabajar similar a MESSAGEBOX(), donde puede manejar cualquier tipo de datos e incluso objetos.
WAIT WINDOW DATE()
WAIT WINDOW _Screen
WAIT WINDOW _Screen.ForeColor

VFP Tips & Tricks - Drew Speedie

25 de enero de 2006

Mantener centrada una imagen en la pantalla principal


Ya en un artículo anterior se publicó como centrar una imagen en la pantalla principal de VFP:

-- Centrar una imagen en la pantalla principal (_Screen) --
http://comunidadvfp.blogspot.com/2002/03/centrar-una-imagen-en-la-pantalla.html

Esta vez enlazaremos el evento Resize de la pantalla principal para mantener siempre centrada la imagen, aunque la pantalla se redimensione. Para ello utilizaremos la función BINDEVENT() disponible desde VFP8.

_SCREEN.ADDOBJECT("oImagen","MiImagen")
WITH _Screen.oImagen
  .PICTURE = "C:\MiImagen.jpg"
  .LEFT = INT(_SCREEN.WIDTH  - .WIDTH)/ 2
  .TOP = INT(_SCREEN.HEIGHT - .HEIGHT)/ 2
  .VISIBLE = .T.
ENDWITH

BINDEVENT(_SCREEN,"Resize",_SCREEN.oImagen,"MiMetodo")

DEFINE CLASS MiImagen AS IMAGE
  PROCEDURE MiMetodo
    WITH THIS
      .LEFT = INT(_SCREEN.WIDTH  - .WIDTH)/ 2
      .TOP = INT(_SCREEN.HEIGHT - .HEIGHT)/ 2
    ENDWITH
  ENDPROC
  PROCEDURE DESTROY
    UNBINDEVENT(THIS)
  ENDPROC
ENDDEFINE

Luis María Guayán

Mantener centrada una imagen en un formulario

Podemos poner y mantener centrada una imagen en un formulario, aunque éste cambie de tamaño, haciendo lo siguiente:

  • Agregar un objeto Image al formulario
  • Agregar código que "centre" la imagen en el método Init de la imagen (ver el código de abajo)
  • Agregar código que mantenga "centrada" la imagen en el método Resize del formulario (ver el código de abajo)

En el siguiente ejemplo podemos ver el código y como funciona.

loMiForm = CREATEOBJECT("MiForm")
loMiForm.SHOW(1)
RETURN

DEFINE CLASS MiForm AS FORM

  HEIGHT = 400
  WIDTH = 500
  AUTOCENTER = .T.
  CAPTION = "Redimensionar el formulario..."
  NAME = "MiForm"

  ADD OBJECT text1 AS TEXTBOX WITH ;
    HEIGHT = 25, LEFT = 125, TOP = 125, WIDTH = 300, ;
    NAME = "Text1", VALUE = "Comunidad VFP en Español"

  ADD OBJECT text2 AS TEXTBOX WITH ;
    HEIGHT = 25, LEFT = 125, TOP = 200, WIDTH = 300, ;
    NAME = "Text2", VALUE = "Nada corre como un zorro"

  ADD OBJECT image1 AS IMAGE WITH ;
    PICTURE = HOME(2) + "data\graphics\pattcaro.gif", ;
    HEIGHT = 20, LEFT = 12, TOP = 12, WIDTH = 20, ;
    NAME = "Image1", STRETCH = 0

  PROCEDURE RESIZE
    THIS.Image1.LEFT = INT(THISFORM.WIDTH  - THIS.Image1.WIDTH)/ 2
    THIS.Image1.TOP = INT(THISFORM.HEIGHT - THIS.Image1.HEIGHT)/ 2
  ENDPROC

  PROCEDURE image1.INIT
    THIS.LEFT = INT(THISFORM.WIDTH  - THIS.WIDTH)/ 2
    THIS.TOP = INT(THISFORM.HEIGHT - THIS.HEIGHT)/ 2
    THIS.ZORDER(1)
  ENDPROC

ENDDEFINE

Luis María Guayán

24 de enero de 2006

USE IN en una sola línea

Puesto que el comando USE IN falla si el Alias elegido no está en uso, los desarrolladores de VFP publican con frecuencia el comando USE IN como esto:

IF USED("AlgunAlias")
 USE IN AlgunAlias
ENDIF

Sin embargo, lo antedicho se puede lograr con la siguiente equivalecia en una sola línea:

USE IN SELECT("AlgunAlias")
Esto tiene compatibilidad hacia atrás por lo menos hasta FoxPro 2.6.

[061] VFP Tips & Tricks - Drew Speedie

17 de enero de 2006

Comprobar si un variable de memoria o propiedad es un Array

Aquí está la mejor técnica que he visto para comprobar si una variable de memoria o propiedad es un Array.

IF TYPE("ALEN(AlgunaVariable)") = "N"
  * Si es un Array
 ELSE
  * NO es un Array
ENDIF

[021] VFP Tips & Tricks - Drew Speedie

9 de enero de 2006

FoxPro Tips: Examinador de Clases

Artículo original: FoxPro Tips: Class Browser
http://rickschummer.com/blog/2005/11/foxpro-tips-class-browser.html
Autor: Rick Schummer
Traducido por: Ana María Bisbé York


En la recientemente finalizada German DevCon presenté mi sesión "Get Productive with Visual FoxPro" (Lograr más productividad con Visual FoxPro). Esta sesión es siempre diferente, cada vez que la doy. Casi siempre, porque la gente que participa muchas veces aporta sus propios consejos y trucos (a lo que los animo en todas mis sesiones). Siempre comienzo la sesión con trucos sobre cómo aumentar la productividad con la Herramienta Examinador de Clases que viene con VFP (desde VFP 3). Es muy frecuente que me contacte un desarrollador después de la sesión y me haga saber cuánto agradece los consejos relacionado al Examinador de Clases.

Por eso, en caso de que no haya estado en la sesión, he aquí algunos consejos:

Establecer el archivo predeterminado cuando comienza el Examinador de clases

Primero, abra el Examinador de clases y abra la biblioteca que desea que se abra cuando arranque el Examinador de clases. Desde la ventana de comandos:
_oBrowser.SetDefaultFile()
Si desea limpiar la clase por defecto ejecute lo siguiente:
_oBrowser.ResetDefaultFile()
Funciona muy bien si está constantemente modificando clases desde la biblioteca de clases por un largo período de tiempo.

Puede abrir el Examinador de clases con múltiples bibliotecas de clases

El primer parámetro aceptado por el Examinador de clases es el nombre del archivo del VCX, o con más exactitud una lista de nombres, separados por comas
DO (_browser) WITH "examples\CPhkBase2, examples\demo"
Lista de los usados recientemente

¿Alguna vez ha hecho Clic derecho en el botón Abrir del Examinador de clases? Si no, hágalo y verá una larga lista de librerías de clases que han sido abiertas anteriormente. Eso ha estado en la herramienta durante años, pero aun le enseño este truco a los desarrolladores que me ha ahorrado horas de estar buscando por las estructuras de directorios.

El Administrador de proyectos puede abrir el Examinador de clases

Al hacer Doble clic en el Administrador de proyectos en una biblioteca visual de clases en VFP 9, se abrirá el Examinador de clases. Antes de VFP 9, no ocurría nada al hacer doble clic en una biblioteca de clases. Puede detener este comportamiento haciendo un gancho al proyecto desde el evento  QueryModifyFile. Puede además, interceptarlo en un gancho al evento QueryModifyFile  y activar su propia herramienta para bibliotecas de clases, o su herramienta favorita como HackCX Profesional (el código para hacer esto se encuentra en http://www.whitelightcomputing.com/downloadsdevelopertool.htm para los usuarios de HackCX Profesional)

El Examinador de clases puede abrir y mantener clases basadas en PRG

El Examinador de clases ha sido siempre capaz de abrir archivos VCX; pero muchos desarrolladores prefieren codificar sus clases en código de programas (PRG). Una de las desventajas de tomar la vía de los PRG era la imposibilidad de utilizar el Examinador de Clases para mantener las clases y tener una representación visual de la jerarquía de clases. Visual FoxPro 9 elimina esa limitación.

Renombrar métodos y propiedades sin abrir la clase

Puede renombrar métodos y propiedades al hacer clic derecho en las propiedades o métodos y seleccionar Rename ... del menú contextual. Aparece un diálogo que permite renombrar la propiedad o método. Recuerde, por favor que al renombrar un método o propiedad no renombra mágicamente todas las referencias en el código del método. Necesitará buscar manualmente y sustituir cualquier referencia que ha cambiado.

Copiar y mover clases entre las bibliotecas de clases

Puede abrir dos instancias del Examinador de clases y utilizar el ratón con la tecla Ctrl presionada para arrastrar el icono en la esquina superior izquierda a otra instancia del Examinador de clases. Esto va a crear una copia de la clase en la otra biblioteca de clases. Esto va a mantener la misma relación con su clase padre. Si no se mantiene oprimida la tecla Ctrl, lo que ocurre es que se mueve la clase de una biblioteca a otra.

No es común que se sorprendan los desarrolladores cuando les muestro que podemos tener varias instancias del Examinador de clases. Para mí es una de las características que más poder le ofrecen a esta herramienta tan importante.

He publicado esto ayer en FoxForum.com  y una amiga me envió un correo hoy haciéndome ver que estaba muy interesante, por eso lo coloqué en mi blog (ofreciendo la publicación entera). ¿Cómo podría yo pagar enviando un sólo truco cuando tengo otros muchos? Por eso, Gracias Mary, es tu culpa que todo este conocimiento llegue más allá en la Comunidad Fox.

¡ Que lo disfruten !

6 de enero de 2006

Guardar la posición y el tamaño de un formulario

Muchas veces nuestros usuarios desean que al volver a ingresar a un formulario, éste mantenga el tamaño y la posición de la última vez que se ejecutó. Aquí mostraremos una forma simple de realizar esta tarea con un ejemplo al cual Uds. podrán darle la funcionalidad y la complejidad que sus aplicaciones requieran.

¿Qué utilizaremos?

A partir de Visual FoxPro 8.0 se agregó la cláusula NAME a los comandos SCATTER y GATHER, que nos permite actualizar las propiedades de un objeto con el registro actual de una tabla, y a la inversa, reemplazar el registro actual de una tabla a partir de las propiedades de un objeto.

Por ejemplo si tenemos una tabla con los nombres de campos que coincidan con los nombres de las propiedades de un objeto, el siguiente código actualizará las propiedades del objeto con los valores del registro actual de la tabla:
USE MiTablaSCATTER NAME Objeto ADDITIVE

¿Qué haremos?

Lo que vamos a hacer, es crear una tabla libre con nombre "_Prop_" mas el nombre físico del archivo del formulario utilizando la función SYS(1271). En el caso de crear el formulario programáticamente (como en el ejemplo) la función SYS(1271) retorna .F., con lo cual agregaremos "Form" al nombre de la tabla. Los campos de la tabla solo serán las propiedades que nos dan la posición y el tamaño del formulario (Top, Left, Width y Height)  y el color de fondo (BackColor).

Importante: Tener en cuenta que las tablas libres solo soportan nombres de campos de hasta 10 caracteres de longitud. En el caso de este ejemplo, las propiedades a guardar son Top, Left, Width, Height y BackColor con lo cual no tendremos inconvenientes ya que ninguna supera los 10 caracteres de largo, pero si deseamos poder guardar y recuperar propiedades de mas de 10 caracteres de longitud, debemos reemplazar la tabla libre por una tabla contenida en una base de datos que soportan nombres de campos de hasta 128 caracteres de longitud.

En el método Init del formulario tomamos los valores de las propiedades con en comando SCATTER NAME ThisForm ADDITIVE y en el método Destroy guardamos los valores con el comando GATHER NAME ThisForm.

El código de ejemplo

Copie el código siguiente en un archivo PRG, ejecútelo, y cambie el tamaño, posición y color de fondo del formulario. Luego salga y ejecútelo nuevamente y verá que conserva las propiedades que ha cambiado.
PUBLIC oMiForm
oMiForm = CREATEOBJECT("MiForm")
oMiForm.SHOW(1)
RETURN

DEFINE CLASS MiForm AS FORM
  TOP = 10
  LEFT = 10
  HEIGHT = 180
  WIDTH = 324
  CAPTION = "Guardar posición, tamaño y color de fondo"
  BACKCOLOR = RGB(200,220,255)
  NAME = "frmMiForm"

  ADD OBJECT cmdColor AS COMMANDBUTTON WITH ;
    TOP = 12, LEFT = 12, HEIGHT = 27, WIDTH = 132, ;
    CAPTION = "Cambiar BackColor", NAME = "cmdColor"

  ADD OBJECT cmdSalir AS COMMANDBUTTON WITH ;
    TOP = 48, LEFT = 12, HEIGHT = 27, WIDTH = 132, ;
    CAPTION = "Salir", NAME = "cmdSalir"

  ADD OBJECT lblAyuda AS LABEL WITH ;
    AUTOSIZE = .T., WORDWRAP = .T., BACKSTYLE = 0, ;
    CAPTION = "Cambie la posición, tamaño y color del " + ;
    "formulario. Salga del formulario y ejecutelo nuevamente.", ;
    FONTSIZE = 12, LEFT = 12, TOP = 96, NAME = "lblAyuda"

  PROCEDURE INIT
    THISFORM.InicializarPropiedades()
    THISFORM.TomarPropiedades()
    THISFORM.RESIZE
  ENDPROC

  PROCEDURE DESTROY
    THISFORM.GuardarPropiedades()
  ENDPROC

  PROCEDURE RESIZE
    THISFORM.lblAyuda.WIDTH = THISFORM.WIDTH - 24
  ENDPROC

  PROCEDURE InicializarPropiedades
    LOCAL lcScx
    *-- Creo propiedades
    THISFORM.ADDPROPERTY("Prop_Alias")
    THISFORM.ADDPROPERTY("Prop_Tabla")
    *-- Nombre de la tabla de propiedades
    lcScx = SYS(1271,THISFORM)
    THISFORM.Prop_Alias = "_Prop_" + IIF(EMPTY(lcScx),"Form",JUSTSTEM(lcScx))
    THISFORM.Prop_Tabla = FORCEEXT(FULLPATH("")+ THISFORM.Prop_Alias, "DBF")
    *-- Si no existe la tabla la creo
    IF NOT FILE(THISFORM.Prop_Tabla)
      CREATE TABLE (THISFORM.Prop_Tabla) FREE ;
        (TOP I, LEFT I, WIDTH I, HEIGHT I, BACKCOLOR I)
      APPEND BLANK
      GATHER NAME THISFORM
      USE IN SELECT(THISFORM.Prop_Alias)
    ENDIF
  ENDPROC

  PROCEDURE TomarPropiedades
    *-- Tomo las propiedades de la tabla
    SELECT 0
    USE (THISFORM.Prop_Tabla)
    SCATTER NAME THISFORM ADDITIVE
    USE IN SELECT(THISFORM.Prop_Alias)
  ENDPROC

  PROCEDURE GuardarPropiedades
    *-- Guardo las propiedades en la tabla
    SELECT 0
    USE (THISFORM.Prop_Tabla)
    GATHER NAME THISFORM
    USE IN SELECT(THISFORM.Prop_Alias)
  ENDPROC

  PROCEDURE cmdColor.CLICK
    THISFORM.BACKCOLOR = GETCOLOR(THISFORM.BACKCOLOR)
  ENDPROC

  PROCEDURE cmdSalir.CLICK
    THISFORM.RELEASE
  ENDPROC

ENDDEFINE
Para terminar

La idea de este código para publicar en PortalFox fue tomada de uno de los ejemplos de la aplicación "Solution" que viene con Visual FoxPro. Este formulario de ejemplo (que viene a partir de VFP 8.0) lo podemos ver ejecutando:

DO FORM (HOME(2) + "Solution\Toledo\ScatterName")

Hasta la próxima.

Luis María

2 de enero de 2006

Inserción Masiva de Registros de VFP a MySQL

Aquí una pequeña rutina al vapor para insertar un cursor a una tabla de MySQL de forma ágil y rápida.
CREATE CURSOR csrTEMPORAL(campo1 C(100), campo2 C(100), cAMPO3 C(100), CAMPO7 C(100))
FOR I = 1 TO 150
  INSERT INTO csrTEMPORAL VALUES(CDOW(DATE()+i),CDOW(DATE()+i+1),CDOW(DATE()+2),CDOW(DATE()+3))
ENDFOR
cDataSource = "Test"
cUserName = "root"
cPassword  = "root"
ConnectionString = [DRIVER={MySQL ODBC 3.51 Driver};SERVER=localhost;DATABASE=] + ;
  cDataSource + [;USER=] + cUserName + [;PASSWORD=] + cPassword + [;OPTION=3;]
nConexion  = SQLSTRINGCONNECT( ConnectionString )
SELECT csrTEMPORAL
lcComando = ""
SCAN
  lcComando = lcComando + [("] + ALLTRIM(csrTEMPORAL.CAMPO1) + [","] + ;
    ALLTRIM(csrTEMPORAL.CAMPO2) + [","] + ALLTRIM(csrTEMPORAL.CAMPO3) + ;
    [","] + ALLTRIM(csrTEMPORAL.CAMPO7) + ["),]
ENDSCAN
lcComando = [INSERT INTO TEMPORAL (CAMPO1, CAMPO2, CAMPO3, CAMPO7) VALUES ] + ;
  SUBSTR(lcComando,1,LEN(lcComando)-1)
? lcComando
lnSegundos = SECONDS()
x = SQLEXEC(nConexion ,lcComando)
MESSAGEBOX(SECONDS()-lnSegundos)
x = SQLEXEC(nConexion, "SELECT * FROM TEMPORAL", "csrTemporalSQL")
x = SQLDISCONNECT(0)
Lic. J. Enrique Ramos Menchaca
Guadalajara, Jalisco, México