28 de marzo de 2006

Build Your Own Framework with Visual Foxpro

Libro que parte desde cero para diseñar un Framework, incluso el Framework que viene con el codigo fuente es usable en forma directa.

De nivel medio-avanzado.



Se lo puede ver y comprar en: http://www.hentzenwerke.com/catalog/buildfox.htm

Está editado para trabajar con Visual Foxpro 8.0 en adelante. Los capítulos se refieren al código del framework que viene con el libro, no "enseña" el lenguaje, por ello lo del nivel.

Title: Build Your Own Framework with Visual Foxpro
Autor: Kenneth Chazotte
ISBN: 1-930919-53-0
Length: 330 pages
Formats Available: Printed (incl. ebook) or Ebook only
Printed book format: Paperback, 7"x9"
Ebook format: PDF (2.0 MB)
Price ($US): 49.95
Weight: 1.5 lbs.
Press date: March, 2004
Printed book availability: Being reprinted (avail 1/2006)
Ebook availability: Complete & Ready for Download
Source code: Complete & Ready for Download (1.0 MB)

Capítulos:

 1: Introduction
 2: Project Planning
 3: Framework Architecture
 4: Techniques for Flexibility
 5: Beginning Developmente
 6: Creating a Class Library
 7: Environmentes and Sessions
 8: Collectiones
 9: Cursor and CursorAdapter
10: Business Objects
11: Fremework Services
12: Forms
13: Data Entry Forms
14: Toolbars
15: Error Handling
16: Security
17: Developer Tools
18: Starting New Projects
19: Sample Application

21 de marzo de 2006

Acceder a una DBF desde SQL Server 7/2000 con T-SQL

Necesitas ser Administrador y que esté instalado el Proveedor OLEDB de Visual FoxPro.

Por ejemplo para leer una tabla llamada Clientes en un directorio del servidor llamado D:\Dbf\

SELECT * FROM OpenDataSource('VFPOLEDB', 'Data Source=D:\Dbf\;Mode=Read;User ID=;Password=;DSN=')...Clientes
GO

Rafael Cano

20 de marzo de 2006

Nuevos videos educativos de Craig Boyd

Un nuevo aporte a la comunidad VFP llega de la mano del MS MVP VFP Craig Boyd. Craig ha encontrado tiempo para continuar la serie de videos educativos para aprender a programar bien con Visual FoxPro.

La información y los enlaces para la descarga de los videos nuevos, está en:

http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,ada057d3-53e8-4436-8617-aa4ce16507b0.aspx.

En este caso, se va a referir al tema "Alcance en Visual FoxPro", visto para variables, matrices, parámetros, constantes, procedimientos y miembros de objetos. Se ven algunos comandos que están limitados a una determinada sesión de datos. Es de la serie de principiantes, aunque trata de profundizar bastante en el tema, así que será muy útil para los de nivel intermedio también.
Los datos para esta segunda entrega son:

Para ver en modo conectado:
Para ver en modo desconectado:
Craig Boyd comenta que si hay problemas para entender alguno de los conceptos presentados en el video, asegúrese de verlo en el código fuente que acompaña los videos. Debido a que las copias de pantallas son muy buenas para impartir información, lo mejor es intentarlo por si mismo. Los archivos procedurales facilitarán la tarea de explorar los diferentes aspectos.

Para aquellos que nunca han utilizado el marco Visual FoxPro para el Depurador de la forma que Craig lo hace en estos videos, sepa que está disponible como un parámetro del depurador. Vaya a la ventana Herramientas - Opciones - ficha Debug (Depurador), combobox Entorno, seleccione el valor Marco de FoxPro.

Así mismo, informa sobre los temas que está considerando para videos futuros, los que son, sin un orden particular:
  • Control de errores (On Error y Try ... Catch ... Finally)
  • Modal contra Modeless
  • Informes
  • Creación de bases de datos
  • SQL / Vistas (Remota, local, Createoffline()/Use Online, etc.)
  • Transacciones (incluyendo MAKETRANSACTABLE) / XML / HTML
  • Servicios Web
  • Depuración
  • Analizador de trayecto (Coverage Profiler)
  • CONFIG.FPW
  • Análisis de cadenas
  • Índices (incluyendo reindexados efectivos)
  • Comandos SET
  • Ganchos de proyecto (Project Hooks)
  • Empleo de Windows APIs
  • Intellisense
  • Controles (grid, listbox, combobox, etc.)
  • Foundation classes (xmladapter, cursoradapter, reportlistener, etc.)
  • Arrastrar y soltar (Drag and Drop)
  • Funciones BITwise (bitset, bitclear, bitand, etc.)
  • Bindevent
  • Directivas del compilador
Nos anima a comentarle sobre el orden en que preferimos los temas y/o la inclusión de algún tema que no aparezca en su lista. De esa forma Craig garantizaría brindar primero los temas más necesarios a la comunidad Visual FoxPro.

Muchas gracias a Craig Boyd por esta nueva entrega. ¡¡ Excelente trabajo !!

Saludos,

Ana María Bisbé York
www.amby.net

17 de marzo de 2006

Arrastrar y soltar en el Administrador de Proyectos

Artículo original: FoxPro Tips Project Manager Dragging and Dropping
http://rickschummer.com/blog/2006/02/foxpro-tips-project-manager-dragging.html
Autor: Rick Schummer
Traducido por: Ana María Bisbé York

Algunos desarrolladores se sorprenden al conocer que el Administrador de Proyectos es, en materia de arrastrar y soltar, tanto cliente como servidor. Esto significa que los archivos pueden ser arrastrados al Administrador de Proyectos desde varios orígenes, incluyendo otros proyectos y desde fuera del Visual FoxPro. Si arrastra archivos desde el Explorador de Windows todos los archivos se agregarán al proyecto.

Arrastrar desde un proyecto a otro

Arrastrar archivos entre dos proyectos diferentes crea una referencia en el segundo proyecto hacia ese archivo. Si existe una descripción para ese archivo, esta descripción también se agrega al segundo proyecto, incluso para aquellos archivos que no guardan la descripción en el archivo como tal. Si en el conjunto de archivos hay un programa de inicio en el proyecto original, VFP preguntará si desea que este archivo sea programa de inicio en el segundo proyecto. No necesita estar en la misma página de cada proyecto. El archivo se coloca naturalmente agregado a la categoría basándose en la extensión del archivo.

Arrastrar objetos desde un proyecto hasta un diseñador

Arrastrar archivos desde el proyecto hasta un formulario o diseñador de clases puede ahorrar tiempo durante el desarrollo. Muchos objetos del proyecto pueden ser arrastrados al Diseñador de Clases o Formularios. Los objetos arrastrados son instanciados en el diseñador.

Al arrastrar un archivo desde una base de datos que contiene una tabla, vista o tabla libre o a un formulario o clase, instanciará la clase asociada según el tipo de datos. Las ventajas de estas posibilidades es que crea un objeto en la clase dentro del uso del entorno de datos. Muchos desarrolladores, a los que tutoreado a través de los años, piensan que necesitan arrastrar la clase y luego asignar su ControlSource.

Aunque trabaja la configuración manual del ControlSource, requiere que el desarrollador realice un paso extra. La otra ventaja de esta técnica es que incorpora la capacidad de arrastrar también IntelliSense, cuando se realiza esta operación desde el entorno de datos. De esta forma las clases especificadas de antemano se utilizan en lugar de las clases base de VFP. Las tablas arrastradas al formulario o clases se instanciarán en un grid. Si hace clic derecho y arrastra, tiene la opción para la clase grid (u otra clase para la que haya definido Configuración múltiple en el Field Mapping de Menú - Herramientas - Opciones - Panel de Tareas - Environment Manager).

Si desea arrastrar una clase específica sobre otra clase contenedora, puede seleccionarla en el Administrador de proyecto y arrastrarla a la clase contenedora. Esto no enlaza el objeto, como ocurre con el arrastre de un campo de una tabla. Esto permite sobreescribir los parámetros de IntelliDrop que ha configurado. Yo esperaba que un icono arrastrado pudiera establecer la propiedad Icon y que al arrastrar un objeto gráfico genere un objeto imagen. No ocurre así. Los objetos no mencionados en esta sección no se pueden arrastrar a un formulario o clase contenedora.

Arrastrar desde el proyecto a un programa

Con la misma idea descrita en la sección precedente, puede arrastrar y soltar diferentes objetos del proyecto a editores de código. El nombre del objeto se muestra en la ventana de código. Por ejemplo, si arrastra un nombre de campo a la ventana de Comandos, va a obtener el nombre de campo. Desafortunadamente no obtendrá la sintaxis nombretabla.nombrecampo. Esto trabaja para cada tipo de objeto en el proyecto excepto los nombres de procedimientos almacenados. Los único objetos que arrastran su extensión son los que se encuentran en la categoría "otros".

15 de marzo de 2006

Registrando cambios a vistas locales

Título original: Logging Changes to Local Views
Autor: Nancy Folsom (http://www.pixeldustindustries.com)
Traducido por: Luis María Guayán


Durante la creación de un prototipo, e incluso durante el desarrollo, frecuentemente, y a veces inadvertidamente, hago retoques a las vistas locales. Esto puede suceder, por ejemplo, cuando me he olvidado de utilizar NVL(), o si necesito cambiar una expresión del filtro. Seguro, esto no debería suceder nunca, excepto después de que el diseño haya documentado el cambio de diseño, pero, bien, sucede. Si es un cambio cuidadoso, o un cambio de prueba que no fue quitado, puede ser diabólicamente difícil de encontrar lo que ha roto de repente una vista. De todas formas, lo analicé esta semana y pasé algunos minutos implementando un simple evento de la base de datos que registrará mis cambios en la vista -una tarea que vengo tratando de hacer desde antes de tratar de limpiar mi sótano-.

Mi enfoque es utilizar un PRG externo a los procedimientos almacenados de la DBC así pueda utilizar los mismos eventos para múltiples contenedores de bases de datos. Para este artículo, agregué un registro de entrada similar para las modificaciones de las tablas, aunque mi interés principal estaba en las vistas.

El siguiente código creará una tabla de registro de cambios y un contenedor de bases de datos, crea un PRG externo con los eventos dbc_AfterModifyView y dbc_AfterModifyTable de la base de datos, y finalmente habilita los eventos de la base de datos, para la base de datos que usted seleccionó. Como advierto en los comentarios, asegúrese de respaldar sus datos primero, lo ideal es ejecutar este código en un contenedor de bases de datos de ejemplo para estar seguro que usted entiende cómo trabaja.

* 2005.12.20 Nancy Folsom, Pixel Dust Industries
* Este programa crea un contenedor de base de datos y una tabla
* para registrar las modificaciones en las tablas y vistas
* * Se asume que se ejecuta en el directorio de desarrollo
* * ¡Cuidado! Como cualquier código que cambia datos, primero 
* * haga un respaldo de sus datos, y pruebe el código sobre algunos
* * datos de prueba antes de ejecutarlo sobre datos de producción
*
* Creamos el registro de modificaciones
*
If !File('ChangeLog.DBC')
  Create Database ChangeLog
Endif
Open Database ChangeLog
Set Database To ChangeLog
Create Table ChangeLogEvents (;
  IID I Autoinc, cObjectName C(254), ;
  cAction C(254), mValue M, tTimeStamp T)
Local lcDBC, lcLogFile, lcPRG
*
* Creamos los eventos PRG usando los comandos TEXT y StrToFile()
*
TEXT to lcPrg textmerge noshow
Procedure dbc_AfterModifyView(cViewName, lChanged)
  If lChanged
    * 
    * Almacenamos la definición SQL. 
    * Deberiamos guardar todos los valores DBGETPROP
    *
    Insert Into ChangeLog!ChangeLogEvents ( ;
      cAction, mValue, cObjectName, tTimeStamp) ;
      Values ( "AfterModifyView", ;
      DBGetProp(cViewName,"VIEW","SQL"), cViewName, DATETIME() )
    Return .T.
  Endif
Endproc
Procedure dbc_AfterModifyTable(cTableName, lChanged)
  If lChanged
    Local lni, lnj, laArray[1], lcStructure
    lcStructure = "Field structures" + Chr(13)
    * Por cada campo en la tabla ...
    For lni = 1 To Afields(laArray,cTableName)
      For lnj = 1 To Alen(laArray,2) - 1
        * ... capturamos la estructura del campo
        lcStructure = lcStructure + Transform(laArray[lni,lnj]) + ", "
          Next lnj
        lcStructure = lcStructure + Transform(laArray[lni,lnj]) + Chr(13)
      Next lni
      lcStructure = lcStructure + Chr(13) + "Indices" + Chr(13)
      * Por cada etiqueta de índice ...
      For lni = 1 To Ataginfo(laArray,cTableName)
        For lnj = 1 To Alen(laArray,2) - 1
          * ... capturamos el nombre de la etiqueta y la expresión
          lcStructure = lcStructure + laArray[lni,lnj] + ", "
        Next lnj
        lcStructure = lcStructure + laArray[lni,lnj] + Chr(13)
      Next lni
      Insert Into ChangeLog!ChangeLogEvents (;
        cAction, mValue, cObjectName, tTimeStamp) Values (;
        "AfterModifyTable", lcStructure, cTableName, DATETIME())
    Endif
    Return .T.
  Endproc
ENDTEXT
* Guardamos la cadena que hicimos con TEXT en un PRG.
lcLogFile = Putfile("Events file", "DataBaseEvents","PRG")
Strtofile(lcPRG, lcLogFile)
* Tomamos la DBC para habilitar los eventos
lcDBC = Getfile('DBC')
* Abrimos la DBC, ponemos los eventos y ponemos el archivo de eventos 
* al PRG creado arriba
Open Database (lcDBC)
lcDBC = Juststem(lcDBC)
DBSetProp(lcDBC,"Database", "DBCEvents",.T.)
DBSetProp(lcDBC,"Database","DBCEventFilename", lcLogFile)
* Ya está. Cada vez que una vista o tabla es modificada, la estructura
* será registrada en ChangeLogEvents (o el nombre que usted quiera).
Hay claramente muchas direcciones que esto puede tomar. Una de mis metas es identificar cambios específicos, con las fechas, como parte de mi sistema de documentación. Lo invito a que me contacte en nfolsomNOSPAM@NOSPAMpixeldustindustries.com con cualquier comentario, pregunta o crítica. Sus comentarios serán bienvenidos.

Observese que los eventos de la base de datos fueron agregados en Visual FoxPro 7.0. Usted puede leer más sobre ellos en http://msdn.microsoft.com/library/en-us/dv_foxhelp/html/neconDatabaseContainerEvents.asp.

Nancy Folsom

13 de marzo de 2006

Funciones GetFile y GetPict eXtendidas

Estas funciones GetFile y GetPict eXtendidas nos permiten especificar en su primer parámetro la carpeta que se mostrará en el cuadro de diálogo "Abrir".

Las funciones nativas GetFile() y GetPict() de Visual FoxPro, muestran en el cuadro de diálogo "Abrir" la carpeta actual, sin permitir especificar otra carpeta. Estas dos funciones extendidas suman un nuevo parámetro a todos los parámetros de las funciones originales, para especificar una carpeta.

*-- Ejemplo de GetFileX()
? GetFileX()
? GetFileX(HOME(1)+ "Tools\GenDBC\","PRG")
? GetFileX("C:\Datos\","DBF","Nombre tabla:", "Abrir tabla", 0, "Busca tabla")

*-- Ejemplo de GetPictX()
? GetPictX()
? GetPictX(HOME(2) + "Solution", "BMP")
? GetPictX("C:\Fotografias\","","Foto:", "Abrir foto")

El código de ambas funciones es el siguiente:
**********************************************************************************
* FUNCTION GetFileX(tcRuta, tcExtension, tcLeyenda, tcBoton, tnBoton, tcTitulo)
********************************************************************************
* Función GetFile eXtendida. Al igual que la función GetFile muestra un cuadro
* de diálogo Abrir y retorna el nombre del archivo seleccionado. Si no se
* selecciona ningun archivo retorna una cadena vacia. La diferencia con
* GetFile() es que se puede especificar con el primer parámetro la carpeta
* donde se abre el cuadro de dialogo.
*
* RETORNA:
*   Caracter
* PARAMETROS:
*   tcRuta: Ruta inicial
*   tcExtension: Extension de los archivos que se muestran
*   tcLeyenda: Título del cuadro de texto "Nombre de archivo"
*   tcBoton: Título del botón "Aceptar"
*   tnBoton: Tipo y número de botones [0, 1 ó 2]
*   tcTitulo: Título de la ventana Abrir
* USO:
*   ? GetFileX("C:\Dat\","DBF","Nombre tabla:", "Abrir tabla", 0, "Busca tabla")
********************************************************************************
FUNCTION GetFileX(tcRuta, tcExtension, tcLeyenda, tcBoton, tnBoton, tcTitulo)
  LOCAL lcDirAnt, lcGetPict
  tcRuta = IIF(NOT EMPTY(tcRuta) AND DIRECTORY(tcRuta,1),tcRuta,"")
  tcExtension = IIF(EMPTY(tcExtension), "", tcExtension)
  tcLeyenda = IIF(EMPTY(tcLeyenda), "", tcLeyenda)
  tcBoton = IIF(EMPTY(tcBoton), "", tcBoton)
  tnBoton = IIF(EMPTY(tnBoton), 0, tnBoton)
  tcTitulo = IIF(EMPTY(tcTitulo), "", tcTitulo)
  lcDirAnt = FULLPATH("")
  SET DEFAULT TO (tcRuta)
  lcGetPict = GETFILE(tcExtension, tcLeyenda, tcBoton, tnBoton, tcTitulo)
  SET DEFAULT TO (lcDirAnt)
  RETURN lcGetPict
ENDFUNC

********************************************************************************
* FUNCTION GetPictX(tcRuta, tcExtension, tcLeyenda, tcBoton)
********************************************************************************
* Función GetPict eXtendida. Al igual que la función GetPict muestra un cuadro
* de diálogo Abrir imagen y retorna el nombre del archivo de imagen
* seleccionado. Si no se selecciona ningun archivo retorna una cadena vacia.
* La diferencia con GetPict() es que se puede especificar con el primer
* parámetro la carpeta donde se abre el cuadro de dialogo.
*
* RETORNA:
*   Caracter
* PARAMETROS:
*   tcRuta: Ruta inicial
*   tcExtension: Extension de los archivos de imagen que se muestra
*   tcLeyenda: Título del cuadro de texto "Nombre de archivo"
*   tcBoton:  Título del botón "Aceptar"
* USO:
*   ? GetPictX("C:\Imagenes\","JPG","Foto:", "Abrir foto")
********************************************************************************
FUNCTION GetPictX(tcRuta, tcExtension, tcLeyenda, tcBoton)
  LOCAL lcDirAnt, lcGetPict
  tcRuta = IIF(NOT EMPTY(tcRuta) AND DIRECTORY(tcRuta,1),tcRuta,"")
  tcExtension = IIF(EMPTY(tcExtension), "", tcExtension)
  tcLeyenda = IIF(EMPTY(tcLeyenda), "", tcLeyenda)
  tcBoton = IIF(EMPTY(tcBoton), "", tcBoton)
  lcDirAnt = FULLPATH("")
  SET DEFAULT TO (tcRuta)
  lcGetPict = GETPICT(tcExtension, tcLeyenda, tcBoton)
  SET DEFAULT TO (lcDirAnt)
  RETURN lcGetPict
ENDFUNC

********************************************************************************
Luis María Guayán

10 de marzo de 2006

¿Cómo verificar si una tabla está abierta en exclusiva? (II)

Algunos comandos (ZAP, PACK) requieren que el acceso al DBF sea de forma exclusiva, para tal motivo debe de revisarse si no existe algún otro cliente usando la tabla en cuestión (por lo que la función IsExclusive no nos es útil).

A continuación un par de métodos más utilizando otras técnicas basadas en la captura de error:
*--------------------------------------------------
FUNCTION _Exclusivo(tcTable, tlCloseTable)
  *--------------------------------------------------
  * Verifica (y usa) una tabla con acceso EXCLUSIVO
  * Check (and use) a table with EXCLUSIVE access
  * USO:
  *   ++ Revisa y usa una tabla, dejandola abierta
  *   ++ Check and use a table leaving it open
  *      _Exclusivo("C:\VFP\MiTabla.DBF")
  *      _Exclusivo("C:\VFP\MiTabla.DBF",.F.)
  *   ++ Revisa y usa una tabla en EXCLUSIVO, cierra la tabla después de eso.
  *   ++ Check if can open the table in EXCLUSIVE and close the table
  *   _Exclusivo("C:\VFP\MiTabla.DBF",.T.)
  * PARAMETRO/PARAMETERS:
  *   tcTable = Ruta completa del archivo .DBF
  *             Full path to the DBF File
  *   tlCloseTable = Indica si cerrará la tabla al finalizar el chequeo 
  *                  (default .F., no cierra la tabla)
  *                  Indicates if the checked table will be closed after 
  *                  the checking (default .F., leave open the table).
  * RETORNO/RETURNS: .T. si se puede abrir en exclusivo. 
  *                  If can open on exclusive access returns .T.
  * Developer: Esparta Palma (esparta @ gmail.com) http://www.PortalFox.com
  *--------------------------------------------------
  LOCAL llRetValue
  llRetValue = .T.
  *** Check If we are using VFP8 or newer version .
  *** Revisamos si tenemos VFP8 o posterior.
  #DEFINE isVFP8 (VERSION(5) >= 800)

  #IF NOT isVFP8
  *** If we dont have TRY..CATCH blocks use ON ERROR
  *** Si no tenemos bloques TRY...CATCH, usamos ON ERROR
    ON ERROR llRetValue = .F.
   *** Add FoxTools Library, to use the Function Juststem
   *** Agregamos la libreria FoxTools.fll para poder hacer uso de la función JustStem
    IF NOT ("FOXTOOLS.FLL" $ SET("LIBRARY"))
       SET LIBRARY TO (HOME(1)+"FoxTools.fll")
   ENDIF

  #ELSE
    *** We can use TRY...CATCH, let's use it
    *** Podemos usar TRY...CATCH, usémoslo
    TRY
    #ENDIF
    USE (tcTable) IN 0 EXCLUSIVE
    IF (llRetValue) AND (tlCloseTable)
      USE IN SELECT(JUSTSTEM(tcTable))
    ENDIF
    #IF isVFP8
    CATCH TO oError
      llRetValue = .F.
      MESSAGEBOX("Error al intentar usar en exclusivo:"+oError.MESSAGE)
    ENDTRY
  #ELSE
    ON ERROR
  #ENDIF
  RETURN llRetValue
ENDFUNC
La función arriba implementada utiliza condiciones de preprocesador para poderla utilizar transparentemente en cualquier versión de Visual FoxPro, si puede utilizar las técnicas de manejo de errores estructurados (TRY/CATCH) lo hará, de otro modo utilizará el truco de mandar una bandera en cuanto suceda un errror (con el problema de que se perderá su antigua configuración de ON ERROR.

Espero les sea de utilidad.

Espartaco Palma Martínez

8 de marzo de 2006

Se liberaron videos de Web Connection 5.0 Beta

Web Connection es una herramienta para trabajar con aplicaciones Web desde VFP. Fue creada por el gurú y MS MVP Rick Stralh. Acaban de ser liberados unos videos sobre la beta de la versión 5.0.

Por Ana María Bisbé York


Resumen

Pues sí, unos videos sobre la versión 5.0 Beta de Web Connection (http://www.west-wind.com/wconnect) han sido puestos a libre descarga por su creador, Rick Stralh. Lo ha comentado en su blog: http://west-wind.com/weblog/posts/3732.aspx

En este blog, Rick Stralh comenta que en esta nueva versión ha agregado nuevos controles y ha actualizado el framework para asegurarse de que tiene alta compatibilidad hacia atrás con la versión 4.x, de tal forma que las aplicaciones existentes puedan continuar ejecutándose con pocos cambio o ninguno.

Web Connection 5.0 introduce un modelo de programación al estilo ASP.NET, que está basado en controles utilizando los principios de orientación a objetos y la posibilidad de utilizar Visual Studio 2005 o Visual Web Developer, que es gratis, para el diseño de aplicaciones que utilizan código Visual FoxPro puro. Este nuevo framework combina lo mejor de ASP.NET y Visual FoxPro para lograr un entorno más productivo para desarrollos Web y Visual FoxPro.

Rick Stralh ha creado un conjunto de videos que muestran las novedades de funcionalidad, mucho mejor que en un artículo, se pueden descargar desde: http://www.west-wind.com/webconnection/videos.asp, además hay información disponible en http://www.west-wind.com/webconnection/docs/index.htm?page=_1LN1DG5DR.htm.

Para los que ya desarrollan con Web Connection este framework brinda muchas mejoras. Ofrece un modelo mucho más abierto y extensible para la generación de aplicaciones. Permite separar las aplicaciones web en clases para páginas individuales, que pueden lógicamente controlar acciones en una página Web con eventos en el servidor que se corresponden con los métodos ya existentes en las clases. Este modelo es muy parecido a ASP.NET - de hecho Web Connection trabaja con muchos de los controles nativos de ASP.NET, aunque querrá utilizar los controles específicos de Web Connection para aprovecharse de todo el control y las características de VFP que ya están en el framework. Por ejemplo, el enlace de datos a través de ControlSource es mucho más de lo que trae ASP.NET sobre databinding, y para los desarrolladores VFP es conocido que es un mecanismo muy poderoso y que trabaja fenomenal.

El soporte para el diseño visual significa además, que tiene la flexibilidad para diseñar aplicaciones utilizando un editor WYSIWYG (que en inglés significa "What You See Is What You Get", es decir lo que ve es lo obtiene) y controles basados en propiedades, así como un modelo de eventos que haga corresponder los eventos del servidor con el código FoxPro.

Comenta que está muy entusiasmado con todo esto, porque esta sincronización mejora con creces lo que venía haciendo con ASP.NET durante estos años. Aunque empleaba tanto ASP.NET como VFP, había gran desconexión entre los dos entornos - ahora están mucho más cerca, yo sigo encontrando mucha necesidad y deseo de seguir programando en VFP puro y hay muchos desarrolladores VFP que simplemente no desean moverse a .NET. Web Connection ofrece la forma de utilizar código FoxPro en un entorno ASP.NET sin la complicación de interoperabilidad con objetos COM.

Rick Stralh ofrece una reflexión muy interesante que traduzco directamente.

¿ASP.NET o FoxPro con Web Connection?

Con vistas a esta nueva versión he recibido muchas preguntas sobre si los desarrolladores deben utilizar ASP.NET puro o continuar aferrados a Visual FoxPro. Y la respuesta a esta pregunta es que depende del entorno de sus necesidades.

Aquellos que lean este blog con regularidad saben que yo utilizo mucho ASP.NET en mi trabajo, y aunque a veces me incomodan los problemas que aun tiene, en realidad, me gusta trabajar con ASP.NET y en mi opinión es una vía muy clara para aplicaciones nuevas y que van a crecer a largo plazo.

Sin embargo, comprendo que existen muchos desarrolladores, que tienen sus aplicaciones en Fox y a los que les es difícil pasarlas a .NET sin tener que re-escribirlas completamente. No existe algo como un conversor de aplicaciones FoxPro a .NET, básicamente es cosa de botar lo que hay y empezar de nuevo. Además hay muchos desarrolladores Fox con los que he hablado en este último año, que apenas han tocado superficialmente .NET o han movido algunos proyectos a .NET y se sienten terriblemente frustrados por la curva de aprendizaje de .NET y la carencia de facilidades en el uso de enlaces a datos en .NET, especialmente en términos de manipulación y enlace de datos locales.

Aunque no estoy de acuerdo con esto - veo el argumento de que el manejo de datos con .NET es marcadamente más complejo y menos flexible que lo que se puede hacer con el motor de datos Fox, incluso si existen las vías para realizar estas operaciones. Este framework brinda beneficios mucho mayores que ASP.NET - aumento de productividad, alto nivel de abstracción y soporte de diseño visual, sin tener que hacer una gran inversión en tecnología .NET. Al mismo tiempo, también ofrece la oportunidad de familiarizarse con el paradigma de Visual Studio, mientras continúa trabajando con Visual FoxPro. Incluso, dejando estos aspectos, pienso que el enfoque ASP.NET del framework Web Connection, es la vía más productiva de desarrollo Web que puedo imaginar para generar aplicaciones. Los demos y guías que he generado aquí toman una parte del tiempo que toman los métodos tradicionales de Web Connection, y son mucho más funcionales de arrancar (boot). Esto se puede apreciar con estos videos de demos.

Así, que estoy atrapado en medio de dos fuegos. Por una parte recibo de la gente de Fox quienes dicen que no quieren programar en .NET y por otro, la gente .NET que dice ¿utilizando FoxPro, bromeas? Esto es lo que hace la vida más interesante. Francamente a mi me da igual, porque hago lo que creo que funciona mejor. Y pienso que tengo una herramienta bien creada que es fácil de utilizar, productiva y mantenible y de esto se trata… En este momento, tengo frameworks Web trabajando en Fox y .NET que se corresponden, de tal horma que es fácil moverse entre ellos sin preocuparse por las barreras de los lenguajes. No se lo que Usted piensa; pero yo creo que esto es genial.

La conclusión aquí es que desde la primera vez que hablé y mostré esta herramienta, ha suscitado gran interés y he recibido gran cantidad de comentarios positivos que me animan a seguir adelante por este camino tanto para el negocio como para la perspectiva de desarrollo profesional. Para mí, es un proyecto interesante y divertido y espero haber sabido mostrarle mi entusiasmo.

Pues, aquí está, en las páginas de Web Connection hay mucha información, ayuda, artículos, etc. El blog de Rick Stralh se actualiza constantemente con valiosos comentarios y artículos.

Espero que les resulte de utilidad.

Saludos,

Ana María Bisbé York

3 de marzo de 2006

Códigos de barra 128 con lectura humana

En este artículo vamos a presentar unas funciones para imprimir códigos de barras del tipo 128 con diversas fuentes TrueType que nos permitirán lograr distintas alturas de códigos de barras y también la impresión de la cadena para lectura humana.

Los códigos 128

Como ya vimos en el artículo "Códigos de barras en reportes de Visual FoxPro", los códigos de barras 128 se dividen en 3 subconjutos:
  • El subconjunto A incluye: los dígitos, las letras mayúsculas, y los códigos de control.
  • El subconjunto B incluye: los dígitos, las letras mayúsculas y minúsculas, y los códigos de control.
  • El subconjunto C incluye: solo los dígitos y comprime dos dígitos numéricos en cada carácter, proporcionando una muy buena densidad de impresión.
Los códigos 128 se forman de la siguiente manera:
CaracterInicial + CadenaTexto + DigitoControl + CaracterFinal 
Las funciones descritas al final del artículo calculan el dígito de control y añaden los caracteres de inicio y final de cada tipo de código de barra 128, a la cadena de texto.

Las fuentes TrueType

Las siguientes son una descripción de las fuentes disponibles en este artículo:
  • Code 128AB (Bc128ab.ttf): Código 128 A y B Normal
  • Code 128AB Short (Bc128abs.ttf): Código 128 A y B Bajo
  • Code 128AB Tall (Bc128abt.ttf): Código 128 A y B Alto
  • Code 128AB HR (Bh128ab.ttf): Código 128 A y B Normal con Lectura Humana
  • Code 128AB Short HR (Bh128abs.ttf): Código 128 A y B Bajo con Lectura Humana
  • Code 128AB Tall HR (Bh128ab.ttf): Código 128 A y B Alto con Lectura Humana
  • Code 128C (Bc128c.ttf): Código 128 C Normal
  • Code 128C Short (Bc128cs.ttf): Código 128 C Bajo
  • Code 128C Tall (Bc128ct.ttf): Código 128 C Alto
  • Code 128C HR (Bh128c.ttf): Código 128 C Normal con Lectura Humana
  • Code 128C HR Short (Bh128cs.ttf): Código 128 C Bajo con Lectura Humana
  • Code 128C HR Tall (Bh128ct.ttf): Código 128 C Alto con Lectura Humana
  • Codigo de barras CyT (codigo_barras_cyt.ttf): Código 128 A y B Alto
Estas fuentes TrueType se corresponden adecuadamente al tamaño de fuente mínimo recomendado por Correos de España que es 24 y de un ancho máximo de 105 mm.

Los requisitos para los envíos a Correos de España son:
  • Código 128 A
  • Densidad entre 0,38 mm. y 0,63 mm.
  • Composición del código:
    • Tipo de producto en 2 posiciones: Consultar con Correos los tipos admitidos
    • Código de cliente en 8 posiciones: Solicitar el código a Correos
    • Número de envío en 13 posiciones: No puede repetirse antes de 5 años. Puede incluir el año como las 4 primeras posiciones
La fuente que mejor se adapta a estos requisitos es la "Code 128AB Tall HR" con un tamaño de 28 puntos.

Independientemente de lo expresado anteriormente, estas fuentes TrueType se pueden adaptar a cualquier necesidad de impresión de códigos de barras 128, por las diversas combinaciones posibles entre tipo, tamaño e impresión de la cadena para la lectura humana.

Las funciones en VFP

Las funciones en Visual FoxPro para cada uno de los tres tipo de código de barra 128 son las siguientes:
FUNCTION Codigo128A
  LPARAMETERS m.cadena
  *** Convierte una cadena para ser impresa en un
  *** código de barras de tipo 128 A
  *** Fuentes True Type válidas:
  *** "Code 128AB", "Code 128AB HR",
  *** "Code 128AB Short", "Code 128AB Short HR",
  *** "Code 128AB Tall", "Code 128AB Tall HR"  y
  *** "Codigo de barras CyT"
  IF PCOUNT() = 0
    RETURN ""
  ENDIF
  IF TYPE("m.cadena") = "N"
    m.cadena = TRANSFORM(m.cadena)
  ENDIF
  IF TYPE("m.cadena") != "C"
    RETURN ""
  ENDIF
  m.cadena = ALLTRIM(m.cadena)
  LOCAL m.vuelta, m.suma, m.caracterinicial, m.co, m.letra, ;
    m.valorascii, m.checksum, m.caracterfinal
  m.suma = 103
  m.caracterinicial = CHR(123)
  m.vuelta = m.caracterinicial
  m.caracterfinal = CHR(126)
  FOR m.co = 1 TO LEN(m.cadena)
    m.letra = SUBSTR(m.cadena, m.co, 1)
    m.valorascii = ASC(m.letra)
    m.valorascii = m.valorascii - IIF(m.valorascii < 123, 32, 70)
    m.suma = m.suma + (m.valorascii * m.co)
    m.vuelta = m.vuelta + IIF(m.letra = " ", CHR(174), m.letra)
  NEXT m.co
  m.checksum = MAX(MOD(m.suma, 103), 0)
  m.checksum = m.checksum + IIF(m.checksum > 90, 70, IIF(m.checksum = 0, 174, 32))
  m.checksum = CHR(m.checksum)
  m.vuelta = m.vuelta + m.checksum + m.caracterfinal
  RETURN m.vuelta
ENDFUNC
FUNCTION Codigo128B
  LPARAMETERS m.cadena
  *** Convierte una cadena para ser impresa en un
  *** código de barras de tipo 128 B
  *** Fuentes True Type válidas:
  *** "Code 128AB", "Code 128AB HR",
  *** "Code 128AB Short", "Code 128AB Short HR",
  *** "Code 128AB Tall", "Code 128AB Tall HR"  y
  *** "Codigo de barras CyT"
  IF PCOUNT() = 0
    RETURN ""
  ENDIF
  IF TYPE("m.cadena") = "N"
    m.cadena = TRANSFORM(m.cadena)
  ENDIF
  IF TYPE("m.cadena") != "C"
    RETURN ""
  ENDIF
  m.cadena = ALLTRIM(m.cadena)
  LOCAL m.vuelta, m.suma, m.caracterinicial, m.co, m.letra, m.valorascii, ;
    m.checksum, m.caracterfinal
  m.suma = 104
  m.caracterinicial = CHR(124)
  m.vuelta = m.caracterinicial
  m.caracterfinal = CHR(126)
  FOR m.co = 1 TO LEN(m.cadena)
    m.letra = SUBSTR(m.cadena, m.co, 1)
    m.valorascii = ASC(m.letra)
    m.valorascii = m.valorascii - IIF(m.valorascii < 123, 32, 70)
    m.suma = m.suma + (m.valorascii * m.co)
    m.vuelta = m.vuelta + IIF(m.letra = " ", CHR(174), m.letra)
  NEXT m.co
  m.checksum = MAX(MOD(m.suma, 103), 0)
  m.checksum = m.checksum + IIF(m.checksum > 90, 70, IIF(m.checksum = 0, 174, 32))
  m.checksum = CHR(m.checksum)
  m.vuelta = m.vuelta + m.checksum + m.caracterfinal
  RETURN m.vuelta
ENDFUNC
FUNCTION Codigo128C
  LPARAMETERS m.cadena
  *** Convierte una cadena para ser impresa en un
  *** código de barras de tipo 128 C
  *** Fuentes True Type válidas:
  *** "Code 128C", "Code 128C HR",
  *** "Code 128C Short", "Code 128C HR Short",
  *** "Code 128C Tall", "Code 128C HR Tall"
  IF PCOUNT() = 0
    RETURN ""
  ENDIF
  IF TYPE("m.cadena") = "N"
    m.cadena = TRANSFORM(m.cadena)
  ENDIF
  IF TYPE("m.cadena") != "C"
    RETURN ""
  ENDIF
  m.cadena = ALLTRIM(m.cadena)
  LOCAL m.vuelta, m.suma, m.caracterinicial, m.co, m.letra, ;
    m.valorascii, m.valorreal, m.checksum, m.caracterfinal
  m.suma = 105
  m.caracterinicial = CHR(125)
  m.vuelta = m.caracterinicial
  m.caracterfinal = CHR(126)
  IF LEN(m.cadena) % 2 # 0
    m.cadena = "0" + m.Cadena
  ENDIF
  FOR m.co = 1 TO LEN(m.cadena) STEP 2
    m.letra = SUBSTR(m.cadena, m.co, 2)
    m.valorreal = VAL(m.letra)
    m.valorascii = m.valorreal + IIF(m.valorreal < 90, 33, 71)
    m.suma = m.suma + (m.valorreal * CEILING(m.co/2))
    m.vuelta = m.vuelta + CHR(m.valorascii)
  NEXT m.co
  m.checksum = MAX(MOD(m.suma, 103), 0)
  m.checksum = m.checksum + IIF(m.checksum < 90, 33, 71)
  m.checksum = CHR(m.checksum)
  *-- Reemplazo CheckSum
  m.checksum = CHRTRAN(m.checksum, ;
    CHR(171)+CHR(172)+CHR(173), CHR(176)+CHR(177)+CHR(178))
  m.vuelta = m.vuelta + m.checksum + m.caracterfinal
  RETURN m.vuelta
ENDFUNC

Nota importante: Estas funciones solo se corresponden con las fuentes TrueType de este artículo. Las funciones de los artículos "Códigos de barras en reportes de Visual FoxPro" y "Resolución General 1702 de la AFIP (Argentina)" se corresponden a las fuentes disponibles para descarga de cada artículo. Cada fuente tiene su función asociada para la correcta generación de los distintas simbologías de códigos de barras.

Ejemplos

Para utilizar las funciones se debe pasar como parámetro la cadena a codificar:
lc128A = Codigo128A("CODIGO128A")
lc128B = Codigo128B("codigo128b")
lc128C = Codigo128C("16886271")
Para la impresión se debe seleccionar la fuente correspondiente a cada función:
CLEAR
? Codigo128A("CODIGO128A") FONT "Code 128AB Short HR",36
? Codigo128B("codigo128b") FONT "Code 128AB Tall HR",36
? Codigo128C("16886271") FONT "Code 128C HR",60
?
? Codigo128A("PortalFox") FONT "Codigo de barras CyT",48



Descargas

Estos son los enlaces para las descargas disponibles de este artículo:
  • Para descargar un proyecto de ejemplo haga clic aquí. (ejemplo128.zip 6,6 KB)
  • Hasta la próxima.

    Carlos Yohn Zubiria (España) y Luis María Guayán (Argentina)