28 de abril de 2015

Encontrar la ruta de las carpetas especiales

Artículo original: Finding the Paths for Special Folders
http://doughennig.blogspot.com/2007/01/finding-paths-for-special-folders.html
Autor: Doug Hennig
Traducido por: Ana María Bisbé York


Guardar los archivos de datos de una aplicación en el lugar correcto tiene dificultades en Windows Vista. La mayoría de los desarrolladores simplemente escriben en los archivos INI guardados en la carpeta de la aplicación (usualmente c:\Archivos de programa\Alguna carpeta) y guardan los archivos de datos en la carpeta Data en esa carpeta. Por su parte, Microsoft ha criticado fuertemente esta práctica en el pasado, y ahora hace que ,incluso si está iniciado como administrador, falle el escribir a algunos recursos protegidos, como C:\Archivos de programa o el HKEY_LOCAL_MACHINE metido en el registro.

Esto puede romper la mayoría de las aplicaciones heredadas (cualquiera escrita antes de Vista). Entonces, para evitar esto, están ejecutándose en modo compatible XP. A través de un proceso llamado virtualización, la escritura a recursos protegidos son redirigidos por el sistema operativo a algún otro lugar. Por ejemplo, intentar escribir a un archivo en C:\Archivos de programa\Alguna carpeta provoca que el archivo se cree o actualice en C:\Usuarios\NombredeUsuario\AppData\Local\VirtualStore\Archivos de programa\Alguna carpeta.

Mientras es bueno que Microsoft proteja nuestras aplicaciones contra errores, esto realmente es una solución a corto plazo. Es mejor revisar dónde están almacenados los datos y emplear una de los localizaciones preferidas, tales como: C:\ProgramData para la configuración global y C:\Usuarios\NombredeUsuario\AppData\Local para los datos específicos del usuario. El problema es que no debe escribir directamente en los programas estas rutas, especialmente si algunos usuarios están trabajando en Vista y otros en XP. En su lugar, utilice funciones API para determinar estas localizaciones.

SpecialFolders.PRG es un envoltorio para estas funciones. Devuelve los valores adecuados sin importarle si la aplicación se está ejecutando en Windows o XP. Vea los comentarios en el encabezado para la descripción de los parámetros a pasar. Este código no controla todas las carpetas especiales, solamente las más comunes; pero es fácilmente actualizable para trabajar también con las otras carpetas.

*==============================================================================
* Programa: SpecialFolders.PRG
* Objetivo: Determinar la ruta a las carpetas especiales especificadas
* Autor: Doug Hennig
* Última revisión: 01/24/2007
* Parámetros: tuFolder - la carpeta a la que se quiere obtener la ruta.
* Especifica el  valor CSIDL para la carpeta deseada 
* (la que podemos obtener desde:
* http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp
* o emplea una de las siguientes cadenas:
* "AppData": datos específicos de la aplicación
* "CommonAppData": datos de la aplicación para todos los usuarios
* "Desktop": Escritorio del usuario
* "LocalAppData": datos para aplicaciones locales (que no se desplazan)
* "Personal": carpeta Mis Documentos
* Devuelve: La ruta para la carpeta especificada o blanco 
* si no encuentra la carpeta
* Entorno de entrada: Ninguno
* Entorno de salida: Error 11 ocurre si tuFolder no ha sido especificado correctamente
* Notas: Este código ha sido adaptado desde:
* http://msdn2.microsoft.com/en-us/library/aa140088(office.10).aspx
* Es posible agregar fácilmente soporte para otros CSIDLs 
*==============================================================================

lparameters tuFolder
  local lcPath, ;
  lnFolder, ;
  lcFolder, ;
  lnPidl, ;
  lnPidlFound, ;
  lnFolderFound

* Define los valores CSIDLs para las diferentes carpetas.

#define CSIDL_APPDATA 0x1A
* Datos específicos de la aplicación:
* XP: C:\Documents and Settings\username\Application Data
* Vista: C:\Users\username\AppData\Roaming
#define CSIDL_COMMON_APPDATA 0x23
* Datos de la aplicación para todos los usuarios:
* XP: C:\Documents and Settings\All Users\Application Data
* Vista: C:\ProgramData
#define CSIDL_DESKTOPDIRECTORY 0x10
* Escritorio del usuario:
* XP: C:\Documents and Settings\username\Desktop
* Vista: C:\Users\username\Desktop
#define CSIDL_LOCAL_APPDATA 0x1C
* datos para aplicaciones locales (que no se desplazan):
* XP: C:\Documents and Settings\username\Local Settings\Application Data
* Vista: C:\Users\username\AppData\Local
#define CSIDL_PERSONAL 0x05
* Carpeta Mis Documentos:
* XP: C:\Documents and Settings\username\My Documents
* Vista: C:\Users\username\Documents

* Definir algunas otras constantes.
#define ERR_ARGUMENT_INVALID 11
#define MAX_PATH 260
#define NOERROR 0
#define SUCCESS 1

* Comprobar los parámetros.

do case

  * Si es numérico, asume que es un valor CSIDL válido;  
  * si no, la función API devuelve una cadena vacía

  case vartype(tuFolder) = 'N'
    lnFolder = tuFolder

  * Se ha pasado un tipo de dato no válido o una carpeta vacía

  case vartype(tuFolder) <> 'C' or empty(tuFolder)
    error ERR_ARGUMENT_INVALID
    return ''

  * Si se ha pasado una cadena, lo convierte en el valor CSIDL adecuado.

  otherwise
    lcFolder = upper(tuFolder)
    do case
      case lcFolder = 'APPDATA'
        lnFolder = CSIDL_APPDATA
      case lcFolder = 'COMMONAPPDATA'
        lnFolder = CSIDL_COMMON_APPDATA
      case lcFolder = 'DESKTOP'
        lnFolder = CSIDL_DESKTOPDIRECTORY
      case lcFolder = 'LOCALAPPDATA'
        lnFolder = CSIDL_LOCAL_APPDATA
      case lcFolder = 'PERSONAL'
        lnFolder = CSIDL_PERSONAL
      otherwise
        error ERR_ARGUMENT_INVALID
        return ''
    endcase
endcase

* Declara las funciones API que necesitamos.

declare long SHGetSpecialFolderLocation in shell32 long hWnd, long nFolder, ;
  long @ ppidl
declare long SHGetPathFromIDList in shell32 long Pidl, string @ pszPath
declare CoTaskMemFree in ole32 long pvoid

* Inicia las variables que actualizará la función API.

lcPath = space(MAX_PATH)
lnPidl = 0

* Obtiene la ruta para las carpetas especificadas.

lnPidlFound = SHGetSpecialFolderLocation(0, lnFolder, @lnPidl)
if lnPidlFound = NOERROR
  lnFolderFound = SHGetPathFromIDList(lnPidl, @lcPath)
  if lnFolderFound = SUCCESS
    lcPath = left(lcPath, at(chr(0), lcPath) - 1)
  endif lnFolderFound = SUCCESS
endif lnPidlFound = NOERROR
CoTaskMemFree(lnPidl)
lcPath = alltrim(lcPath)
return lcPath

27 de abril de 2015

Eliminar directorio y subdirectorios contenidos

Una solución efectiva, utilizando recursividad y funciones del API de Windows. Cortesía de Çetin Basöz
Set Date Dmy
Local ldFolder,lcBaseFolder,ix
Local Array aFolders[1]
lcBaseFolder = 'e:\Backup'
APIDeclarations()
For ix=1 To Adir(aFolders,Addbs(m.lcBaseFolder)+'*',"DRHS")
  ldFolder = Ctod(Transform(aFolders[m.ix,1], \@R 99/99/9999'))
  If !Empty(m.ldFolder) And m.ldFolder < Date()-1
    RemoveFolder(Addbs(m.lcBaseFolder)+aFolders[m.ix,1])
  Endif
Endfor

Function RemoveFolder(m.tcPath)
  GetSubdirs(m.tcPath,'DirList')
  Select Dirlist
  Local Array laFolders[Reccount()]
  Scan
    laFolders[Recno()] = dirname
  Endscan
  Use In 'DirList'
  Asort(laFolders,1,-1,1,1)
  For jx=1 To Alen(laFolders)
    RemoveSubFolder(laFolders[m.jx])
  Endfor
Endfunc

Function GetSubdirs
  Lparameters tcPath,tcCursorName
  Local ix
  Local Array laDirs[1]
  If !Used(m.tcCursorName)
    Create Cursor (m.tcCursorName) (dirname m)
  Endif
  Insert Into (m.tcCursorName) Values (Upper(m.tcPath))
  For ix = 1 To Adir(laDirs,Addbs(m.tcPath)+"*.*","DRHS")
    If laDirs[ix,1]#"." And "D"$laDirs[ix,5]
      GetSubdirs(Addbs(m.tcPath)+laDirs[ix,1],m.tcCursorName)
    Endif
  Endfor
Endfunc

Function RemoveSubFolder(tcPath)
  Local Array laFiles[1]
  Local ix
  For ix=1 To Adir(laFiles,Addbs(m.tcPath)+'*.*','HRS')
    setAttribs(Addbs(m.tcPath)+laFiles[m.ix,1])
  Endfor
  setAttribs(Addbs(m.tcPath))
  Erase (Addbs(m.tcPath)+'*.*')
  Rmdir (m.tcPath)
Endfunc

Function APIDeclarations
  Declare Integer SetFileAttributes In Win32API ;
    string @ lpFileName,  Integer dwFileAttributes
  Declare Integer GetFileAttributes In Win32API ;
    string @ lpFileName
Endfunc

Function setAttribs
  Lparameters tcFileName, tlReadOnly, tlHidden, tlSystem
  #Define FILE_ATTRIBUTE_READONLY    0x00000001
  #Define FILE_ATTRIBUTE_HIDDEN      0x00000002
  #Define FILE_ATTRIBUTE_SYSTEM      0x00000004
 Local lnNewAttr  lnNewAttr = Iif(m.tlReadOnly,FILE_ATTRIBUTE_READONLY,0)+;
    iif(m.tlHidden,FILE_ATTRIBUTE_HIDDEN,0)+;
    iif(m.tlSystem,FILE_ATTRIBUTE_SYSTEM,0)

  Return ( SetFileAttributes(@tcFileName, ;
    bitor(Bitand(GetFileAttributes(@tcFileName),0xFFFFFFF8),lnNewAttr)) = 1)
Endfunc
Çetin Basöz
MS Foxpro MVP, MCP

24 de abril de 2015

Secretos ocultos del IDE de VFP (Parte 2)

Texto original: Hidden Secrets of the VFP IDE, Part 2
https://msdn.microsoft.com/en-us/library/ms947597.aspx
Autor: Cathy Pountney
Traducido por: Ana María Bisbé York


... Continuación de Secretos ocultos del IDE de VFP (Parte 1)

FoxPro ha tenido siempre diferentes vías para hacer lo mismo. Cuántas veces ha mirado sobre el hombro de otro desarrollador y ha dicho, "¡Hey!, ¿Cómo has hecho eso?" En esta serie de artículos, Cathy Pountney va a descubrir muchas formas de trabajar dentro del IDE, especialmente aquellas que no son tan evidentes o no están documentados. Aprenderá varias vías diferentes de mejorar su productividad. Incluso experimentados desarrolladores aprenderán algo nuevo.

Este es el segundo de dos artículos donde estoy exponiendo varios secretos desconocidos del IDE de VFP. En la primera parte, debatí sobre varios diseñadores, algunos controles, la ventana Propiedades, la herramienta Vista del documento y el cuadro de diálogo Buscar. Además descubrí algunos secretos de IntelliSense y varias herramientas y utilidades incluidas con Visual FoxPro. En este artículo, voy a revelar secretos de la ventana Comandos, varios comandos y para finalizar, resumiré un popurrí de secretos ocultos.

Ventana Comandos y comandos

La ventana Comandos es otro lugar en el que pasamos gran parte de nuestro día. Hay varios trucos que se pueden utilizar en la ventana Comandos, y otros secretos menos conocidos sobre algunos comandos de VFP.

Ventana Comandos

Mucha gente ya sabe que puede resaltar una línea de código en la ventana Comandos, hacer clic derecho y seleccionar Ejecutar selección para ejecutar el código resaltado. Pero ¿sabía que puede resaltar varias líneas de código y ejecutarlas de una vez? Sin embargo, debe tener en cuenta que este trabajo puede no tener los resultados esperados. Cuando se ejecutan múltiples líneas de código, se crea un programa temporal y luego se ejecuta. Esto significa que las variables pueden irse de alcance después de que un fragmento del código sea ejecutado. ¡Esto es más un "atrape oculto" que un "secreto oculto"!

Otra cosa que puede hacer con la ventana de comandos es utilizar punto y coma (;), como un carácter de continuación justo como hace en su código. Esto es muy bueno, cuando copia código desde un programa o cuando crea una instrucción SELECT gigante que desea poder ver íntegramente.

_CLIPTEXT

El primer extra es una variable de sistema llamada _CLIPTEXT. Contiene el contenido del portapapeles de VFP. Puede utilizarlo para establecer otra información basada en qué hay en el portapapeles, y puede utilizarla precisamente, para definir qué hay en el portapapeles. Es una variable de dos sentidos que debe aprovechar en tiempo de diseño e incluso en tiempo de ejecución dentro de su aplicación.

Para demostrarlo, resalte una línea de código en la ventana de comandos y presione Ctrl+C para guardarlo en el Portapapeles. Ahora, introduzca ? _CLIPTEXT en la ventana Comandos y verá que la línea de código que ha resaltado está impresa en la pantalla. Otro ejemplo es ejecutar el siguiente código para crear un programa:

_cliptext = '? "FOX ROCKS"' + CHR(13) + CHR(10) + ;
'? "VFP 8 ES FANTÁSTICO"' + CHR(13) + CHR(10)
ERASE JUNK.PRG
MODIFY COMMAND Junk NOWAIT
KEYBOARD '{CTRL+V}'

El código anterior llena el portapapeles con dos líneas de código, crea un archivo de programa, y luego pega el contenido del portapapeles al programa creado recientemente.

_VFP.DataToClip()

El segundo extra que tiene VFP para ayudarnos con funciones de cortar y pegar es la función _VFP.DataToClip(). Esta función toma los datos desde la tabla o cursor y los coloca en el portapapeles. Desde ahí, puede pegarlos en cualquier otro lugar, incluyendo Microsoft Excel. El tercer parámetro define el formato de los datos. Si utiliza un 1 (uno) en el tercer parámetro, el dato utiliza un espacio para separar cada campo. Sin embargo, si utiliza un 3 en la tercera columna, se utilizan tabs para separar cada campo, lo cual es perfecto para insertar en Excel u otra aplicación.

Imprimir el portapapeles

Otra característica poco conocida en VFP es el hecho de que pueda imprimir lo que sea que esté en el portapapeles. Esto es muy bueno cuando quiere imprimir un fragmento de código de su programa; pero no un programa entero. Resalte el texto que desee imprimir y seleccione Archivo – Imprimir en el menú principal de VFP para llamar al cuadro de diálogo Imprimir (puede utilizar Ctrl.+P para invocar este mismo diálogo). Desde el diálogo Imprimir, seleccione el botón Opciones para mostrar el cuadro de diálogo Opciones de impresión. De forma predeterminada el combobox Tipo aparece relleno con el nombre del programa actual. Sin embargo puede desplegarlo y seleccionar Porta papeles, seleccionar Aceptar y luego regresar al cuadro de diálogo Imprimir para finalizar la selección del resto de los parámetros de impresión.

Teclas de la ventana Examinar (BROWSE)

Al utilizar el comando BROWSE, existe un grupo de teclas que pueden ayudarlo a realizar operaciones especiales, como se muestra en la Tabla1.

Combinación de teclas¿Qué hace?
Ctrl+FBusca el siguiente (Find)
Ctrl+GBusca el anterior
Ctrl+YAñade un regitro
Ctrl+TAlterna la bandera de eliminar
Ctrl+HomeEdita un campo memo
Ctrl+WGuarda y cierra
Ctrl+F10Alterna entre maximizar y restaurar

Tabla1. Teclas con el comando BROWSE.

¿Qué hay en un NAME?

La cláusula NAME puede ser muy útil para pasar datos. Los comandos SCATHER, GATHER e INSERT INTO tienen la cláusula NAME. Esto los hace mucho más poderosos que días anteriores cuando hubiera utilizado SCATTER con MEMVAR. Ahora puede utilizar SCATTER con un nombre en NAME, puede pasar el dato a otro objeto como un parámetro. El siguiente código muestra un ejemplo de cómo hacerlo:

*-- Abrir tablas
CLOSE TABLES ALL
USE MyTable1 IN 0
USE MyTable2 IN 0 EXCLUSIVE
ZAP IN MyTable2
*-- Copiar registros desde MyTable1 hasta MyTable2
SELECT MyTable1
GOTO TOP
SCAN
SCATTER NAME oMyTable
AddToTableGather('MyTable2', oMyTable)
AddToTableInsert('MyTable2', oMyTable)
ENDSCAN
SELECT MyTable2
BROWSE
*-- Cerrar tablas
CLOSE TABLES ALL
RETURN
*************************
FUNCTION AddToTableGather
*************************
LPARAMETERS pcTable, poFields
LOCAL lcAlias
lcAlias = ALIAS()
SELECT (pcTable)
poFields.Descr = ALLTRIM(poFields.Descr) + 'G'
APPEND BLANK
GATHER NAME poFields
SELECT (lcAlias)
RETURN
*************************
FUNCTION AddToTableInsert
*************************
LPARAMETERS pcTable, poFields
poFields.Descr = ALLTRIM(poFields.Descr) + 'I'
INSERT INTO (pcTable) FROM NAME poFields
RETURN

Otro buen ejemplo de la utilización de la cláusula NAME es con el comando BROWSE. En la ventana comandos, escriba lo siguiente:

USE MyTable1
BROWSE NAME oBrowse

Ahora, en la ventana Comandos, entre la cadena "oBrowse." (no olvide el punto final) y verá el impacto de IntelliSense en cuanto escriba el punto. Esto es muy bueno, la ventana Examinar es ahora un objeto que puede manipular. Empiece a escoger algunas propiedades como FontBold o RowHeight, desde IntelliSense y puede manipular la ventana examinar precisamente desde la ventana Comandos.

TRANFORM() implícito

En VFP 8, algunos comandos tienen implementado una característica de TRANSFORM() implícito. Esto significa que puede utilizar los tipos de datos que no son de carácter, y el comando los transformará automáticamente por usted. Si el elemento ha sido transformado es un objeto, es utilizado el texto "(Object)".

Intente el siguiente comando y se sorprenderá de que no lanzará un error.

WAIT WINDOW DATE()
MESSAGEBOX(500)
DEBUGOUT DATE()
? _VFP

Popurrí

Existen más secretos ocultos que se desparraman por todo Visual FoxPro.

Truco tramposo

Utilizar la tecla Mayúsculas antes de seleccionar una opción de menú, puede cambiar las opciones de menú. Por ejemplo, presionar Mayúscula y seleccionar el menú Archivos cambia la opción Cerrar por Cerrar todo. Utilizar Mayúsculas desde la ventana de menú cambia, Ocultar por Ocultar todo. Normalmente, la opción Formato – Fuente cambia la fuente en la ventana de Comandos. Sin embargo, utilizar la tecla Mayúsculas con el menú Formato cambia la fuente de la pantalla, por tanto, cambia la fuente de la pantalla de VFP.

Otra característica, que tiene ya cerca de años y años en FoxPro y VFP, es la característica de Fuera de vista (outshow) Presionar Ctrl+Alt+Shift oculta todas las ventanas excepto la de salida. Están ocultas mientras continúe presionando la combinación de teclas. En cuanto las libere, las ventanas ocultas aparecen nuevamente. Esto es extremadamente útil cuando muestra algo desde la ventana de comandos con el carácter signo de interrogación (?) y el resultado final se mostrará detrás del resto de las ventanas.

Copiar una clase

De inicio, parece como si no hubiera una forma de copiar una clase existente en VFP. Puede crear una subclase; pero al parecer no hay forma de copiar una clase. Entonces, utilizará el Administrador de proyectos que puede lograrse bastante fácil con los siguientes pasos:

  1. Arrastre la clase origen desde una biblioteca a otra.
  2. Renombre la clase en la nueva biblioteca.
  3. Arrastre nuevamente la clase renombrada a la biblioteca original.
  4. Elimine la clase de la biblioteca temporal.

Por supuesto, sería agradable si existiera un botón copiar en el menú contextual que se activa con el clic derecho o en algún otro lugar. Pero ¡al diablo!,… no podemos tenerlo todo.

Arrastrar y soltar

En VFP 8, el Administrador de proyectos fue mejorado al permitir adicionar múltiples archivos a la vez. Antes de esta versión, podía añadir solo un archivo cada vez. Sin embargo, puede arrastrar y soltar múltiples archivos, y esta característica ya está hace algún tiempo. Abra el Administrador de proyecto y el Explorador, seleccione algunos archivos en el Explorador y luego arrástrelos al Administrador de proyectos. Una ventaja adicional es que el Administrador de proyectos es suficientemente inteligente como para colocar cada archivo en su ficha correspondiente, en dependencia de la extensión del archivo.

_VFP.SetVar()

Esta función, tan poco conocida, puede ser utilizada para establecer variables en situaciones donde no puede ejecutar un comando; pero puede llamar a una función. Un ejemplo perfecto de cuando utilizarla es el Diseñador de informes. Yo la utilizo todo el tiempo en expresiones Al Entrar (OnEntry) y Al Salir (OnExit) de varias bandas del informe. Por ejemplo, en la expresión Al Salir en el Pie de grupo, puede utilizar _VFP.SetVar('rnRecordCount', 0) para limpiar el valor de la variable rnRecordCount. O, cuando utiliza _VFP.SetVar('rnCountDataGroups', rnCountDataGroups+1) para incrementar una variable que almacena la cantidad de grupos de datos procesados.

Caracteres comodín

Algunos comandos aceptan caracteres comodín, y, a pesar de que es grandioso poder trabajar con ellos, puede ser peligroso. No hay mucho daño en escribir MODI COMM MyProg*. Todo lo que va a hacer es abrir todos los programas que comiencen con MyProg. Sin embargo, el tema de escribir DELETE FILE MyProg*.prg … ¡Peligro!¡Peligro!¡Peligro!... cruzan destellos por mi mente. ¡Sea muy cuidadoso a la hora de utilizar caracteres comodín!

Sólo por diversión

¡Vaya! Tenemos aquí un artículo lleno de información. Hasta ahora, su cerebro está probablemente confundido, por eso, voy a finalizar con algunas cosas divertidas.

Filer

Años atrás, Filer fue lo más utilizado por desarrolladores de Visual FoxPro para Buscar y encontrar archivos. Después de VFP 3.0, desapareció y muchos desarrolladores se quejaron. Bueno, el Equipo de Fox ha escuchado y decidido traerlo de regreso. Escriba lo siguiente en la ventana de Comandos, para ver un ejemplo de cómo ejecutarlo.

DO FORM (HOME(1) + 'Tools\Filer\Filer.scx')

Busque en el archivo de Ayuda de VFP y lea sobre el Nuevo Filer, porque este es orientado a objetos y puede interactuar con el e implementarlo en sus propias aplicaciones. ¡Supongo que podrá llamarlo FilerX!

Puzzle

Esta es otra característica de VFP que nos ha sido devuelta con VFP 8.0. Escriba lo siguiente en la ventana de Comandos. Sin embargo, está advertido… ¡puede disminuir drásticamente su productividad en el trabajo!

ACTIVATE WINDOW PUZZLE

Programas libres de errores

¿Sabe que escribir programas libres de errores, es muy fácil con VFP? Sólo necesita escribir la siguiente línea de código en su programa de inicio, y ya está cubierto.

ON ERROR *

Por supuesto, esto no significa que sus programas están libres de fallas. Significa solamente que no se emitirán mensajes de error por el sistema.

¡Ame su trabajo!

Estoy segura que ama VFP tanto que nunca quisiera dejarlo ir. Muy bien, no hay problemas. Al iniciar VFP, escriba la siguiente línea de código:

ON SHUTDOWN *

No importa, cuánto se esfuerce, no podrá salir de VFP. Esto es genial – ahora puede estar con VFP 24 horas, 7 días de la semana y ¡nunca tendrá que dejarlo! Bien, bien, no es una muy buena idea. Para reparar los daños hay que escribir el siguiente código:

ON SHUTDOWN

¡Trabaje Mejor, no Más!

Este par de artículos están abarrotados de información. Mi objetivo es exponerle tantas características como son posibles y dejarle sus momentos "ah ha". Algunas de ellas pueden que no sean novedosas; pero aquellas que sí le han sido descubiertas, le permitirán ahorrar tiempo en el futuro. Como siempre digo, ¡Trabaje mejor, no más!

Para encontrar más sobre FoxTalk y Publicaciones Pinnacle (Pinnacle Publishing) visite su sitio Web en http://www.pinpub.com

Nota: Este no es un sitio Web de la corporación Microsoft. Microsoft no es responsable por su contenido. Este artículo está reproducido de la edición de este mes de enero de 2004 de FoxTalk, Copyright 2004, por Pinnacle Publishing, Inc., sin alguna otra nota. Todos los derechos reservados. FoxTalk es una publicación independiente de Pinnacle Publishing, Inc. Ninguna parte de este artículo puede ser reproducido (excepto en breves acotaciones utilizadas en revistas y artículos especializados) sin previo consentimiento de Pinnacle Publishing, Inc. Para contactar con Pinnacle Publishing, Inc, favor de llamar al 1-800-788-1900.

23 de abril de 2015

Secretos ocultos del IDE de VFP (Parte 1)

Texto original: Hidden Secrets of the VFP IDE, Part 1
https://msdn.microsoft.com/en-us/library/ms947595.aspx
Autor: Cathy Pountney
Traducido por: Ana María Bisbé York


FoxPro ha tenido siempre diferentes vías para hacer lo mismo. Cuántas veces ha mirado sobre el hombro de otro desarrollador y ha dicho, "¡Hey!, ¿Cómo has hecho eso?" En esta serie de artículos, Cathy Pountney va a descubrir muchas formas de trabajar dentro del IDE, especialmente aquellas que no son tan evidentes o no están documentados. Aprenderá varias vías diferentes de mejorar su productividad. Incluso experimentados desarrolladores aprenderán algo nuevo.

En la parte 1 de esta serie de dos partes, voy a descubrir algunos secretos ocultos en varias áreas de Visual FoxPro. Se comentarán varios diseñadores, unos pocos controles, la ventana Propiedades, la ventana Vista de documento (Document View), el cuadro de diálogo Buscar, Intellisense y un grupo de herramientas y utilidades incluidas con el Visual FoxPro. En la parte 2 se revelarán los secretos de la ventana de comandos y varios comandos, y se resumirán un popurrí de secretos ocultos.

Diseñador de Informes

Por supuesto ya sabe que comenzaré con mi diseñador favorito, ¡El diseñador de informes!

Navegar entre objetos

En VFP 8, puede navegar entre los controles de un informe simplemente utilizando Tab para el control siguiente y Shift+Tab para el control anterior. En versiones previas a VFP8, necesitaba utilizar Ctrl+Tab para obtener primero el modo Tab, y luego poder hacer Tab entre los objetos con las teclas Tab y Ctrl+Tab.

Modificar una etiqueta existente

Para modificar un objeto etiqueta existente en un informe, simplemente seleccione el objeto y luego presione Ctrl+E. Esto activa el modo edición de tal forma que puede cambiar el texto de la etiqueta.

Diseñador de formularios

VFP tiene algunos trucos para trabajar con contenedores.

Llegar a los objetos dentro de los contenedores

Trabajar con los contenedores, tales como el pageframe (marco de página), puede ser difícil a veces. Sin embargo, puede modificar rápidamente el objeto dentro del contenedor utilizando Ctrl+Clic sobre el objeto. Esto "pasa por encima" del contenedor y le permite tomar el control del objeto que está dentro.

Si existen contenedores dentro de otros contenedores, puede utilizar Ctrl+Shift+Clic para profundizar aun más en el nivel. Por ejemplo, si tiene un control optiongroup en una página de un pageframe, puede posicionar su cursor en una la las opciones (optionbuttons), presionar Ctrl+Shift+Clic, y VFP pasa por encima de los controles pageframe, page y optiongroups y va directo al control optionbutton.

Controles ListBox y ComboBox

El carácter "\" tiene especial significado al utilizar listBox y combobox – vea Tabla 1 para más detalles.

CarácterDescripción
\Si se utiliza "\" como primer carácter, el elemento es inhabilitado entero.
\\Debido a que una barra inversa tiene especial significado, si verdaderamente necesita una barra "\" en el elemento, debe colocar dos barras juntas.
\]Debido a que la barra simple al inicio del elemento significa que debe ser inhabilitado, si verdaderamente desea que el elemento comience con barra invertida debe utilizar "\]" para indicar que no debe estar inhabilitado.
\-Una barra inversa seguida por un guión significa que desea dibujar una línea horizontal para este elemento.

Tabla 1. Utilizar el carácter "\" en ListBox y ComboBox

Controles Grid

Los controles Grid han presentado siempre dificultad para trabajar, especialmente para nuevos desarrolladores, debido a que algunas cosas no son muy intuitivas.

Agregar controles

Cuando las columnas son agregadas a las cuadrículas (grid), tienen automáticamente dos controles – un control header (encabezado), llamado header1 y un control textbox llamado Text1. Sin embargo, en muchos casos necesita otro control en lugar del textbox. Desafortunadamente, no es fácil intuir como añadir y eliminar controles de las columnas.

Lo primero que hay que hacer es entrar al grid. Coloque su ratón sobre uno de las líneas de la columna que desea cambiar y presione Ctrl+Clic. Asegúrese de estar en una de las filas de datos y no en la fila del encabezado. Ahora tiene activa la columna y puede utilizar la barra de herramientas de controles del formulario para arrastrar y soltar el objeto que desee en la columna.

Al arrastrar el objeto a la columna, no se aprecia que haya ocurrido nada. Sin embargo, si mira la ventana propiedades y se posiciona en la columna, verá que el objeto original text1 se encuentra junto al que acaba de agregar. La propiedad CurrentControl está establecida aun en el control textbox Text1, por eso es que todavía no ve el control agregado.

Si hubiera cambiado la propiedad CurrentControl de la columna al nombre del objeto que ha agregado, el grid le mostrará el objeto. Sin embargo, si realmente no necesita el textbox text1 original, puede liberarlo y no preocuparse por la propiedad CurrentControl.

Eliminar controles

Si piensa que agregar controles no es intuitivo, estoy segura que se asombrará mucho cuando aprenda cómo eliminar un control indeseado. Es lo más poco intuitivo que hay. Primero, seleccione el control que desee eliminar en la ventana propiedades. Luego, haga clic con el ratón en una fila de datos de su grid y luego presione la tecla Suprimir para eliminar el control. Es posible que no ocurra nada en el grid, si mira en la ventana Propiedades no estará el control.

Navegación

Los grids presentan otro problema para los usuarios finales. Los usuarios están acostumbrados que la tecla Tab los lleve al otro control. Sin embargo, cuando está dentro del grid, Tab mueve el cursor entre las columnas del grid. Entonces, ¿cómo debe hacer el usuario para salir del grid? La respuesta es utilizar Ctrl+Tab para navegar hacia el control posterior al grid o utilizar Ctrl+Shift+Tab para navegar hacia el control anterior al grid.

La ventana propiedades

Existen diferentes teclas de acceso directo para invocar, navegar y establecer valores en la ventana Propiedades (vea la Tabla 2).

Método abreviado Descripción
Alt + Doble ClicDesde el diseñador de formularios, esta combinación active la ventana propiedades aún si no se estaba mostrando.
Clic derecho (Ventana propiedades)Al presionar clic derecho en un área de la ventana Propiedades que está inutilizada muestra un menú con opciones adicionales. La opción Sólo propiedades no predeterminadas mostrará sólo las propiedades con valores no predeterminados.
Clic derecho (propiedades)Al presionar clic derecho en una propiedad cuyo valor es de caracteres muestra un menú con la opción Zoom. Seleccione Zoom para mostrar una ventana de edición grande para ver el valor de la propiedad.
Shift+ Flecha arriba / Flecha abajoPresionar esta combinación cuando se está en una propiedad con múltiples valores permite navegar por todos los posibles valores de la propiedad.
.Cuando está en una propiedad con valor lógico, el punto alterna entre .t. y .f.
Ctrl+ Página arriba/ Página AbajoEsta combinación hace que el cursor vaya al objeto siguiente o previo en la ventana Propiedades.
Ctrl+ Inicio/FinEsta combinación hace que el cursor vaya al objeto primero o posterior en la ventana Propiedades.
Ctrl+Alt+<letra>Presione Ctrl+Alt más alguna letra para saltar a la primera propiedad, método o evento que comienza con esa letra.

Tabla 2. Teclas de acceso directo para invocar, navegar y establecer valores en la ventana Propiedades.

Editor

Muchos de nosotros pasamos mucho tiempo dentro del editor de código de VFP. Después de todo, es lo que hacemos – ¡escribir código! Las siguientes pistas develan algunos de los secretos ocultos del editor.

Vista de documento

La herramienta Vista de documento es una gran herramienta que le permite navegar por el código a través de varios procedimientos y funciones. Pero ¿sabe que no necesita activar la ventana Vista de documento para tomar ventaja de esta característica? En cuanto se abre la ventana de Vista de documento, puede presionar Ctrl+PageUp y Ctrl+PageDown para navegar a través del elemento en la lista. No necesita saltar a la Vista de documentos, navegar por el, y luego saltar al programa.

Mayúsculas y minúsculas

Si es un porfiado sobre las mayúsculas y minúsculas, puede utilizar Ctrl.+U para convertir el texto seleccionado a minúsculas y Ctrl+Shift+U para convertirlo a mayúsculas

Marcadores

Los marcadores son muy buenos cuando trabaja con mucho código. Puede leer a través de algún código y ver referencias de otro método o función. Por supuesto, necesita echar un vistazo a ese código y luego saltar atrás a donde estaba antes, al finalizar. Puede hacerlo más rápido empleando marcadores (bookmarks). Hay que marcar la ubicación existente presionando Alt+Shift+F2. Ahora vaya al otro código que necesita mirar y al finalizar, presione F2 o Shift+F2 para regresar al código anterior. El saltar entre diferentes secciones de código, puede permitirle ahorrar mucho tiempo si marca cada sección con un marcador.

Cuadro de diálogo Buscar

La tabla3 muestra los efectos de utilizar el carácter "\" en el cuadro de diálogo Buscar. Realmente no buscará el carácter de barra inversa, en su lugar, provocará que el diálogo Buscar busque otros caracteres especiales.

CarácterDescripción
\tBusca caracteres Tab
\rBusca el final de cada línea
\nBusca el inicio de cada línea
\\Busca el carácter "\"

Tabla 3. Utilizar el carácter "\" en el diálogo Buscar.

Las búsquedas "\r" y "\n" tienen algunas trampas. Escriba "\r" en el cuadro de diálogo Buscar y presione el botón Buscar siguiente. Al inicio parece como si nada hubiera ocurrido, sin embargo, mantenga presionado el botón Buscar siguiente y verá un cuadro en su código en la primera línea en blanco.

Lo que ocurre es que como Buscar "\r" va al final de cada línea de código; el cursor no se ilumina; pero realmente está situado al final de la línea. Cada vez que presiona Buscar siguiente, va al final de la línea siguiente pero no tiene ninguna pista visual hasta que choca con una línea en blanco. Para demostrar que está trabajando realmente, active el editor y escriba una letra. Verá la letra al final de la línea. Lo mismo es válido cuando se hace una búsqueda por "\n" excepto que el cursor va al inicio de cada línea. Sin embargo, al buscar por "\n" no verá nunca el cursor.

Los caracteres "\\" buscan la primera barra inversa "\" como una salida y luego tratan de buscar la segunda barra como el carácter a ser buscado. Por lo tanto, la búsqueda por "\\" encontrará una sola barra inversa. Sin embargo, esto en realidad no es necesario, porque una barra inversa en el cuadro de diálogo Buscar, encontrará todas las barras inversas.

Cuadro de diálogo Buscar – caracteres comodín

Una de las casillas de verificación del cuadro de diálogo Buscar es Usar caracteres comodín, Seleccionar esta opción le permitirá utilizar caracteres especiales para establecer la coincidencia. Tabla 4 muestra que está disponible.

CarácterCoincidencia con comodín
?Único carácter
*Múltiples caracteres
#Único dígito
<Coincidencia con caracteres al inicio
>Coincidencia con caracteres al final
[ ]Lista de caracteres
[!]Lista de excepciones

Tabla 4. Utilizar caracteres especiales para establecer coincidencia en el cuadro de diálogo Buscar.

Los símbolos "?", "*", y "#" se explican por si solos; pero algunos de los otros elementos necesitan mayor explicación. Buscando por "<Fox" encontrará sólo aquellas palabras que comiencen con "Fox". Si tiene una variable llamada lcFox, no será encontrada, porque no comienza con Fox. En la otra cara de la moneda, "Fox>" encuentra sólo aquellos elementos que terminen con "Fox". Por consiguiente, encontrará la variable lcFox; pero, no encontrará una variable llamada lcFox1, Los caracteres "[" y "]" pueden ser utilizados juntos para encontrar una lista de elementos. Por ejemplo, "lcFox[1-2]" encontrará variables llamadas lcFox1 y lcFox2. Otro ejemplo es "lcFox[1,2,4]", la que va a encontrar lcFox1, lcFox2, y lcFox4. Sin embargo, no encontrará lcFox3.

Utilizar el signo "!" con los corchetes cambia el significado a una lista de excepciones en lugar de la lista de lo que se está buscando. Buscar por "lcFox[!2]" encontrará lcFox1, lcFox3, lcFox4, etc; pro no encontrará lcFox2. De esta misma forma, "lcFox[!2-3]" que encontrará lcFox1 y lcFox4, pero no encontrará lcFox2 y lcFox3.

IntelliSense

IntelliSense se introdujo con el VFP 7, y puedo decir, que merece la pena la actualización, aunque sea sólo por esta característica. Personalmente, no puedo vivir más sin IntelliSense. Si tengo que trabajar en un proyecto de VFP previo a VFP 7, me volvería loca. De hecho, usualmente hago todas mis modificaciones en VFP 7 o VFP 8, y luego utilizo las versiones antiguas sólo para compilarlas.

Operador expansión

Con IntelliSense viene un grupo de características de teclas, así como el operador expansión. ¿Cuántas veces ha escrito lnCount = lnCount + 1? Juro que lo he hecho un millón de veces hasta ahora. Pero, estos días, puedo cortar escribiendo lnCount++, presiono la barra espaciadora, y listo. VFP lo expandirá a lo que yo quiero. La tabla 5 muestra todo del operador expansión disponible.

Esto...Expande a…
cVar++cVar = cVar + 1
cVar--cVar = cVar - 1
cVar+=cVar = cVar +
cVar-=cVar = cVar -
cVar/=cVar = cVar /
cVar*=cVar = cVar *

Tabla 5. Opciones de operador expansión.

Teclas de acceso directo IntelliSense

He visto gran número de desarrolladores comenzar a escribir, aprovechar las ventajas de IntelliSense, y luego, darse cuenta de que han cometido un error. Lo que hacen es comenzar a borrar con la tecla retroceso hasta llegar al punto "." Sin embargo, esto no es necesario. Ctrl+J va a listar los miembros del objeto sin ir hacia atrás hasta el punto. Puede utilizar además Ctrl+J después del signo igual para listar los valores asociados con una propiedad particular, y Ctrl+I puede ser utilizado para mostrar información rápida.

Ponga el siguiente código de ejemplo en un programa y luego posicione el cursor como se instruye y presione el apropiado Ctrl+J o Ctrl+I para ver que funciona.

*-- Intellisense
LOCAL loForm AS Form 
*-- CTRL+J para listar los miembros
*-- (coloque el cursor después del punto)
loForm.
*-- CTRL+J para listar los valores 
*-- (coloca el cursor después del signo igual)
loform.alwaysontop = 
loForm.BorderStyle =
*-- CTRL+I for Quick Info 
*-- (coloca el cursor en uno de los parámetros)
SEEK(cMyValue, cMyTable, cIndex)

Registros predefinidos "U"

IntelliSense es completamente extensible porque todo es guardado en una tabla DBF. Puede ver estas tablas escribiendo USE (_FOXCODE) SHARED en la ventana de comandos. Si se mueve cerca del inicio de esta tabla, verá varios registros con el tipo de "U". El equipo de VFP ha cargado varios ejemplos de cómo puede cortar sus teclas entrando registros de estos tipos. Puede copiar estos registros a nuevos registros y comenzar a agregar sus propios registros para cosas que hace de forma habitual.

La tabla 6 muestra los registros predefinidos "U" en VFP 8. Algunos de estos trabajos en la ventana Comandos y otros trabajos dentro del editor de programas y código de método.

Esto...Expande como …
MFModify File
MCModify Command
DCDefine Class
ZdefMuestra #DEFINEs
ZlocMuestra variables locales
DOCASEDO CASE
CASE
OTHERWISE
ENDCASE
DOWHILEDO WHILE
ENDDO
IFENDIF
ENDIF
IFELSEIF
ELSE
ENDIF
TRYENDTRY
CATCH
FINALLY
ENDTRY
FOREACHFOR EACH
ENDFOR
FORENDFOR
ENDFOR
SCANENDSCAN
ENDSCAN
TEXTENDTEXT TO NOSHOW TEXTMERGE
ENDTEXT
WITHENDWITH
ENDWITH

Tabla 6. Registros predefinidos "U" en VFP 8.

Les animo a crear su propio registro "U" para simplificar su escritura diaria. Así, probablemente no le sorprenda que yo haya agregado a mi tabla _FOXCODE, MR para expandir como MODIFY REPORT. Otro cambio que puedo hacer es cambiar el registro MF para expandir como MODIFY FORM en lugar de MODIFY FILE.

Herramientas de VFP y utilidades

VFP está lleno de herramientas nativas y utilidades para ayudarlo a ser más productivo cada día. Algunas de estas herramientas tienen ya años y años, y otras, son nuevas en VFP 8.0. No escribiré mucho sobre cómo utilizar estas herramientas, porque eso merece un artículo por si mismo. Sólo quiero que sea consciente de estas herramientas para que pueda utilizarlas.

Class Browser (Examinador de clases)

El examinador de clases tiene una pequeña lista MRU - Utilizado más recientemente (Most Recently Used) – a la que puede acceder al hacer clic derecho sobre los botones. Puede ver la lista de Documentos recientes (MRU) desde los botones Abrir, Ver archivo adicional y el botón Galería de componentes.

Utilizar clic derecho con el botón Ver código de clases cambia ligeramente el comportamiento. La ventana de edición que aparece con el código es pequeña y cabe dentro del marco derecho del examinador de clases. De hecho, puede hacer clic en el botón Ver código de clase (View Class Code) para traer el código para una clase, y luego utilizar clic derecho para traer el código de una segunda clase.

Una de las características más útiles y menos conocidas del examinador de clases son sus posibilidades de arrastrar y soltar a un formulario. ¡¡La clase seleccionada es soltada en un formulario!!. Puede además arrastrar el icono de la clase a la ventana de comandos y el código NEWOBJECT es generado por usted.

Depurador

¿Sabe que puede arrastrar y soltar desde dentro del depurador? Puede resaltar una variable en la ventana Seguimiento y luego arrastrarla hasta la ventana Inspección. Esto puede ahorrar tiempo ya que no necesita escribir variables con largos nombres, y reduce las posibilidades de errores de escritura incorrecta. Puede además arrastrar una variable desde las ventanas Inspeccionar o Local a la ventana Comandos o el editor.

Otra fantástica característica del editor es que puede cambiar los valores de variables a voluntad. Una vez que una variable está en la ventana Inspección o Local, puede resaltar su valor (Value) y escribir lo que desee. Esto es muy bueno, si se da cuenta que hay valores mal establecidos y desea continuar la ejecución para ver si el resto va bien. Además de escribir un nuevo valor, puede escribir una expresión para que sea evaluada inmediatamente. Por ejemplo, para una variable de tipo fecha, puede escribir DATE() y en cuanto presione la tecla Return (Intro), el valor de la variable queda establecido en la fecha actual.

Referencias de código – nuevo en VFP 8.0

En mi opinión, esta herramienta no tiene el nombre correcto, ya que es en realidad una fabulosa herramienta de búsqueda – que trabaja más allá que con el código. Esta herramienta permite buscar por un proyecto entero determinada cadena. Puede buscar programas, clases, informes, y todo tipo de archivos en un proyecto. Busca además propiedades y en los códigos de los métodos.

Además de ser una herramienta de búsqueda, es una herramienta que permite sustituir. Puede decirle que sustituya todas las ocurrencias que encuentre o algunas ocurrencias específicas. Esto hace cambios masivos en su aplicación de forma muy simple.

Administrador de paneles (Task Pane) – nuevo en VFP 8.0

El Administrador de paneles es un portal que lleva a diferentes aspectos del Visual FoxPro, incluyendo los ejemplos Solutions y las Comunidades de desarrolladores de Visual FoxPro. Como sucede con muchas herramientas en Visual FoxPro, puede personalizar esta herramienta profundizando en su contenido más interno, llegando al corazón mismo. La personalización puede ser distribuida a otros al exportar e importar archivos XML sencillos. Se espera que más de la tercera parte de los desarrolladores de herramientas y utilidades ofrezcan sus propios add-ins en el Panel de tareas.

ToolBox – Nuevo en Visual FoxPro 8.0

El ToolBox puede considerarse un reemplazo a la barra de herramientas de controles del formulario – pero es mucho más que eso. Puede agregar todas sus clases más comúnmente utilizadas a esta herramienta y esto le hará diseñar con más facilidad sus formularios. Pero puede aprovechar muchas otras ventajas que no son muy conocidas.

Una categoría del ToolBox es Text Scraps (fragmentos de texto). Significa que le permite predefinir un conjunto de texto y luego pegarlo en sus programas y sus códigos de métodos. Además, no está limitado a VFP, puede pegar fragmentos de texto de otras aplicaciones, como por ejemplo Microsoft Word.

Uno de los elementos que puede agregar al ToolBox es un archivo. Sin embargo, puede utilizar esta característica para agregar nuevas cosas que no son realmente archivos. Por ejemplo, agregar un archivo ficticio y luego cambiar las propiedades en una URL. Al seleccionar este elemento desde el ToolBox, el Explorador de Internet (o cualquier otro examinador que tenga establecido) emerge e intenta ir a esa URL. Entonces, si existen algunos sitios Web que visita de forma regular durante el desarrollo de sus aplicaciones, colóquelos en el ToolBox con accesos rápidos.

Otra cosa que puede hacer con la opción File (Archivos), es apuntar hacia un directorio. Primero, tiene que definir un archivo ficticio y luego cambiar sus propiedades para ir al directorio, en lugar de ir a unos archivos. Al seleccionar esta opción desde el ToolBox, el Explorador emergerá con este directorio como predeterminado. Si ve que siempre navega por el mismo directorio, agréguelo al ToolBox y ahorre tiempo.

Foundation Clases

Déle un vistazo al directorio FFC en el directorio raíz de VFP (DIR HOME(1) + 'ffc\*.*') y verá toneladas de clases que han sido definidas. Estas clases fueron creadas por el Grupo de desarrollo de VFP para ayudarlo con sus aplicaciones. Algunas de ellas son justamente subclases de clases base de VFP. Sin embargo, muchas otras son clases, que puede utilizar con sus aplicaciones, como la clase para mostrar un termómetro de progreso.

Ejemplos Solutions

Escriba el siguiente comando en la ventana de comandos y se sorprenderá de lo que ocurre:

DO (HOME(2) + 'solution\solution.app')

Al navegar por la estructura de árbol, verá toneladas de ejemplos de cosas que puede querer en sus aplicaciones. La interfaz de usuario le permitirá ejecutar los ejemplos o ver el código para ver cómo se hace. Es una gran herramienta de aprendizaje, para entender cómo se hacen las cosas en VFP.

HexEdit

Si ha necesitado alguna vez un editor hex para examinar un archivo (hack), sabrá que este programa puede ser un salva-vidas. O si su curiosidad le está volviendo loco, puede utilizar el HexEditor para ojear en un fichero DBF y ver exactamente cómo almacena los datos. ¡Puede ser una gran experiencia instructiva!

Puede encontrarlo en C:\Program Files\Microsoft Visual FoxPro 8\Tools\HexEdit\hexedit.prg.

GenDBC

Cuando se ejecuta este programa, crea todo el código necesario para re-crear su DBC. Puede ser muy útil para crear e instalar una nueva aplicación. No necesita enviar todos lo archivos de datos. En su lugar, está listo para distribuir su aplicación, con sólo ejecutar este programa en su PC y poner el programa creado en su proyecto. Haga que su programa de instalación ejecute el programa generado por el GenDBC, y la nueva instalación se inicializará y ejecutará sin pérdida de tiempo.

Es además, una gran vía para obtener uno o dos archivos copiados en otra DBC y guardar todo sobre el mismo. Ejecute GenDBC en la DBC original. Luego, modifique el programa creado y borre todo menos el código que genera los pocos archivos que desea. Cambie el nombre de la DBC en el programa y re-ejecútelo para agregar estos archivos a diferente DBC.

Puede encontrarlo en C:\Program Files\Microsoft Visual FoxPro 8\Tools\Gendbc\gendbc.prg.

xSource

A veces, la mejor vía para aprender acerca de algo es bucear en el código que hay detrás. Muchas de las herramientas y utilidades de VFP estás actualmente escritas ¡con el propio código de VFP! El código fuente para todas estas herramientas están incluidas en un archivo .zip que se guarda en la carpeta C:\Program Files\Microsoft Visual FoxPro 8\Tools\xsource. Cuando tenga algo de tiempo, descomprima este archivo y comience a bucear en él para ver cómo el equipo Fox ha logrado muchas cosas maravillosas en las herramientas y utilidades nativas de FVP.

"Ah ha"

Siempre disfruto escribiendo sobre "pistas y trucos", como ya he hecho en ese artículo. Incluso experimentados desarrolladores tienen por obligación su momento "ah ha". Existe mucho en FoxPro así que es difícil para una persona saberlo todo. En el próximo artículo de esta serie, voy a hablar de la ventana de comandos, algunos comandos y un conjunto de ideas varias.

Para encontrar más sobre FoxTalk y Publicaciones Pinnacle (Pinnacle Publishing) visite su sitio Web en http://www.pinpub.com

Nota: Este no es un sitio Web de la corporación Microsoft. Microsoft no es responsable por su contenido. Este artículo está reproducido de la edición de este mes de enero de 2004 de FoxTalk, Copyright 2004, por Pinnacle Publishing, Inc., sin alguna otra nota. Todos los derechos reservados. FoxTalk es una publicación independiente de Pinnacle Publishing, Inc. Ninguna parte de este artículo puede ser reproducido (excepto en breves acotaciones utilizadas en revistas y artículos especializados) sin previo consentimiento de Pinnacle Publishing, Inc. Para contactar con Pinnacle Publishing, Inc, favor de llamar al 1-800-788-1900.

Continua en ... Secretos ocultos del IDE de VFP (Parte 2)

20 de abril de 2015

Autogenerar Report Mejorando Presentación (II)

Hace ya tiempo que publiqué un primer articulo con este nombre, que permitía la generación de un informe de forma automática (sin plantilla) tomando como origen un cursor o tabla con los datos a mostrar.

Estaba pensado para aquellas ocasiones en que necesitaríamos realizar un listado sencillo, sin grupos ni totales, pero hasta el punto de diseñar un informe específico.

Sólo era capaz de realizarlo en orientación "Vertical", lo que limitaba la cantidad de información que podía mostrar.

Bien, pues ya lo he conseguido, con el único inconveniente de que su uso queda limitado a VFP9 por las funciones utilizadas.

Espero que os sirva de ayuda.

Este el el código:

[ACTUALIZADO EL 16 DE MARZO DE 2016]

******************************************************************************
* Autogeneracion de un listado (report rapido) partiendo de un cursor o tabla.
* Se autoajusta fuente, tamaño y nº de columnas a mostrar
* Vers: 1.6
******************************************************************************
* Parametros:  cCursor    --> Nombre del cursor/tabla origen
*        cTitulo   --> Titulo para el listado
*        lNoRepite --> (.F./.T.)   No repetir 1er.campo
*        nType     --> Tipo Salida (sólo FoxyPreviewer)
*                              0 -> Vista Previa (default)
*                             10 -> PDF
*                             11 -> PDF como imagen
*                             12 -> RTF
*                             13 -> XLS
*                             14 -> HTML
*                             15 -> HTML Simple
*                             20 -> Automático (por extensión --> cDestino)
*
*        lRetorno  --> (.F./.T.) Devolver nombre del report generado
*                             sin borrarlo, para su uso posterior
*         cDestino  --> Archivo a exportar con extensión (solo TYPE 20):
*                             "PDF","RTF","DOC","XLS","XML","HTM","HTML","MHT",
*                             "BMP","GIF","JPG","JPEG","TIF","TIFF","PNG","EMF"
*        lOrienta  --> (.F./.T.) Forzar orientación horizontal
******************************************************************************
* NOTAS:
*
* Se hacen coincidir los valores de 'nType' con OBJECT TYPE de FoxyPreviewer
*
* Si el nuevo parámetro 'lRetorno'=.T., sólo generará el report, sin mostrarlo,
* y se devuelve el nombre de dicho report. Habrá que borrarlo posteriormente.
******************************************************************************
*
* Ej.  Do autorepo with "micursor", "Titulo del Listado",.F.,15,.F.
*
******************************************************************************
LPARAMETERS cCursor, cTitulo, lNoRepite, nType, lRetorno, cDestino, lOrienta
*
LOCAL cRepo, cFile, nLong, sFont, cFont, cCampos, nMaxCol
LOCAL sExtra, nOrientation, nOriginal, nVersion, CampoUno

cRepo = SYS(2015) + '.frx'

IF VARTYPE(cCursor) # 'C'
  WAIT WINDOW "Faltan Datos"
  RETURN
ENDIF

IF VARTYPE(cTitulo) # 'C'
  cTitulo = cCursor
ENDIF

IF lRetorno = .T.
  nType = 0
  cDestino = ''
ENDIF

IF VARTYPE(nType) # 'N'
  nType = 0
ENDIF

IF VARTYPE(cDestino) # 'C'
  cDestino = ''
  IF nType = 20
    nType = 1
  ENDIF
ELSE
  IF EMPTY(cDestino)
    cDestino = cCursor
  ENDIF
ENDIF

nOrientation = 0
IF lOrienta = .T.
  nOrientation = 1
ENDIF

DO CASE
  CASE INLIST(nType, 10,11)
    cFile = FORCEEXT(cDestino,'pdf')

  CASE nType = 12
    cFile = FORCEEXT(cDestino,'rtf')

  CASE nType = 13
    cFile = FORCEEXT(cDestino,'xls')

  CASE INLIST(nType, 14,15)
    cFile = FORCEEXT(cDestino,'html')

  CASE INLIST(nType, 20)
    IF INLIST(JUSTEXT(cDestino),"PDF","RTF","DOC","XLS","XML","HTM","HTML","MHT","BMP","GIF","JPG","JPEG","TIF","TIFF","PNG","EMF")
      cFile = ALLTRIM(cDestino)
    ELSE
      nType = 1
      cDestino = ''
      cFile = ''
    ENDIF

  OTHERWISE
    nType = 1
    cDestino = ''
    cFile = ''
ENDCASE

cFile =LOWER(cFile)

nVersion = INT(VERSION(5) / 100)

cFont = 'Times New Roman'  && Fuente de letra a usar
*
nMaxCol = 225        && Nº máximo de columnas (depende de fuente)
IF nVersion = 9
  nMaxCol = 315
ENDIF
*
nLong = 0
cCampos = ''
nOriginal = PRTINFO(1)
*
* Establecer anchura, limites y tamaño fuente
nCampos = AFIELDS(aCampos, cCursor)
FOR xx = 1 TO nCampos
  *
  IF xx = 1
    CampoUno = LOWER(ALLTRIM(aCampos(xx,1)))
  ENDIF
  *
  IF nLong  + aCampos(xx, 3) > nMaxCol
    *
    cTitulo = cTitulo + '    ***'
    EXIT
    *
  ELSE
    IF EMPTY(cCampos)
      cCampos = cCampos + aCampos(xx,1)
    ELSE
      cCampos = cCampos + ', ' +aCampos(xx,1)
    ENDIF
    *
    nLong = nLong + aCampos(xx, 3) + 8
    *
  ENDIF
ENDFOR

IF nVersion = 9
  * Establecer orientación necesaria
  IF nOrientation = 0
    IF nLong > 225
      nOrientation = 1
    ELSE
      nMaxCol = 225
    ENDIF
  ENDIF
  * Comprobar y cambiar orientacion si procede
  IF nOriginal <> nOrientation
    CambiarOrientacion(nOrientation)
  ENDIF
ENDIF

*   'sFont' fuente según nº caracteres por linea
*   'sExtra' retroceso vertical para titulos columnas
DO CASE
  CASE nLong > nMaxCol - 35
    sFont = 7
    sExtra = 120

  CASE nLong > nMaxCol - 65
    sFont = 8
    sExtra = 200

  CASE nLong > nMaxCol - 95
    sFont = 9
    sExtra = 360

  OTHERWISE
    sFont = 10
    sExtra = 450

ENDCASE

* Crear report
nReport = 80
IF nVersion = 9
  nReport = SET("ReportBehavior")
  SET Reportbehavior 80
ENDIF
CREATE REPORT (cRepo) FROM DBF(cCursor) FIELDS &cCampos COLUMN WIDTH nLong
IF nVersion = 9
  SET Reportbehavior nReport
ENDIF

* Abrir report como fichero
USE (cRepo) IN 0 ALIAS mirepor EXCL
SELECT mirepor

* Evitar Repetición 1er.campo si así se pidió
IF lNoRepite = .T.
  GOTO TOP
  LOCATE FOR LOWER(ALLTRIM(EXPR)) = CampoUno AND ObjType = 8
  IF !EOF()
    REPLACE Supalways WITH .F.
    REPLACE Supovflow WITH .T.
    REPLACE Suprpcol WITH 3
    REPLACE Supgroup WITH 0
    REPLACE Supvalchng WITH .T.
    REPLACE FontStyle WITH 1
  ENDIF
  GOTO TOP
ENDIF
*
* Cambiar texto 'Page' por 'Página' en caso de runtime en ingles
REPLACE EXPR WITH ["Página "] FOR ALLTRIM(EXPR) = ["Page "] IN mirepor
*
* Cambiar la fuente para todos 'labels' y 'campos'
REPLACE ALL fontface WITH cFont FOR INLIST(ObjType, 1, 5, 8)

* Cambiar tamaño fuente y estilo para 'labels' encabezado columnas
REPLACE ALL FONTSIZE WITH sFont, FontStyle WITH 3 FOR ObjType=5 AND Vpos=0 IN mirepor

* Reducir tamaño fuente para todos 'campos'
REPLACE ALL FONTSIZE WITH MIN(sFont - 1,8)  FOR ObjType = 8

* Cambiar tamaño fuente y estilo para 'labels' y 'campos' del pie de pagina
REPLACE FONTSIZE WITH MAX(sFont - 2,8), FontStyle WITH 3 FOR ALLTRIM(EXPR) = [DATE()] IN mirepor
REPLACE FONTSIZE WITH MAX(sFont - 2,8), FontStyle WITH 3 FOR ALLTRIM(EXPR) = ["Página "] IN mirepor
REPLACE FONTSIZE WITH MAX(sFont - 2,8), FontStyle WITH 3 FOR ALLTRIM(EXPR) = [_PAGENO] IN mirepor

*-------------------------------------------
* Añadir línea separación en pie de pagina
*-------------------------------------------
GOTO TOP
LOCATE FOR ALLTRIM(mirepor.EXPR) = [_PAGENO]
miW = mirepor.hpos + mirepor.WIDTH + 100
miV = mirepor.Vpos - 100
*
APPEND BLANK IN mirepor
REPLACE mirepor.ObjType WITH 7
REPLACE mirepor.objcode WITH 4
REPLACE mirepor.Vpos WITH miV
REPLACE mirepor.WIDTH WITH miW
REPLACE mirepor.HEIGHT WITH 300
REPLACE mirepor.penred WITH -1
REPLACE mirepor.pengreen WITH -1
REPLACE mirepor.penblue WITH -1
REPLACE mirepor.fillred WITH 192
REPLACE mirepor.fillgreen WITH 192
REPLACE mirepor.fillblue WITH 192
REPLACE mirepor.pensize WITH 1
REPLACE mirepor.fillpat WITH 1
REPLACE mirepor.TOP WITH .F.
REPLACE mirepor.Supalways WITH .T.
REPLACE mirepor.offset WITH 16
REPLACE mirepor.Suprpcol WITH 3
REPLACE mirepor.platform WITH 'WINDOWS'

*-------------------------------------------
* Añadir línea separación en encabezado
*-------------------------------------------
GOTO TOP
LOCATE FOR mirepor.ObjType=5 AND mirepor.Vpos=0
*
miV = mirepor.Vpos + mirepor.HEIGHT - 100
*
APPEND BLANK IN mirepor
REPLACE mirepor.ObjType WITH 7
REPLACE mirepor.objcode WITH 4
REPLACE mirepor.Vpos WITH miV
REPLACE mirepor.WIDTH WITH miW
REPLACE mirepor.HEIGHT WITH 300
REPLACE mirepor.penred WITH -1
REPLACE mirepor.pengreen WITH -1
REPLACE mirepor.penblue WITH -1
REPLACE mirepor.fillred WITH 192
REPLACE mirepor.fillgreen WITH 192
REPLACE mirepor.fillblue WITH 192
REPLACE mirepor.pensize WITH 1
REPLACE mirepor.fillpat WITH 1
REPLACE mirepor.TOP WITH .F.
REPLACE mirepor.Supalways WITH .T.
REPLACE mirepor.offset WITH 16
REPLACE mirepor.Suprpcol WITH 3
REPLACE mirepor.platform WITH 'WINDOWS'

*
* Mover todo hacia abajo, para colocar titulo
IF !EMPTY(cTitulo)
  *
  extra = 4000  && Altura para el titulo
  GOTO TOP
  REPLACE ALL Vpos WITH Vpos + extra FOR INLIST(ObjType, 5, 6, 7, 8) IN mirepor
  REPLACE ALL HEIGHT WITH HEIGHT + extra FOR objcode = 1 IN mirepor
  *
  * Añadir Titulo
  APPEND BLANK IN mirepor
  REPLACE mirepor.platform WITH 'WINDOWS'
  REPLACE mirepor.ObjType WITH 5
  REPLACE mirepor.hpos WITH 100
  REPLACE mirepor.fontface WITH cFont
  REPLACE mirepor.FontStyle WITH 4
  REPLACE mirepor.FONTSIZE WITH 16
  REPLACE mirepor.WIDTH WITH 70000
  REPLACE mirepor.HEIGHT WITH 2800
  REPLACE mirepor.Supalways WITH .T.
  REPLACE mirepor.EXPR WITH ["&cTitulo"]
  REPLACE mirepor.mode WITH 1
  *
  REPLACE mirepor.Suprpcol WITH 3
  REPLACE mirepor.penred WITH -1
  REPLACE mirepor.pengreen WITH -1
  REPLACE mirepor.penblue WITH -1
  REPLACE mirepor.fillred WITH -1
  REPLACE mirepor.fillgreen WITH -1
  REPLACE mirepor.fillblue WITH -1

ENDIF

*
* Ajustar 'labels' columnas segun version VFP
REPLACE ALL mirepor.Vpos WITH mirepor.Vpos - sExtra FOR mirepor.ObjType=5 AND mirepor.Vpos = extra
*
DELETE ALL FOR ObjType = 26 IN mirepor
PACK
*
USE IN mirepor

*
* Mandar impresion
*
IF lRetorno = .F.

  IF VARTYPE(_SCREEN.oFoxyPreviewer) = 'O'
    *
    IF nReport = 80
      SET Reportbehavior 90
    ENDIF
    *
    _SCREEN.oFoxyPreviewer.cTitle = 'Vista Previa'
    _SCREEN.oFoxyPreviewer.lExpandFields = .T.
    _SCREEN.oFoxyPreviewer.lPDFEmbedFonts = .T.
    _SCREEN.oFoxyPreviewer.cPDFSymbolFontsList = 'Wingdings 2'
    _SCREEN.oFoxyPreviewer.cPDFDefaultFont = 'Times New Roman'
    _SCREEN.oFoxyPreviewer.cSaveDefName = cTitulo
    *
    SELECT &cCursor
    GOTO TOP
    *
    IF nType < 10
      REPORT FORM (cRepo) OBJECT TYPE nType
    ELSE
      REPORT FORM (cRepo) OBJECT TYPE nType TO FILE &cFile PREVIEW
    ENDIF
    *
    IF nReport = 80
      SET Reportbehavior nReport
    ENDIF
    *
  ELSE
    *
    nType = 0
    *
    oFormObj = ""
    IF _SCREEN.FORMCOUNT > 0
      *
      FOR vv = 1 TO _SCREEN.FORMCOUNT
        IF _SCREEN.FORMS(vv).SHOWWINDOW = 2
          oFormObj = "Window (_Screen.Forms(vv).Name)"
          EXIT
        ENDIF
      ENDFOR
    ENDIF
    *
    oForm = CREATEOBJECT("Form")
    WITH oForm
      *
      .CAPTION = "Vista Previa"
      .WINDOWTYPE = 1

      MOUSE DBLCLICK AT .CURRENTX + 1, .CURRENTY + 5
      *
      SELECT &cCursor
      GOTO TOP
      *
      REPORT FORM (cRepo) TO PRINTER PROMPT NOCONSOLE NOEJECT PREVIEW WINDOW (.NAME)
      *
      .RELEASE()
      *
    ENDWITH
    *
  ENDIF
  *
  * Borrar Report autogenerado
  *
  DELETE FILE (JUSTSTEM(cRepo) + '.frx')
  DELETE FILE (JUSTSTEM(cRepo) + '.frt')
  cRepo = ''
  *
ENDIF

* Comprobar y establecer orientacion original si procede
IF nVersion = 9
  IF nOriginal <> nOrientation
    CambiarOrientacion(nOriginal)
  ENDIF
ENDIF

RETURN cRepo


*************
* Funciones *
*************
FUNCTION CambiarOrientacion
  LPARAMETERS nValor
  LOCAL cValor1, cValor2
  *
  cValor1=[ORIENTATION=0]
  cValor2=[ORIENTATION=1]
  IF nValor = 0
    cValor1=[ORIENTATION=1]
    cValor2=[ORIENTATION=0]
  ENDIF
  *

  CREATE CURSOR mytemp (nulo c(1))
  *
  cRepo2 = SYS(2015)+'.frx'
  * Crear un report temporal para cambiar orientacion
  CREATE REPORT (cRepo2) FROM DBF('mytemp') FIELDS nulo COLUMN WIDTH 256
  *
  *
  USE (cRepo2) IN 0 ALIAS mytempfrx EXCL
  SELECT mytempfrx
  *
  GOTO TOP
  REPLACE mytempfrx.EXPR WITH STRTRAN(mytempfrx.EXPR,cValor1,cValor2)
  *
  SYS(1037,3)
  *
  * Eliminar cursor y reports temporales
  *
  USE IN SELECT('mytempfrx')
  USE IN SELECT('mytemp')
  *
  DELETE FILE (JUSTSTEM(cRepo2) + '.frx')
  DELETE FILE (JUSTSTEM(cRepo2) + '.frt')
  *
ENDFUNC

Un saludo a todos.

Jose Antonio Blasco

16 de abril de 2015

Función GoWeek()

Una función definida por el usuario para sumar o restar semanas a una variable Fecha o Fecha-Hora. Similar a GoMonth(), que sirve para meses.
? GoWeek(DATETIME(), 2)
? GoWeek(DATE(), 3)
? GoWeek(DATETIME(), -3)

FUNCTION GoWeek(tuDate,tnWeeks)
  LOCAL luRet
  IF VARTYPE(tnWeeks) # "N"
    tnWeeks = 0
  ENDIF
  DO CASE
    CASE VARTYPE(tuDate) = "D"
      luRet = tuDate + tnWeeks * 7
    CASE VARTYPE(tuDate) = "T"
      luRet = tuDate + tnWeeks * 7 * 60 * 60 * 24
    CASE NOT VARTYPE(tuDate) $ "TD"
      *-- Error
      luRet = NULL
  ENDCASE
  RETURN luRet
ENDFUNC
Tomado de la función GoDay() publicada aquí.

Luis María Guayán

12 de abril de 2015

Seleccionar uno o mas registros aleatoriamente

Un truco para cuando tenemos que seleccionar registros aleatoriamente con una sentencia SELECT-SQL

Tomemos como ejemplo que deseamos seleccionar aleatoriamente un solo Cliente de la tabla Northwind!Customers, para ello nos ayudaremos con la función RAND() de VFP:

*-- Por primera vez tomo una semilla a partir del reloj del sistema. Ver la ayuda de la función RAND()
RAND(-1)

SELECT TOP 1 *, RAND() AS Rnd ;
 FROM (HOME(2) + "Northwind\Customers") ;
 ORDER BY Rnd

En el caso de que necesitemos seleccionar mas clientes aleatoriamente de la tabla Customers, por ejemplo 5 clientes :

SELECT TOP 5 *, RAND() AS Rnd ;
 FROM (HOME(2) + "Northwind\Customers") ;
 ORDER BY Rnd

Fuente: Respuesta en el foro de http://www.UniversalThread.com

5 de abril de 2015

¿Es una variable o propiedad un array?

Cuando validamos un parámetro en una función o procedimiento, a veces es necesario determinar si el parámetro pasado es una matriz (array). Hasta VFP 9.0 no había una manera evidente de hacerlo.

En VFP 9.0 la función TYPE() acepta un segundo parámetro adicional: 1, para determinar si se la expresión pasada es una matriz, una colección o ninguno de los dos. En versiones anteriores de VFP podemos usar la función TYPE() en combinación con la función ALEN().

Este es el código de ejemplo:

&& VFP 9.0
IF TYPE("AlgunaVariableOrPropiedad",1) = "A"
  && Es un array
ENDIF
 
&& VFP 8.0 y anteriores
IF TYPE("ALEN(AlgunaVariableOrPropiedad)")) = "N"
  && Es un array
ENDIF

Comprobar que TYPE("AlgunaVariableOrPropiedad[1]") = "N" no funciona para propiedades intrínsecas de VFP. Retornando "N" para estas.

loForm = CreateObject ( "Form") 
? TYPE("loForm.Top[1]") && Retorna N

Entrada Original: http://www.berezniker.com/content/pages/visual-foxpro/-varable-or-property-array