Nuevas órdenes en VFP 6.0

Por la Redacción de FoxPress
© Copyrights 1998 by FoxPress, All rights reserved
FoxPress, Octubre 1998

En estas líneas quiero comentar algunas de las nuevas ordenes de VFP 6.0 frente a VFP 5.0. No es una relación exhaustiva y tampoco están ordenadas por importancia sino que van apareciendo según me las he ido encontrando.

HOME(2)

En VFP 5.0 ya teníamos la función HOME() que nos devolvía el nombre del directorio desde el que se inició Visual FoxPro.

En VFP 6.0 tenemos la opción de HOME(2) que nos da también el directorio en el que se encuentran los ejemplos. El único problema que he visto es que si no tienes instalados los ejemplos no devuelve nada.

VARTYPE()

No existe en VFP 5.0

En VFP 6.0 sí existe y esta función es muy similar a la función TYPE() de VFP 5.0 pero ahora nos ahorramos las comillas.

En VFP 5.0 para saber de qué tipo era una variable tenías que ponerla entre comillas de una forma parecida a esto:

 x = 5
? TYPE (‘x’)

que nos devolvía: N

Ahora es mucho más cómodo pues escribes:

x = 5
? VARTYPE(x)
que nos devolverá N

Es mucho más cómodo aunque pierdes la interoperabilidad hacia atrás.

COMPILE DATABASE

En VFP 5.0 no existe.

En VFP 6.0 te permite quitar todos los registros marcados para borrar de tu .DBC

En toda la fase de diseño de una aplicación se van añadiendo y quitando tablas de la Base de Datos y añadiendo y modificando tablas de los campos. Todo esto implica un movimiento de registros en la tabla que almacena la información del .DBC. Esos registros marcados no se borran y uno de pronto un día descubría que su .DBC tenía varios megas y asustado lo abría como una tabla y al ver tantos registros marcados los borraba con un PACK.

Esto mismo ahora te lo hace el COMPILE DATABASE DE VFP 6.0

ALTER TABLE con soporte de FOR

Esta es una de esas mejoras que es suficiente para justificar el pasarse a VFP 6.0

La razón estriba en que en VFP 5.0 no puedes crear por código índices principales filtrados.

Tal vez me puedas argumentar que es relativamente raro tener que crear por código este tipo de índices pero te respondería que si quieres poder ‘rehacer’ toda tu Base de Datos por código, es seguro que tendrás que hacer esto.

En VFP 5.0 los que necesitaban rehacer toda su Base de Datos por código lo que hacían era en vez de usar Indices principales filtrados era el uso de Indices candidatos filtrados que sí están accesibles en esa versión.

CLASSINFO()

VFP 6.0 viene con una nueva función llamada CLASSINFO(). En un principio pensaba que esta función nos podría servir para saber si está instalada una aplicación como el Word o el Excel pero sufrí una pequeña frustración.

Esta función nos da el ProgID y el CLSID de las aplicaciones instaladas.

Supongamos que queremos saber qué versión del ADO tenemos en nuestra máquina, entonces deberemos escribir:

x = CREATE('ADODB.RECORDSET')
? COMCLASSINFO(x,1)
? COMCLASSINFO(x,4)

Si quisieramos hacer lo mismo pero con VFP 6.0 deberíamos escribir:

x = CREATE('VISUALFOXPRO.;
APPLICATION')
? COMCLASSINFO(x,1)
? COMCLASSINFO(x,4)

Aparentemente es muy interesante esto pero tiene una pega y es que previamente hay que crear una instancia del objeto para posteriormente ser analizada por la función COMCLASSINFO() con lo que si el objeto no existe se produce un error no controlado. O sea, seguimos igual. Si queremos saber si el usuario tiene instalado el word 8.0 deberemos seguir usando las funciones del API de windows.

STRTOFILE() y FILETOSTR()

La función STRTOFILE(), que es nueva en VFP 6.0 envía el contenido de una cadena a un archivo. Al permitir otros tipos de salida puede también enviar esa cadena a la impresora. El fuente que se adjunta sacado del documento Q190769 envía el contenido de una cadena o un Array a la impresora que se escoja.

La función FILETOSTR(), por su parte, lleva el contenido de un archivo a una cadena.

1. Ejecuta el siguiente código desde un archivo de tipo (.prg):

LOCAL lcString_to_Output, laOutput[1] ;
		lcOutPut = ""

* Obtiene información de la versión de 
* VFP6.exe, 
* y lo deja en un array.

=AGETFILEVERSION(laOutput, ;
HOME()+'vfp6.exe')

* Convierte el contenido de ese Array a 
* una cadena con la función 
* Array_to_String. Fíjate que hay un salto 
* de línea y una línea en blanco detrás de
 * cada línea

lcString_to_Output = ;
Array_to_String(@laOutput)

* Imprime la cadena

 =Print_a_String(lcString_to_Output)

* Se adegura de que el .prg no está 
* abierto.

CLOSE ALL

* Print this PRG file after converting it to a string with
* FILETOSTR().
=Print_a_String(FILETOSTR(SUBSTR(SYS(16),;
	1, LEN(SYS(16))-3) + 'prg'))

RETURN

PROC Print_a_String
LPARAMETER tcStringToPrint
LOCAL laPrinters[1,1], lnArrayRow, ;
lcPrinter
* Se selecciona la impresora.

lcPrinter = GETPRINTER()

* Se debería usar el SET('printer', 2) 
* para obtener los valores por defecto de * Windows y
* printer, o SET('printer', 3) para 
* devolver la impresora por defecto de 
* VFP.

IF LEN(lcPrinter) = 0
RETURN .F.
ENDIF
=APRINTERS(laPrinters)
lnArrayRow = ASUBSCRIPT(laPrinters, ASCAN(laPrinters, lcPrinter),1)

* IIF usa la segunda columna del array 
* laPrinters en Windows 95, y 
* la primera en Windows NT.

* El último argumento .T. pasado a  
* STRTOFILE() siginifica ADDITIVE output.

IF STRTOFILE(tcStringToPrint, ;
      laPrinters[lnArrayRow,IIF;
('NT'$OS(), 1, 2)], ;
      .T.) > 0
* Ha sido exitoso ya que no se han escrito 
* bytes.
   RETURN .T.
ELSE

* No ha sido exitoso ya que no se han 
* escrito bytes.
    RETURN .F.
ENDIF
ENDPROC

PROC Array_to_String
LPARAMETERS tcarray
* Note: Esto exige modificación si se 
* pretende escribir con arrays 
* multicolumnas
LOCAL lni, lcOutPut
lcOutPut = ""

#DEFINE       CR_LF       CHR(13)+CHR(10)

FOR lni = 1 TO ALEN(tcarray)
 lcOutPut = lcOutPut + tcarray[lni] + CR_LF
ENDFOR
RETURN lcOutPut
ENDPROC

2. Selecciona un destino para imprimir cada vez que uno es interrogado.

Este código imprime la información sobre la versión de Visual FoxPro 6.0 y el contenido del programa.

Cada vez que imprimas de esta manera debes de tener cada línea terminada con un salto de carro y otra línea sin caracteres para asegurar que se muestra bien la información

Window NT usa la el nombre de la impresora que está en la primera columna del array creado por APRINTERS(). Windows 95 usa el puerto que está en la segunda columna del array creado pro APRINTERS().

El método setViewPort de los Formularios

Cuantas quejas se escucharon sobre el tema de que los formularios no tenían barras de scroll... Pues bien, ahora tenemos la propiedad scrollbar que te permite activar los scroll en caso de que todos los objetos que tienes no te quepan en el formulario.

Ahora también se tiene un evento scrolled para detectar cuando el usuario ha pulsado sobre el scroll y las propiedades Viewportleft y ViewporTop.

Pero seguía existiendo un problema, a diferencia del Grid que sí que tiene un método de scroll de forma que puedes por programa hacer que el scroll avance para ir a un registro determinado, el formulario por defecto no tiene ese método.

Para poder imitar ese funcionamiento se debe usar el método SetViewPort para programáticamente hacer un scroll del formulario.

El siguiente ejemplo nos muestra la forma de hacer esto usando las teclas de Avance de Página y de Retroceso de Página:

PUBLIC oform
oform=NewObject("ScrollForm")
oform.show

DEFINE CLASS ScrollForm AS form
 Top = 0
 Left = 0
 Height = 101
 Width = 168
 ScrollBars = 2
 Caption = "Use PgUp/PgDwn to Scroll Form"
 vertscrollpos = 0
 Name = "Form1"
 ADD OBJECT shape1 AS shape WITH ;
         Top = 12, ;
         Left = 12, ;
         Height = 421, ;
         Width = 553, ;
         Name = "Shape1"
      ADD OBJECT command1 AS ;
commandbutton WITH ;
         Top = 24, ;
         Left = 36, ;
         Height = 27, ;
         Width = 84, ;
         Caption = "Close", ;
         Name = "Command1"

      PROCEDURE KeyPress
         LPARAMETERS nKeyCode,;
 nShiftAltCtrl
         IF nKeyCode=3
            Thisform.vertscrollpos=;
Thisform.;
vertscrollpos+;
Thisform.height
            Thisform.SetViewPort(;
0,Thisform.;
vertscrollpos)
            Thisform.Refresh
         ENDIF
         IF nKeyCode=18
            Thisform.vertscrollpos;
=Thisform.;
vertscrollpos-thisform.;
height
            Thisform.SetViewPort(;
0,Thisform.;
vertscrollpos)
            Thisform.Refresh
         ENDIF
      ENDPROC
      PROCEDURE command1.Click
         thisform.release
      ENDPROC
   ENDDEFINE

CREATE FORM.... AS FROM

En VFP 5.0 cuando creabas un formulario con CREATE FORM siempre se basaba en la clase que tuvieras especificada en la pestaña de Herramientas/Opciones.

Si querías basarte en otra clase previamente tenías que cargarla en memoria con el SET CLASSLIB TO...

En VFP 6.0 puedes hacerlo sencillamente con :

CREATE FORM nuevo_form AS ;
clase_form FROM ;
(‘FICHERO_DE_CLASES’)

O también con:

oForm = NEWOBJECT(‘clase_form’,;
’fichero_de_clases’)
oForm.saveas(‘nuevo_form’)
oForm.Release
MODIFY FORM nuevo_form NOWAIT

Los métodos ACCESS y ASSIGN

Visual FoxPro 6.0 te da la capacidad de vincular eventos a propiedades.

Esto se realiza mediante los métodos Access y Assign. Estos eventos se dispararán cuando el valor de una propiedad es leída o cambiada respectivamente. Esto es, cuando en tu aplicación cualquier código evalúa el estado de u na propiedad se dispara el método ACCESS. Por su parte si el valor de esa propiedad ha cambiado se dispara el ASSIGN

Esto tiene muchas consecuencias. Hasta ahora el número de eventos de VFP estaba limitado al número de eventos de windows y a los eventos que el diseñador de VFP había dejado. Ahora puedes tener tantos eventos como quieras.

No obstante, estos métodos deben ser bien codificados

Ejecuta el siguiente código desde un programa.

      PUBLIC oform1

      oform1=NEWOBJECT("form1")
      oform1.SHOW
      RETURN

      DEFINE CLASS form1 AS FORM

         AUTOCENTER = .T.
         CAPTION = "Form1"
         NAME = "Form1"

         PROCEDURE this_access
            LPARAMETERS cMemberName
            ? cMemberName, ;
TTOC(DATETIME())
            RETURN THIS
         ENDPROC

         PROC MOVED
            = THIS.TOP
            = THIS.LEFT
            ?
         ENDPROC

         PROC RESIZE
            = THIS.WIDTH
            = THIS.HEIGHT
            ?
         ENDPROC

      ENDDEFINE

Mueve el formulario con el ratón y verás como van apareciendo en pantalla una serie de datos.

SYS(3055)

En VFP 6.0 se ha levantado el límite que había de 23 campos que había con el TABLEUPDATE() con las Vistas Locales . Ahora tenemos una nueva función para poder establecernos el control de lo que será el nuevo límite.

Para demostrarlo se muestra a continuación un programa que escribió Lisa Slater para el foro de la Beta de VFP 6.0

1.- Quita los campos desde el F27 al F48 y ejecuta el siguiente código y verás que funciona.

2.- Deja el código como está y verás que el programa no funciona.

3.- Ejecuta SYS(3055,(*48) y ejecútalo de nuevo y verás que sí que funciona.

La función SYS(3055) acepta valores hasta 2040 que casualmente es 255 * 8.

CLOSE ALL
ERASE viewdbc.dbc
ERASE VIEWDBC.dcx
ERASE viewdbc.dct
ERASE viewtest.dbf

CREATE DATABASE viewdbc

create table VIEWTEST ;
(F01 C(10), F02 C(10), F03 C(10),;
 F04 C(10), F05 C(10), F06 C(10),;
 F07 C(10), F08 C(10), F09 C(10),;
 F10 C(10), F11 C(10), F12 C(10),;
 F13 C(10), F14 C(10), F15 C(10),;
 F16 C(10), F17 C(10), F18 C(10),;
 F19 C(10), F20 C(10), F21 C(10),;
 F22 C(10), F23 C(10), F24 C(10),;
 F25 C(10), F26 C(10), F27 C(10),;
 F28 C(10), F29 C(10), F30 C(10),;
 F31 C(10), F32 C(10), F33 C(10),;
 F34 C(10), F35 C(10), F36 C(10),;
 F37 C(10), F38 C(10), F39 C(10),;
 F40 C(10), F41 C(10), F42 C(10),;
 F43 C(10), F44 C(10), F45 C(10),;
 F46 C(10), F47 C(10), F48 C(10),)

SET MULTILOCKS ON

CURSORSETPROP('Buffering',5)
APPEND BLANK
TABLEUPDATE()
USE

CREATE SQL VIEW lv_viewtest ;
AS SELECT * FROM viewdbcviewtest

USE lv_viewtest
CURSORSETPROP('Sendupdates',.t.)
CURSORSETPROP('KeyfieldList',.F01)

* Se usa Scatter y Gatter para cambiar 
* todos los campos a la vez

SCATTER MEMVAR
GATHER MEMVAR
IF! TABLEUPDATE (.F.)
	AERROR(laErr)
	MESSAGEBOX('Falló la actualización de ;
la Vista Local')
	+ CHR(13) + 'Error: ';
	+ ALLTRIM(STR(laerr[1]));
	+ ''+ laerr[2])
	TABLEREVERT()
ELSE	
	MESSAGEBOX('Vista Local actualizada')
ENDIF

CLOSE ALL
Alines()

Cuantas veces ha habido que tratar y organizar información de los campos Memo para ordenar o buscar algún dato. Esta función te mete todo el contenido de un campo Memo en un Array metiendo cada línea del campo Memo en un elemento del Array

Si escribes en un Memo:

	Esto es una prueba
	del funcionamiento
	de esta novedosa función	

y ejecutas:

USE Prueba
ALINES(lcArray,Campo_Memo, .T.)
DIPLAY MEMO LIKE lcarray

verás:

LCARRAY 		Pub		A
(   1)			C		“Esto es una prueba”
(   2)			C		“del funcionamiento”
(   3)			C		“de esta novedosa función”

INDEXSEEK()

El interés de esta nueva función radica en que busca un valor sin mover el puntero devolviendo .T. ó .F. Es muy útil para comprobar si determinado valor que es un índice clave existe sin tener que moverse del registro actual en el que se están realizando los cambios.

Respecto a la velocidad de búsqueda, efectivamente el SEEK con la función FOUND() sigue siendo el sistema más rápido seguido por la función SEEK() y a continuación INDEXSEEK(,.T.) seguido por INDEXSEEK(,.F.)

El segundo parámetro del INDEXSEEK nos indica si se debe mover el puntero (.T.) o no (.F.). Este último es el valor por defecto.

Nos dejamos....

Ni son todas las que están, ni están todas las que son. Nos dejamos en el tintero electrónico algunas novedades como las nuevas implementaciones del OS(), o el aNetResources() o incluso el NEWOBJECT() que las comentaremos más adelante.