28 de mayo de 2015

Formulario con menú con control TreeView

El otro día estaba buscando para hacer un formulario para menú con Treeview, como en varias aplicaciones de gestión. Busqué por varios lados y no lo encontré. Así que hice esto que lo comparto con Uds.


** Creo un Cursor con los datos del Menu,
** puede ser una tabla ya predefinida

CREATE CURSOR cMiMenu (Nivel C(20),Nombre C(50), DoWhat C(90))

** nivel = ####_ (separo con "_" cada 4 digitos
**         para identificar a que nivel pertenece

** nombre = el nombre que quiero asignar a ese nodo en el menu

** dowhath = que comando quiero ejecutar con el dobleclick, lo ideal
**           es que solo los hijos finales tengan algo, pero ...

** se pueden agregar mas campos, como por ej: imagen, parametros, usuarios, etc
INSERT INTO  cMiMenu (Nivel, Nombre, DoWhat) ;
  VALUES ('0001_', 'Padre 1', ' ')
INSERT INTO  cMiMenu (Nivel, Nombre, DoWhat) ;
  VALUES ('0002_', 'Padre 2', ' ')
INSERT INTO  cMiMenu (Nivel, Nombre, DoWhat) ;
  VALUES ('0001_0001_', 'Hijo 1', 'DO FORM \FRM\Hijo1.scx')
INSERT INTO  cMiMenu (Nivel, Nombre, DoWhat) ;
  VALUES ('0002_0001_','Hijo 2',' ')
INSERT INTO  cMiMenu (Nivel, Nombre, DoWhat) ;
  VALUES ('0002_0001_0001_', 'Hijo de Hijo 2', 'DO \PRG\hijo_de_hijo2.prg')


PUBLIC oForm
oForm = NEWOBJECT("Form1")
oForm.SHOW

DEFINE CLASS Form1 AS FORM

  TOP = 10
  LEFT = 100
  HEIGHT = 360
  WIDTH = 360
  DOCREATE = .T.
  CAPTION = "Menu con TreeView y DobleClick"
  NAME = "Form1"
  MINWIDTH = 100
  MINHEIGHT = 100

  ADD OBJECT Olecontrol1 AS OLECONTROL WITH ;
    TOP = 10, LEFT = 10, HEIGHT = 340, WIDTH = 340, ;
    NAME = "Olecontrol1", OLECLASS = "MSComctlLib.TreeCtrl.2"

  PROCEDURE Olecontrol1.DBLCLICK
    SELECT cMiMenu
    LOCATE FOR cMiMenu.Nivel = THIS.SELECTEDITEM.KEY
    IF FOUND()
      IF LEN(ALLTRIM(cMiMenu.DoWhat)) > 1
        WAIT WINDOW + cMiMenu.DoWhat
      ENDIF
    ENDIF
  ENDPROC

  PROCEDURE RESIZE
    THIS.Olecontrol1.WIDTH = THIS.WIDTH - 20
    THIS.Olecontrol1.HEIGHT = THIS.HEIGHT - 20
  ENDPROC

  PROCEDURE Olecontrol1.INIT
    LOCAL lcNivel,lcTexto,lnTipo,lnResta
    THISFORM.Olecontrol1.LineStyle = 1
    THISFORM.Olecontrol1.LabelEdit = 1
    THISFORM.Olecontrol1.FullRowSelect = .T.
    THISFORM.Olecontrol1.HotTracking = .T.
    SELECT cMiMenu
    GO TOP
    DO WHILE !EOF()
      lcNivel = ALLTRIM(cMiMenu.Nivel)
      lcTexto = ALLTRIM(cMiMenu.Nombre)
      IF LEN(ALLTRIM(lcNivel)) = 5
        ** Cuando el valor del LEN() = 5 asumo que es un nodo raiz
        lnTipo = 0
        THISFORM.Olecontrol1.Nodes.ADD(, lnTipo, lcNivel, lcTexto,,)
      ELSE
        ** si LEN() > 5 es un hijo, siempre multiplos de 5
        lnTipo=4
        lnResta = LEN(ALLTRIM(Nivel)) - 5
        lcKey = SUBSTR(ALLTRIM(lcNivel), 1, lnResta)
        THISFORM.Olecontrol1.Nodes.ADD(lcKey, lnTipo, lcNivel, lcTexto,,)
      ENDIF
      SKIP
    ENDDO
  ENDPROC

ENDDEFINE
Ramón González
Misiones, Argentina

24 de mayo de 2015

Métodos abreviados del teclado en VFP

Visual FoxPro permite utilizar métodos abreviados del teclado en las áreas siguientes:
  • Comandos del menú
  • Manipulación de ventanas
  • Ayuda
  • Ventana Propiedades
  • Definiciones de macros predefinidas
  • Examinador de clases
  • Editor
  • Diseñador de informes
  • Ventana Vista preliminar

Comandos del menú

Método abreviado Comando
CTRL+A Seleccionar todo (menú Edición)
CTRL+C Copiar (menú Edición)
CTRL+D Ejecutar (menú Programa)
CTRL+E Eliminar elemento (menú Menú)
CTRL+E Ejecutar (menú Programa)

Ejecutar formulario (menú Formulario)

CTRL+F Buscar (menú Edición)
CTRL+G Buscar siguiente (menú Edición)
CTRL+H Cambiar particiones (menú Tabla)
CTRL+I Insertar elemento (menú Menú)
CTRL+J Información del proyecto (menú Proyecto)
CTRL+L Reemplazar (menú Edición)
CTRL+M Reanudar (menú Programa)
CTRL+N Nuevo (menú Archivo)
CTRL+O Abrir (menú Archivo)
CTRL+P Imprimir (menú Archivo)
CTRL+Q Ejecutar consulta (menú Consulta) Salir (menú Archivo)
CTRL+R Rehacer (menú Edición)
CTRL+S Guardar (menú Archivo)
CTRL+T Alternar marca de eliminación (menú Tabla)
CTRL+V Pegar (menú Edición)
CTRL+W Cierra la ventana de Texto actual o el cuadro de diálogo y guarda los cambios.
CTRL+X Cortar (menú Edición)
CTRL+Y Agregar nuevo registro (menú Tabla)
CTRL+Z Deshacer (menú Edición)

Manipulación de ventanas

Método abreviado Acción
CTRL+F1 Recorre las ventanas
CTRL+F2 Muestra la ventana Comandos
CTRL+F4 Cierra la ventana activa
CTRL+F6 Recorre las ventanas
CTRL+ALT+MAYÚS Oculta todas las ventanas secundarias mientras las teclas están presionadas. Ocultar las ventanas hace más fácil ver la salida que se presenta en la ventana principal de la aplicación.
CTRL+F10 Alterna el tamaño de la ventana entre maximizar y restaurar.

Ayuda

Método abreviado Acción
F1 Muestra el Índice de la Ayuda o Ayuda interactiva sobre elementos activos (por ejemplo, una palabra clave resaltada en la ventana Comandos o la propiedad actual de la ventana de Propiedades).
MAYÚS+F1 Activa la Ayuda interactiva solicitada por el usuario. El puntero de inserción cambia a un signo de interrogación de forma que se puede hacer clic en un elemento (por ejemplo, un comando de menú o una barra de herramientas) para mostrar Ayuda interactiva.

Ventana Propiedades

Método abreviado Acción
CTRL+ALT+letra Selecciona la siguiente propiedad en la lista de propiedades que comienza con el carácter de letra. Por ejemplo, presionar CTRL+ALT+B selecciona la próxima propiedad que comience por B.
CTRL+AV PÁG Se desplaza al siguiente objeto de la lista desplegable Objeto.
CTRL+RE PÁG Se desplaza al objeto anterior de la lista desplegable Objeto.
CTRL+FIN Se desplaza al último objeto de la lista desplegable Objeto.
CTRL+INICIO Se desplaza al primer objeto de la lista desplegable Objeto.
Para etiquetas:
CTRL+E
ESC

Cambia del modo Seleccionar a Modificar
Cambia del modo Modificar a Seleccionar

Definiciones de macros predefinidas

Método abreviado Comando
F2 SET
F3 LIST
F4 DIRECTORY( )(Función)
F5 DISPLAY STRUCTURE
F6 DISPLAY STATUS
F7 DISPLAY MEMORY
F8 DISPLAY
F9 APPEND
Nota: Las definiciones de macro se aplican a la ventana Comandos. Se pueden cambiar las definiciones de macro con el comando Macros del menú Herramientas.

Examinador de clases

Método abreviado Acción
F5 Actualiza la vista actual.
MAYÚS+F10 Muestra un menú contextual.
Clic en el botón secundario+botón Abrir
Clic en el botón secundario+botón Agregar
Clic en el botón secundario+botón Galería de componentes
Muestra el historial de los últimos 32 archivos cargados.
Clic en el botón secundario+botón Ver código de clase Muestra el código de clase en un formulario webview.
Ctrl+clic en el botón secundario + icono Clase
(en la esquina superior izquierda del Examinador de clases)
Crea una instancia de la clase con la función NEWOBJECT( ) en la ventana Comandos.

Es idéntico a arrastrar el icono Clase a la ventana Comandos.

MAYÚS+clic en el botón secundario+icono Clase
(en la esquina superior izquierda del Examinador de clases)
Para formularios, ejecuta el formulario.

Para otros controles y objetos, crea una instancia del control u objeto. Para controles, también agrega el control al escritorio de Visual FoxPro en la posición 0,0.

Es idéntico a arrastrar el icono Clase al escritorio de Visual FoxPro.

Editor

Método abreviado Acción
CTRL+J IntelliSense, activa mostrar miembros
CTRL+I IntelliSense – muestra información
CTRL+J IntelliSense – activa Mostrar valores
F3 Busca la siguiente aparición del texto especificado
MAYÚS+F3 Busca la anterior aparición del texto especificado
CTRL+F3, CTRL+G Busca la siguiente aparición del texto seleccionado
CTRL+MAYÚS+F3 Busca la anterior aparición del texto seleccionado
CTRL+FLECHA ARRIBA Desplaza la ventana hacia abajo sin mover el cursor
CTRL+FLECHA ABAJO Desplaza la ventana hacia arriba sin mover el cursor
CTRL+FLECHA DERECHA Mejora el desplazamiento en el editor
CTRL+FLECHA IZQUIERDA Mejora el desplazamiento en el editor
CTRL+F9 Activa o desactiva un punto de interrupción
F9 Inserta o quita un punto de interrupción
CTRL+B Abre el cuadro de diálogo Puntos de interrupción
F2 Se desplaza a la línea que contiene el siguiente marcador
MAYÚS+F2 Se desplaza a la línea que contiene el marcador anterior
ALT+MAYÚS+F2 Activa o desactiva el marcador para la línea actual
ALT+F2 Agrega o quita el acceso directo a la Lista de tareas
CTRL+MAYÚS+U Convierte la selección a mayúsculas
CTRL+U Convierte la selección a minúsculas
CTRL+RETROCESO Elimina la palabra anterior

Diseñador de informes

En las ventanas de edición de Visual FoxPro, puede utilizar teclas modificadoras para seleccionar cortar y pegar o copiar y pegar al arrastrar:

Método abreviado Acción
CTRL+arrastrar Copia y pega.
ALT+arrastrar Corta y pega.
CTRL+TAB Activa el modo de tabulación en el diseñador, de forma que se puede utilizar la tecla Tabulador para desplazarse de un objeto a otro en el informe.
TAB Utiliza el tabulador para desplazarse al objeto siguiente del Diseñador de informes en modo de tabulación.
MAYÚSCULAS+TAB Utiliza el tabulador para desplazarse al objeto anterior del Diseñador de informes en modo de tabulación.
CTRL+E Cambia el control al modo Modificar cuando se selecciona un control Label en el Diseñador de informes. Utilice la tecla ESC para volver al modo Seleccionar.

En esta versión de Visual FoxPro, puede modificar el comportamiento predeterminado de arrastrar y colocar si hace clic en Arrastrar y colocar entre palabras en la ficha Editor del cuadro de diálogo Opciones del menú Herramientas. Utilice ALT+arrastrar para cambiar al otro valor de configuración (arrastrar en palabras o entre palabras solamente).

Ventana Vista preliminar

Método abreviado Acción
Z Acerca y aleja el zoom.
L Alterna entre varios niveles de zoom.
G Abre el cuadro de diálogo Ir a la página.
ESC Cierra la ventana Vista preliminar.
FLECHA IZQUIERDA Desplaza la ventana Vista preliminar hacia la izquierda.
FLECHA DERECHA Desplaza la ventana Vista preliminar hacia la derecha.
FLECHA ARRIBA Desplaza la ventana Vista preliminar hacia arriba.
FLECHA ABAJO Desplaza la ventana Vista preliminar hacia abajo.
AV PÁG Muestra la ventana Vista preliminar en la página siguiente.
RE PÁG Muestra la ventana Vista preliminar en la página anterior.
INICIO Muestra la ventana Vista preliminar en la primera página.
FIN Muestra la ventana Vista preliminar en la última página.

20 de mayo de 2015

Carpetas Especiales de Windows

Por ejemplo para saber la ubicación de la carpeta Desktop (Escritorio) del usuario actual ejecutamos el siguiente código:

oWsh = CREATEOBJECT("WScript.Shell")
? oWsh.SpecialFolders("Desktop")
oWsh = NULL

Las siguientes carpetas especiales están disponibles:

  • AllUsersDesktop - Escritorio de todos los usuarios
  • AllUsersStartMenu - Menú Inicio de todos los usuarios
  • AllUsersPrograms - Menú Programas de todos los usuarios
  • AllUsersStartup - Programas que se ejecutan automáticamente en el inicio de todos los usuarios
  • AppData - Datos de programa
  • PrintHood - Impresoras
  • Templates - Plantillas específicas del usuario actual
  • Fonts - Fuentes instaladas en el sistema
  • NetHood - Entorno de red
  • Desktop - Escritorio del usuario actual
  • StartMenu - Menú Inicio del usuario actual
  • SendTo - Aplicaciones que se muestran al hacer clic derecho sobre un archivo en el Explorador de Windows
  • Recent - Ducumentos recientes del usuario actual
  • Startup - Programas que se ejecutan automáticamente en el inicio del usuario actual
  • Favorites - Favoritos del usuario actual
  • MyDocuments - Mis Documentos del usuario actual
  • Programs - Menú Programas del usuario actual

Para conocer todas las ubicaciones de las carpetas especiales:

oWsh = CREATEOBJECT("WScript.Shell")
FOR EACH lo IN oWsh.SpecialFolders
  ? lo
ENDFOR
oWsh = NULL

Para mas información sobre Windows Script Host haga clic aquí.

Hasta la próxima,

Luis María

18 de mayo de 2015

Herramientas útiles (al menos, yo creo que lo son)

Artículo original: Useful Utilities (at least, I think they are)
http://weblogs.foxite.com/andykramek/archive/2006/06/18/1883.aspx
Autor: Andy Kramek
Traducido por: Ana María Bisbé York


Como todos los desarrolladores, cualquiera que sea el lenguaje o entorno preferidos, tengo mi conjunto propio de herramientas y utilidades que utilizo y hacen mi vida más sencilla. Aunque no sean especialmente genéricas, o incluso inteligentes, considero que estas pequeñas cosas ayudan realmente y por eso las ofrezco aquí, tal cual, para su disfrute, adopción y modificación.

Lo primero es un pequeño trozo de código que escribí, porque estaba cansado de los errores de escritura en los nombres de las columnas al escribir sentencias SQL - especialmente cuando trabajo con cursores que incluyen columnas calculadas o alias. Esta pequeña rutina llamada GetFList() toma los nombres de los campos de un alias especificado (o del alias actualmente seleccionado si no se especifica nada) y lo coloca en el Portapapeles de Windows. Una vez ahí, la lista puede ser pegada en cualquier ventana con la que tenga que trabajar en ese momento. Sencillo; pero me ha ahorrado muchas horas a lo largo de los años.

********************************************************************
*** Nombre.: GetFList.prg
*** Autor.....: Andy Kramek
*** Fecha.....: 7/7/2004
*** Nota.......: Copyright (c) 2004 Tightline Computers, Inc
*** Función...: Copia la lista de los campos de la tabla actual,
*** o una especificada, en el portapapeles
********************************************************************
LPARAMETERS tcTable
LOCAL lcTable, lcAlias, lcList, lnCnt, lcField, lnSelect
*** ¿Tenemos el nombre de tabla?
lnSelect = SELECT()
IF VARTYPE(tcTable) = "C" AND NOT EMPTY( tcTable )
  lcAlias = JUSTSTEM( tcTable )
  *** Si no está en uso, la abre
  IF NOT USED( lcAlias )
    IF FILE( FORCEEXT( tcTable, 'dbf' ))
      USE (tcTable) AGAIN IN 0 ALIAS (lcALias)
    ELSE
      _CLIPTEXT = ''
      RETURN
    ENDIF
  ENDIF
  *** Y selecciona el Alias
  SELECT (lcAlias)
ELSE
  *** Utiliza cualquiera que esté abierta
  lcAlias = ALIAS()
ENDIF
*** Obtiene la lista de nombres de campos
IF NOT EMPTY( lcAlias )
  lcList = ''
  FOR lnCnt = 1 TO FCOUNT()
    lcField = LOWER( ALLTRIM( FIELD( lnCnt )))
    lcList = lcList + IIF( EMPTY( lcList ), "", ", " ) + lcField
  NEXT
  *** Agrega el nombre de alias
  _CLIPTEXT = lcList + CHR(13) + CHR(10) + "*** " + lcAlias
ENDIF
*** Restablece el área de trabajo
SELECT (lnSelect)
RETURN

La segunda pequeña utilidad es una que llamo, desde las teclas clave (hot-key) en mi entorno de desarrollo, para abrir una instancia del Explorador de Windows en el disco y la carpeta actualmente seleccionada. Confieso que encuentro que es irritante el comportamiento inconsistente de Windows al acceder a ficheros del sistema. Algunas aplicaciones abren una ventana a la última carpeta a la que se ha accedido, otras sencillamente utilizan la estándar ("Mis documentos") o la carpeta estática (C:\ o "Mi PC") y otras hacen algo que tal parece aleatorio. Generalmente, cuando trabajo en VFP, necesito acceder al Explorador de Windows, necesito encontrar un archivo que está en la carpeta actual (por lo general en el directorio raíz o en la jerarquía del proyecto) o en alguna carpeta relacionada de la que conozco, en cualquier caso el nombre (por ejemplo "D:\VFP90\COMMON").

El procedimiento RunExplorer utiliza la función API ShellExecute() para abrir el Explorador de Windows en la ubicación requerida y yo la llamo empleando un comando ON KEY LABEL que está disponible desde mi tecla de función "F5". Acepta un disco/directorio como parámetro; pero el comportamiento predeterminado es utilizar el directorio de trabajo actual de VFP. He aquí el código para esto:

********************************************************************
*** Nombre.....: RUNEXPLORER.PRG
*** Autor.........: Andy Kramek
*** Fecha.........: 25/09/2004
*** Nota...........: Copyright (c) 2004 Tightline Computers, Inc
*** Función.......: Ejecuta el Explorador de Windows con el directorio
***                 especificado. Si no se pasa un valor, el valor
***                 predeterminado es el directorio actual de VFP
*****************************************************************
LPARAMETERS tcDir
LOCAL ARRAY laDex[1]
LOCAL lcDir, lnDex, llIsLoaded, lcParms, lnRes
*** Directorio predeterminado, si no es le pasa otra cosa
IF VARTYPE( tcDir ) # "C" OR EMPTY( tcDir )
  lcDir = FULLPATH( CURDIR())
ELSE
  *** Directorio predeterminado si el especificado no existe
  IF NOT DIRECTORY( tcDir )
    lcDir = FULLPATH(CURDIR())
  ELSE
    lcDir = tcDir
  ENDIF
ENDIF
*** Se asegura de que esté disponible Shellexecute
lnDex = ADLLS( laDex )
IF lnDex > 0
  llIsLoaded = (ASCAN( laDex, 'shellexecute', 2, -1, 2, 15 ) > 0)
ELSE
  llIsLoaded = .F.
ENDIF
IF NOT llIsLoaded
  *** Llama a la función
  DECLARE INTEGER ShellExecute IN shell32;
    INTEGER HWND,;
    STRING lpOperation,;
    STRING lpFile,;
    STRING lpParameters,;
    STRING lpDirectory,;
    INTEGER nShowCmd
ENDIF
*** Abre el Explorador en la localización correcta
lcParms = "/N,,/e," + lcDir
lnRes = ShellExecute( 0, "OPEN", 'explorer.exe', lcParms, "", 1 )
RETURN

Incidentalmente, pueden ser utilizados los mismos parámetros ("/n,,/e," + <ruta>) en accesos directos del escritorio para abrir el Explorador de Windows en ubicaciones más útiles que "Mi PC". Generalmente establezco mis accesos directos para utilizar "D:\" una vez que esta es la raíz para mi disco de aplicación y por tanto el mejor lugar por el que quiero comenzar al utilizar el Explorador de Windows  - pero usted puede seleccionar cualquiera.

La última pequeña utilidad que deseo compartir es una que yo utilizo menos; pero que es igualmente útil. Una de las cosas que yo hago es establecer una ruta específica en VFP (para los detalles, vea mi artículo sobre rutas. Nota de la traductora: El autor se refiere al artículo "The importance of Paths in VFP" - http://weblogs.foxite.com/andykramek/archive/2005/03/21/197.aspx, que se encuentra traducido al español bajo el título "La importancia de las rutas en VFP" y publicado en: http://comunidadvfp.blogspot.com/2003/12/la-importancia-de-las-rutas-en-vfp.html)

Por supuesto, para especificar una ruta, necesita enumerar todas las carpetas. Me fastidia mucho que Windows no tenga un mecanismo que nos permita copiar una lista de nombres - así que escribí GetSubDirs() para crear una lista, separada por punto y coma, de primer nivel de subdirectorios que existen bajo una raíz especificada y lo coloque en el portapapeles. ¿Por qué solamente el primer nivel? Solamente, debido a que mi estructura estándar de directorios no es más profunda y no necesito controlar nada de complejidad adicional. El código puede ser recursivo para controlar niveles adicionales de subdirectorios; pero esto lo dejo como ejercicio al lector ...

********************************************************************
*** Nombre........: GETSUBDIRS.PRG
*** Autor.........: Andy Kramek
*** Fecha.........: 23/09/2004
*** Nota..........: Copyright (c) 2004 Tightline Computers, Inc
*** Función.......: Crea una lista separada por ";" de subdirectorios
***                 y la copia en el Portapapeles
********************************************************************
LPARAMETERS tcRoot
LOCAL ARRAY laDirs[1]
LOCAL lcRoot, lcOrigDir, lnDirs, lnCnt, lcDir, lcList
*** Necesitamos definitivamente una carpeta raíz
IF EMPTY( tcRoot ) OR NOT DIRECTORY( tcRoot )
  lcRoot = GETDIR( CURDIR(), "Must specify a Root DIRECTORY", "GET SubDirs" )
  IF EMPTY(lcRoot)
    lcRoot = FULLPATH( CURDIR())
  ENDIF
ELSE
  lcRoot = FULLPATH( tcRoot )
ENDIF
***Guarda la ubicación actual
lcOrigDir = FULLPATH( CURDIR() )
*** Activa el directorio especificado
SET DEFAULT TO (lcRoot)
*** Obtiene l lista de subdirectorios de primer nivel
lnDirs = ADIR( laDirs, '*.', 'D' )
IF lnDirs = 0
  _CLIPTEXT = ""
  SET DEFAULT TO (lcOrigDir)
  RETURN ""
ENDIF
*** Tenemos al menos un subdirectorio
lcList = ''
FOR lnCnt = 1 TO lnDirs
  *** Ignora las entradas "." y ".."
  lcDir = LOWER( ALLTRIM( CHRTRAN( laDirs[lnCnt, 1], '.', '')))
  IF EMPTY( lcDir )
    LOOP
  ENDIF
  *** Agrega los directorios a la lita
  lcList = lcList + IIF( EMPTY( lcList ), '', ';' ) + lcDir
NEXT
*** Copia los resultados en el portapapeles y devuelve la lista
SET DEFAULT TO (lcOrigDir)
_CLIPTEXT = lcList
RETURN lcList

12 de mayo de 2015

Crear un directorio y los subdirectorios Necesarios

Algunas veces necesitamos crear un árbol de directorio completo, pero a veces existe hasta cierto nivel el árbol, y necesitamos ir viendo si el primer nivel existe, si no existe lo creamos, si no creamos el del siguiente nivel...

Con esta api podemos crear un directorio de un solo, si existe no da error, si no existe lo creara.
Declare long MakeSureDirectoryPathExists in "imagehlp.dll" string lpPath 
?MakeSureDirectoryPathExists("c:/este/es/unarbol/dedirecto/directorio")
?MakeSureDirectoryPathExists("c:/este/es/un/arbol/deprueba/con/hijos1")
Jorge Mota

6 de mayo de 2015

Retornar el nombre de todos los subdirectorios de un directorio

Función recursiva que retorna el nombre de todos los subdirectorios de un directorio pasado como parámetro.

*-----------------------------------------------------------------
* FUNCTION ASubdirectorios(taArray, tcRoot)
*-----------------------------------------------------------------
* Devuelve en un array pasado por referencia todos los nombres de
* subdirectorios del directorio "tcRoot".
* Los nombres son de la forma: [Unidad]:[\Directorio][\Subdirectorio]
* RETORNO: Cantidad de subdirectorios en el array. Si no encontró ningún
*    subdirectorio o el directorio "tcRoot" no existe, retorna 0 (cero)
* EJEMPLO DE USO:
*    DIMENSION laMiArray[1]
*    lnC = ASubdirectorios(@laMiArray, "C:\Mis Documentos\")
*    ? "Cantidad de subdirectorios:", lnC
*    FOR lnI = 1 to lnC
*       ? laMiArray[lnI]
*    ENDFOR
*-----------------------------------------------------------------
FUNCTION ASubdirectorios(taArray, tcRoot)
  IF EMPTY(tcRoot)
    tcRoot = SYS(5) + CURDIR()
  ENDIF
  DIMENSION taArray[1]
  =ARecur(@taArray, tcRoot)
  IF ALEN(taArray) > 1
    DIMENSION taArray[ALEN(taArray) - 1]
    RETURN ALEN(taArray)
  ELSE
    RETURN 0
  ENDIF
ENDFUNC
*-----------------------------------------------------------------
* FUNCTION ARecur(taArray, tcRoot)
*-----------------------------------------------------------------
* Funcion recursiva llamada por ASubdirectorios
*-----------------------------------------------------------------
FUNCTION ARecur(taArray, tcRoot)
  PRIVATE lnI, lnCant, laAux
  tcRoot = ADDBS(tcRoot)
  lnCant = ADIR(laAux, tcRoot + "*.", "D")
  FOR lnI = 1 TO lnCant
    IF "D" $ laAux[lnI, 5]
      IF laAux[lnI, 1] == "." OR laAux[lnI, 1] == ".."
        LOOP
      ELSE
        lcSubDir = tcRoot + laAux[lnI, 1]
        =ARecur(@taArray, lcSubDir)
        taArray[ALEN(taArray)] = ADDBS(tcRoot + laAux[lnI, 1])
        DIMENSION taArray[ALEN(taArray) + 1]
        LOOP
      ENDIF
    ENDIF
  ENDFOR
  RETURN
ENDFUNC
*-----------------------------------------------------------------
Luis María Guayán

1 de mayo de 2015

Curiosidades del SET PATH

Artículo original: SET PATH oddities
http://www.foxpert.com/knowlbits_200705_2.htm
Autor: Christof Wollenhaupt
Traducido por: Ana María Bisbé York


Sin comprobar este código en la ventana de comandos, ¿podría decir usted qué rutas busca Visual FoxPro para cada una de las siguientes instrucciones SET PATH ?

SET PATH TO "111,222",333
SET PATH TO 111;"222,333"
SET PATH TO 111, 222 333

El comando SET PATH es un tanto inconsistente. Sin embargo, se pueden seguir algunas reglas sencillas. Todo lo que se escriba después de TO es tratado como una única cadena. La única excepción es si la cadena comienza con comillas. En este caso, SET PATH solamente lee hasta donde encuentra el cierre de las comillas e ignora el resto de la cadena. El análisis gramatical ocurre estrictamente entre los delimitadores que son: coma o punto y coma.

Con esto en mente, ¿qué carpetas busca VFP para cada variante?:

1) El último directorio es ignorado, porque VFP lee hasta que terminen las comillas que siguen a 222.

.\111
.\222

2) Se analizan por separado 222 y 333. No puede especificar un directorio que tenga una coma en su nombre. Vea que los nombres últimos dos directorios contienen una comilla cada uno lo que genera que la ruta sea no válida.

.\111
.\"222
.\333"

3) Si tiene una ruta con un carácter blanco no necesita utilizar comillas. Visual FoxPro mantiene los espacios en el nombre. Sin embargo elimina los espacios en blanco al inicio y al final de la cadena.

.\111
.\222 333