30 de junio de 2006

Proyecto VFPX

El proyecto SednaX ha sido renombrado como VFPX y movido a CodePlex.



¿Que es VFPX?

VFPX es un esfuerzo de la Comunidad Visual FoxPro para crear complementos de código abierto para Visual FoxPro 9.0.

El código, las clases, y las bibliotecas puestas a disposición aquí, complementará los esfuerzos de continuación de Microsoft para mejorar y ampliar Visual FoxPro con el llamado proyecto de Sedna que esta esbozado en http://msdn.com/vfoxpro/roadmap.

Para acceder al Proyecto VFPX haga clic aquí

29 de junio de 2006

Artículos sobre trabajo con imágenes y GDI+ en VFP 9.0

A partir de este artículo vamos a publicar una serie dedicada al trabajo con GDI+ en VFP 9.0. Esta serie es una colección de traducciones del Blog de César Ch., quien ha realizado un extraordinario trabajo al respecto y lo ha publicado para el uso y beneficio de la comunidad internacional.

¡¡ Muchísimas gracias, César !!

Artículos sobre trabajo con imágenes y GDI+ en VFP 9.0

Si trabajas con VFP 9.0, conocerás que una de las novedades más interesantes aportadas a esta versión es la posibilidad de aprovechar las ventajas que ofrece GDI+ para el tratamiento de imágenes.

Esto dicho así suena bien; pero… ¿es así de fácil? Yo diría que no. Trabajar con GDI+ tiene sus limitaciones al inicio, la curva de aprendizaje es un poco más alta y cuesta algo de trabajo hacerse del todo con la idea para poder dominar bien el tema y hacer funcionar el tratamiento de imágenes con GDI+ en nuestras aplicaciones.

La buena noticia es que, una vez más la Comunidad de desarrolladores VFP viene a nuestra ayuda. Aprovechamos todo lo que tenemos a mano y nos ponemos manos a la obra.

Por una parte, acaban de ser liberados, dos artículos excelentes sobre este tema, escritos por Craig Boyd, que fueron publicados en la revista FoxTalk 2.0.

GDI+ on VFP 9 Forms: Working with Primitives
http://www.pinpub.com/ME2/Audiences/dirmod.asp?sid=&nm=&type=Publishing&
mod=Publications%3A%3AArticle&mid=8F3A7027421841978F18BE895F87F791&
AudID=301888DF3BCF483382FC8A1382F3050B&tier=4&id=9B8367F6158545A38353B76262661672


GDI+ on VFP 9 Forms: Solving the Paint Problem
http://www.pinpub.com/ME2/Audiences/dirmod.asp?sid=&nm=&type=Publishing&
mod=Publications%3A%3AArticle&mid=8F3A7027421841978F18BE895F87F791&
AudID=301888DF3BCF483382FC8A1382F3050B&tier=4&id=43FF99C3289346189B14EAEA14573F3C


Además, contamos con el Blog de Cesar Ch., dedicado por entero al trabajo con imágenes desde GDI+. Estos artículos y ejemplos son altamente recomendados.

En los próximos días se publicarán artículos, traducciones y ejemplos dedicados al trabajo con imágenes en Visual FoxPro 9.0 empleando las ventajas y posibilidades de GDI+.

27 de junio de 2006

Modificar la conexion de nuestro DBC "on the fly"

Autor: Ricardo Fynn Reissig

Muchos programadores usan ambas técnicas de acceso a datos remotos, SQL pass through y vistas remotas. No discutiremos cual es mejor, solamente mostraremos como utilizar el mismo origen de datos y cuando este cambie, como modificar automáticamente la conexión de nuestro contenedor de base de datos de VFP (DBC).

Partimos de un ejemplo que nuestra aplicación se conecta a una base de datos remota y usa ambas tecnologías.

Lo primer que hacemos es leer algún archivo de configuración y obtenemos el string de conexión.
Este archivo puede ser un .INI o un XML o lo que prefieran.

Guardando la configuración de acceso a los datos remotos

Una opción que usamos es crear una tabla DBF free o sea, que no esta asociada a ningún contenedor de base de datos. Con una estructura de este estilo:
USER C(50)
PWD C(50)
SOURCENAME C(128)
DRIVER C(128)
SERVER C(128)
ROLEAPP C(50)
ROLEPWD C(50)
Aquí guardamos en un único registro encriptados los datos necesarios para armar el string de conexión.

Un truco muy simple es cambiarle el nombre al archivo DBF, por ejemplo renombrarlo a config.cnx (le pueden poner la exención que quieran).

Desde nuestra aplicación lo único que hacemos es USE config.cnx y desencriptamos los datos para armar el string de conexión. Este archivo lo distribuimos con nuestro ejecutable.

Esta sencilla práctica se puede aplicar al archivos de configuración de nuestras aplicaciones que queden fuera de los ojos de usuarios curiosos, ya que no tiene una aplicación por defecto asociada para abrirlos y el Notepad o Excel mostraran datos ilegibles.

En el siguiente paso leemos el archivo configuración y armamos el string de conexión.
Primero nos conectamos mediante DSN-less a nuestra base de datos remota.

Luego abrimos el contenedor de base de datos de VFP y obtenemos sus datos de conexión remota.
Comparamos ambos y si el archivo de configuración cambió, lo eliminamos y lo volvemos a crear.

lcStrCnx = leerConfiguracion() && llamamos a la función que nos arma el string de conexión
*[ creamos la conexión DSN-less
lnHandle = SQLSTRINGCONNECT(lcStrCnx)
IF lnHandle > 0 && nos conectamos sin problema
  *[ Abrimos nustra base de datos local con sus vistas remotas
  OPEN DATABASE myDataLocal
  SET DATABASE TO myDataLocal
  *[ obtengo los datos de la conexión de mi base de datos VFP
  *[ nuestra conexión se llama, por ejemplo, myCnx
  lcStrCnxDBC = ALLTRIM(DBGetProp("myCnx","CONNECTION","ConnectString"))
  *[ Si nuestro archivo de configuración cambió el acceso a los datos remotos
  *[ borra y crea el string de conexión de la BD local nuevamente
  IF UPPER(lcStrCnx) != UPPER(lcStrCnxDBC)
    DELETE CONNECTION myCnx
    CREATE CONNECTION myCnx CONNSTRING lcStrCnx
  ENDIF
ELSE
  *[ Error al conectar con server remoto
ENDIF


Cuando usar esta técnica ?


Nuestras aplicaciones en general son client-server y guardamos, como mostramos anteriormente, los datos de conexión en un archivo de configuración externo a nuestra aplicación. En algunos casos también usamos un base de datos local VFP para usarla con vistas remotas y ambas técnicas tienen en común el mismo origen de datos.

Por ejemplo, nuestra aplicación apunta a un server SQL Server que residen en un servidor con la IP 200.40.1.1 en el puerto 1433 y el administrador de red de la empresa en que está nuestra aplicación decide migrar el motor de base de datos a otros servidor, por ejemplo \\SERVERBD y cambia el puerto a otros número. Lo único que debemos hacer es cambiar el archivo de configuración.

En otra entrega mostraremos como crear una aplicación que administre este archivo de configuración y permita manejar múltiples orígenes de datos.

8 de junio de 2006

VFP y mySQL

Como conectarse a mySQL desde VFP. Acceder a tablas remotas, creando sentencias SQL simples y complejas. Pasando parámetros a mySQL y ejecutar procedimientos almacenados. Uso de vistas remotas desde VFP a mySQL.

Crear una conexión a mySQL

Este ejemplo muestra como conectarse a una base de datos mySQL y trabajar en ella mediante SQL pass through.

Primero creamos el string de conexión a la misma, aquí damos dos ejemplos, con la base de datos en nuestro disco local y con una base de datos remota y en un puerto diferente.

En este ejemplo estamos usando una práctica llamada DSN-less es decir no usamos el administrador de orígenes de ODBC para conectarnos.

Es una práctica bastante usada y nos independizamos si el usuario creo la conexión ODBC en su puesto de trabajo o no.

Para crear una conexión a mySQL deberá tener instalado el driver ODBC correspondiente, este se puede descargar del siguiente link: http://www.mysql.com/products/connector/odbc

lcStringCnxRemoto = "DRIVER={MySQL ODBC 3.51 Driver};" + ;
                    "SERVER=200.1.1.1;" + ;
                    "PORT=3333;" + ;
                    "UID=booking;" + ;
                    "PWD=booking;" + ;
                    "DATABASE=booking;" + ;
                    "OPTIONS=131329;"

lcStringCnxLocal = "DRIVER={MySQL ODBC 3.51 Driver};" + ;
                   "SERVER=localhost;" + ;
                   "UID=root;" + ;
                   "PWD=clave;" + ;
                   "DATABASE=booking;" + ;
                   "OPTIONS=131329;"
SQLSETPROP(0,"DispLogin" , 3 )
lnHandle = SQLSTRINGCONNECT(lcStringCnxLocal)

Interpretando el string de conexión
  • DRIVER indica que estamos usando el driver mySQL instalado. En este ejemplo la versión 3.51
  • SERVER indica donde está la base de datos mySQL, presentamos dos ejemplos para trabajar localmente y remoto. En el caso que sea remotopodemos especificar un número IP o el nombre de un servidor.
  • PORT especifica donde está instalado el mySQL, muchas veces los administradores de red cambian este puerto (que por defecto es el 3306 por otro).
  • UID es el nombre de login con el cual accederemos.
  • PWD es nuestra clave.
  • DATABASE es el nombre del schema de mySQL en que trabajaremos. en este ejemplo el schema booking.
  • OPTIONS esta opción especifica como mySQL debería trabajar. Si no se usa nos podemos conectar sin problemas. Se utiliza en caso particulares.
En el siguiente link encontraras más información: http://dev.mysql.com/doc/refman/5.0/en/connection-parameters.html

Accediendo a los datos

Vamos a probar nuestro string de conexión.

SQLSETPROP(0,"DispLogin" , 3 )
lnHandle = SQLSTRINGCONNECT(lcStringCnxLocal)
IF lnHandle > 0
 cmd = SQLEXEC(lnHandle,"select QuantityRooms from roomtype","cur_roomtype")
 IF cmd > 0
  BROWSE
 ELSE
  AERROR(laErr)
  MESSAGEBOX("No se pudo conectar a mySQL. Error: " + CHR(13) + laErr[2])
 ENDIF
 USE IN cur_roomtype
 SQLDISCONNECT(lnHandle)
ELSE
 AERROR(laErr)
  MESSAGEBOX("No se pudo conectar a mySQL. Error: " + CHR(13) + laErr[2])
ENDIF
Si nuestra conexión fue satisfactoria, la variable lnHandle fue mayor que cero, comenzamos a hacer operaciones SQL contra la base de datos.

En este ejemplo simplemente hacemos un select que nos devuelve la columna QuantityRooms de la tabla RoomType. El resultado lo guardamos enun cursor llamado cur_roomtype.

Creando sentencias SQL más complejas

El comando SQLEXEC() tiene como segundo parámetro la sentencia SQL. Esta, si es muy compleja la podemos guardar en una variabley si esta es mayor de 255 caracteres (límite de VFP para las variables de tipo string) podemos usar el comando TEXT  y además queda mas elegante en nuestro código
TEXT TO lcSQLcommand NOSHOW
  SELECT Inventory.inventoryid, Inventory.date, Inventory.roomtypeid,
    Inventory.sold, Roomtype.descrip, Roomtype.rooms
      FROM inventory Inventory 
        INNER JOIN roomtype Roomtype 
          ON Inventory.roomtypeid = Roomtype.roomTypeID
            ORDER BY Inventory.date DESC
ENDTEXT
cmd = SQLEXEC(lnHandle,lcSQLcommand)
Nótese que no usa la coma para separar concatenar los comandos. Dentro del bloque TEXT ... ENDTEXT podemos escribir como queramos.

Un punto muy importante es que si nuestra base de datos mySQL reside en un server Linux o Unix esta será case-sensitive, o sea, las distinguirá mayúsculas de minúsculas. No es lo mismo SELECT roomtype que SELECT RoomType. Esto generará un error dependiendo como hayamos creado nuestro schema.

Pasando parámetros a nuestra consulta

La manera mas sencilla de pasar parámetros es definiendo una variable, asignándole un valor previo a la ejecución de la consulta y asignándole un signo de interrogación delante.
nValor = 12
cmd = SQLEXEC(lnHandle,"select QuantityRooms from roomtype where roomtypeid = ?nValor","cur_roomtype")
Llamando un procedimiento almacenado
SQLEXEC(lnHandle, "call myStoreProcedure(@param1)")
Usando vistas remotas a mySQL



El primer paso es crear la conexión en nuestro contenedor de base de base datos de VFP.

Como string de conexión usamos el mismo con el que comenzamos estos ejemplos.

Verificamos que la conexión sea correcta y comenzamos a crear una vista remota.



Una vez que seleccionamos en nuestro contenedor de VFP crear una vista remota, seleccionamos la conexión creada en el paso anterior.

Automáticamente VFP nos pedirá que agreguemos tablas a al diseñador de vistas.
Un punto importante es que debe estar marcado el checkbox "All User Tables", de lo contrario el driver de mySQL nos devolverá un error como que la tabla seleccionada no existe.

Algunas consideraciones importantes

Cuando diseñemos en mySQL nuestro schema de datos, es importante crear un usuario que no sea root para acceder al mismo y darle los privilegios necesarios para trabajar sobre el schema.

root es el usuario con máximos privilegios sobre la base de datos (ídem que el usuario sa en SQL Server) y no es recomendable trabajar con él y menos si se accede en forma remota.

Si nuestro motor mySQL reside en un server Linux (o Unix) tener consideración con los nombres de las tablas y columnas, estos distinguen mayúsculas de las minúsculas.

No existe una estandarización en el lenguaje de los motores de base de datos, por lo cual si en SQL Server usaban la cláusula SELECT TOP 10 FROM miTabla ... para obtener solo 10 registros de una consulta, esta generará un error en mySQL.

mySQL usa la cláusula LIMIT 10. Es muy importante que lean la ayuda sobre cláusulas y funciones y estas no queden "hard-coded" en el código y puedan parametrizarse en el sistema, así si pasan de mySQL a ORACLE o a SQL Server, cambien la capa de datos y no deban tocar su código.

Ricardo Fynn

6 de junio de 2006

Imágenes en controles ListBox y ComboBox

Los controles ListBox y ComboBox permiten añadir imágenes a cada uno de sus elementos.

Podemos añadir imágenes a los elementos de un control ListBox o ComboBox, configurando la propiedad Picture de estos controles.

Si se configura la propiedad Picture con un valor único de propiedad, todos los elementos del control mostrarán la misma imagen (ListBox a la izquierdo de la Figura 1). Si se configura la propiedad Picture como una matriz, se puede almacenar una imagen para cada elemento de la lista, y cada elemento puede tener una imagen distinta (ListBox y ComboBox a la derecha de la Figura 1).


Figura 1.

El siguiente código muestra el formulario de la Figura 1.
PUBLIC goMiForm
goMiForm = CREATEOBJECT("MiForm")
goMiForm.SHOW(1)
RETURN

DEFINE CLASS MiForm AS FORM
  HEIGHT = 232
  WIDTH = 496
  AUTOCENTER = .T.
  SHOWWINDOW = 2
  CAPTION = "Imágenes en controles ListBox y ComboBox"
  NAME = "MiForm"
  ICON = HOME(1) + "Graphics\Icons\Misc\face02.ico"
  ADD OBJECT lstLista1 AS LISTBOX WITH ;
    HEIGHT = 208, LEFT = 12, TOP = 12, WIDTH = 150, ;
    INTEGRALHEIGHT = .T., NAME = "lstLista1"
  ADD OBJECT lstLista2 AS LISTBOX WITH ;
    HEIGHT = 208, LEFT = 170, TOP = 12, WIDTH = 150, ;
    INTEGRALHEIGHT = .T., NAME = "lstLista2"
  ADD OBJECT cmbCombo AS COMBOBOX WITH ;
    HEIGHT = 24, LEFT = 330, TOP = 12, WIDTH = 150, ;
    STYLE = 2, NAME = "cmbCombo"
  *--
  PROCEDURE INIT
    LOCAL lcDir, ln, lnItems
    lcDirBmp = HOME(1) + "Graphics\Bitmaps\Outline\Nomask\"
    WITH THISFORM
      .ADDPROPERTY("la(1)")
      lnItems = ADIR(.la,lcDirBmp + "*.bmp")
      *-- Items e imagen igual para todos los elementos
      .lstLista1.ROWSOURCETYPE = 5 && Matriz
      .lstLista1.ROWSOURCE = "ThisForm.la"
      .lstLista1.PICTURE = lcDirBmp + "Bmp.Bmp"
      FOR ln = 1 TO lnItems
        *-- Items e imágenes para cada elemento del ListBox
        .lstLista2.ADDITEM(.la(ln,1),ln)
        .lstLista2.PICTURE(ln) = lcDirBmp + .la(ln,1)
        *-- Items e imágenes para cada elemento del ComboBox
        .cmbCombo.ADDITEM(.la(ln,1),ln)
        .cmbCombo.PICTURE(ln) = lcDirBmp + .la(ln,1)
      ENDFOR
      .lstLista1.LISTINDEX = 1
      .lstLista2.LISTINDEX = 1
      .cmbCombo.LISTINDEX = 1
    ENDWITH
  ENDPROC
ENDDEFINE
Podemos ver otro caso de imagenes en un control ListBox, en los ejemplos Solutions de Visual FoxPro, ejecutando el siguiente formulario:
DO FORM (HOME(2) + "\Solution\Controls\Lists\PicList.scx")

Luis María Guayán

3 de junio de 2006

West Wind Web Connection 5.05 liberado


Web Connection
West Wind Web Connection 5.0 es una herramienta flexible para construir aplicaciones Web usando el entorno de Visual FoxPro con el cual usted ya está familiarizado.

Web Connection proporciona un Framework completamente basado en Visual FoxPro, orientado a objetos, para construir aplicaciones Web. Use Visual FoxPro para programar, depurar y correr sus aplicaciones contra peticiones Web en línea.

La versión 5.0 introduce un nuevo Web Control Framework similar a ASP.NET, que le permite usar los diseñadores visuales de Visual Studio u otra herramienta; y escribir toda la lógica de procesamiento con código FoxPro.

Mas información en http://www.west-wind.com/webconnection.