Visual FoxPro - Compendio de Guias de Clases

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES COMPENDIO DE GUIAS GUIAS DE VISUAL FOXPRO DOCENTE: MA

Views 49 Downloads 0 File size 3MB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES

COMPENDIO DE GUIAS GUIAS DE VISUAL FOXPRO DOCENTE: MAURICIO CANO CANO

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #1 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO REPASO MANEJO BÁSICO DE TABLAS a) La empresa Instituto Metropolitano de Educación, requiere el diseño de una base de datos que le permita almacenar la siguiente información: 1. 2. 3. 4.

Maestro de Programas: programas de estudio Maestro de asignaturas: asignaturas de estudio. Hojas de vida de los estudiantes: información básica de los estudiantes. Información de matrícula: información de matrícula semestral.

Se requiere diseñar la estructura de las 4 tablas tal y como se indica a continuación: 1. Maestro de Programas 2. Maestro de Asignaturas Nombre Campo Tipo de datos Ancho Nombre Campo Tipo de datos Codigo Carácter 2 Codigo Carácter Nombre Carácter 50 Nombre Carácter Programa Carácter Campo clave ascendente: Codigo Campo clave ascendente: Codigo 3. Hojas de vida Nombre Campo Codigo Nombre Apellidos Programa TelResidencia DirResidencia FechaNacimto

Tipo de datos Carácter Carácter Carácter Carácter Carácter Carácter Fecha

Campo clave ascendente: Codigo

Ancho 10 50 50 2 20 40 8

4. Matrícula Nombre Campo Codigo Fecha Nivel Jornada Estado Observación

Tipo de datos Carácter Fecha Carácter Carácter Carácter Memo

Ancho 10 50 2

Ancho 10 8 2 1 1 10

Campo clave ascendente: Codigo

b) Genere los campos claves indicados en cada estructura. c) Introduzca información dentro de cada tabal. Mínimo cinco registros por tabla. Trate de que la información sea ceñida a la realidad. d) Genere los formularios para automatizar procesos con las 4 tablas. e) Genere cuatro consultas. Una para cada tabla. f) Ejecute los comandos de la hoja Resumen de Comandos dados por el docente. Abra manualmente las tablas y ejecute los comandos. Esto con el objetivo de memorizar órdenes que durante las tareas de programación, se hace muy común su uso. Nota: La programación es un arte que se logra mediante la práctica. La memoria juega un papel importante a la hora de escribir código de programas. Una de las ventajas de los nuevos lenguajes Visuales, es el de esconder un poco el código, pero eso no significa que no sea necesario aprender un poco de las órdenes que caracterizan a cada lenguaje. Instituto Metropolitano de Educación – 512 44 40

Visual FoxPro - Guía de clases #1

2

REPASO COMANDOS DEL FOXPRO COMANDOS PARA MANIPULAR TABLAS CREATE USE USE ALIAS

USE MODIFY STRUCTURE CLOSE ALL SELECT

Crear una tabla. Abrir una tabla. Abre una tabla y selecciona el área de trabajo en la cual se desea trabajar. Cierra cualquier tabla abierta en el área de trabajo activa Modificar la estructura de la tabla abierta. Cerrar todos los ficheros abiertos en el sistema FoxPro. Selecciona el área N de trabajo

COMANDOS PARA MANIPULAR REGISTROS APPEND APPEND BLANK SCATTER MEMVAR GATHER MEMVAR DELETE DELETE ALL DELETE ALL FOR

RECALL RECALL ALL RECALL ALL FOR

Agregar registros a la tabla abierta Agregar un registro en blanco a la tabla abierta Llevar el registro activo a un arreglo de memoria Llevar un arreglo de memoria al registro activo Borrar el registro activo Borrar todos los registros de la tabla abierta Borrar todos los registros que cumplan con la condición. Recuperar o retirar la marca de borrado lógica de un registro Recuperar todos los registros con la marca de borrado lógica. Recuperar todos los registros que cumplan con la condición.

COMANDOS PARA MOVERSE ENTRE REGISTROS GO TOP GO BOTTOM SKIP + SKIP -

Ir al primer registro de la tabla abierta Ir al ultimo registro de la tabla abierta. Mueve el puntero de los registros +N posiciones (Avanzar) Mueve el puntero de los registros –N posiciones (Retroceder)

COMANDOS PARA TRABAJAR ÍNDICES COMPUESTOS USE ORDER TAG SET ORDER TO TAG

SET ORDER TO SEEK FOUND() INDEX ON TAG FOR

Abre la tabla indicada y selecciona el como clasificación de los registros, lo indicado por Índice. Selecciona el índice como orden para los registros. Cierra cualquier fichero índice activado para una tabla. Busca un dato en un campo clave. Función utilizada para verificar el éxito de una búsqueda. Genera un fichero índice compuesto basado en el campo clave y utiliza como filtrado de datos la especificada.

Instituto Metropolitano de Educación – 512 44 40

Visual FoxPro - Guía de clases #1

3

CONSULTAS COMPLEMENTO DE LAS CLASES Un programador debe consumir y devorar gran cantidad de documentación. En una clase es imposible darle todas las técnicas disponibles a un estudiante. El estudiante debe poner mucho de su parte y documentarse acerca de los temas vistos en clase. Se plantean las siguientes consultas para que apoyemos como estudiante, una buena labor por parte del docente. •

Investigar los comandos SET



Investigar las funciones SYS()



Que son las áreas de trabajo? Cuales son las ordenes básicas para manipular áreas de trabajo? Como se aplican dentro de la programación de Visual FoxPro?



La Programación orientada a objetos en el Visual Foxpro. Como funciona? Que son las clases? Como se programan las Clases? Que es la clase wizstyle?



Que es el lenguaje SQL? Cuales son las ordenes básicas del lenguaje SQL? Como se aplican dentro del FoxPro?

Instituto Metropolitano de Educación – 512 44 40

Visual FoxPro - Guía de clases #1

4

COMPLEMENTO GUÍA DE CLASES #1 LAS ÁREAS DE TRABAJO Cuando una aplicación requiere más de una tabla para poder funcionar, se hace necesario el trabajar las áreas de trabajo. Aunque es bien sabido, con las recientes versiones del Visual Foxpro y su maravilloso entorno de programación, se hace innecesaria utilizar las órdenes que permiten controlar las áreas de trabajo. El mismo entorno y estilo de programación del Visual Foxpro ocultan el funcionamiento de las áreas de trabajo y dejan todo el control a la opción “entorno de datos”. Sin embargo, es muy útil el conocer los comandos que permiten el manejo de las áreas de trabajo. a. USE / ALIAS Permite abrir una tabla y asignar un alisa o nombre interno para referencias subsecuentes. Muchos diseños de aplicaciones requieren de largos y complejos nombres en las tablas. El asignar un alias resulta útil a la hora de hacer referencia en forma fácil dentro del código de la aplicación. Sintaxis: USE ORDER TAG ALIAS El Id Alias es un nombre corto para hacer referencia a la tabla en órdenes subsecuentes a su ejecución. Si no se utiliza la opción ALIAS, el sistema asignará automáticamente como alias el mismo nombre de la tabla. Ver el ejemplo siguiente para comprender el uso de esta orden. b. SELECT n Activa el área de trabajo indicada por la n. Un área de trabajo es un espacio asignado en memoria para la tabla que se abra inmediatamente después de ejecutada la orden. FoxPro tiene gran capacidad para asignar áreas, así que si la aplicación requiere de muchas tablas simultáneamente abiertas en memoria, no vamos a tener ningún problema. Para designar el área de trabajo podemos utilizar número del 1 hasta donde lleguemos en cantidad de tablas. O podemos utilizar letras para hacer referencias a las áreas, iniciando por la letra A. Existe un identificador especial para nombrar áreas y es el cero (0). Este identificador le indica al FoxPro que utilice el área máxima disponible para áreas de trabajo. Esta referencia es bastante útil para utilizar en rutinas subsecuentes y distantes de la rutina inicial cuando se abrieron todas las tablas requeridas. Una vez se selecciona el área de trabajo y se abre una tabla, para hacer referencia a la tabla, basta con aplicar la orden SELECT acompañada del área programada.

Instituto Metropolitano de Educación – 512 44 40

Visual FoxPro - Guía de clases #1

5

Analicemos el siguiente código: 1

SELECT 1 USE PROGRAMAS ORDER TAG CODIGO ALIAS PROG

2

SELECT 2

Activar el área 1 o A Abrir la tabla programas y utilizar como alias PROG.

Activar el área 2 o B.

USE ASIGNA ORDER TAG Abrir la tabla ASIGNA. El alias automáticamente de esta CODIGO tabla es ASIGNA, el mismo nombre de la tabla. 3

SELECT C USE MATRIC ORDER TAG CODIGO

4

SELECT PROG

5 6

DELE ALL SELECT B LIST SELECT 3 BROWSE

Activar el área 3 o C. Abrir la tabla MATRIC. El alias automáticamente de esta tabla es MATRIC, el mismo nombre de la tabla. Selecciona y activa el área 1. Se utiliza el mismo alias asignado a la tabla. Borra todos los registros de la tabla PROGRAMAS Selecciona y activa el área 2. Lista el contenido de la tabla ASIGNA. Selecciona y activa el área 3. Ejecuta la ventana Examinar en la tabla MATRIC.

Si ejecutamos la orden: SELECT 0 USE PROFESOR ORDER TAG CODIGO ALIAS PROFE Se utilizaría como área de trabajo la 4 o D. Como alias asignado a la tabla, quedaría PROFE. El comando SELECT 0 es muy útil cuando se desea abrir una tabla de forma temporal, para luego volver a la tabla que estaba abierta cuando se invoco. Por ejemplo, la siguiente sección de código, guarda en una variable el área seleccionada, abre una tabla en el área máxima disponible, examinar la información, la cierra y regresa al área inicial de trabajo. mAlias = alias() mFilter = filter() SELECT 0 USE NOTAS ORDER TAG CODIGO BROWSE USE SELECT mAlias SET FILTER TO FILTER Nota: Para cerrar todas las tablas abiertas, puede utilizar CLOSE ALL. Si solo desea cerrar la tabla de un área en especial, utilice la orden USE. Por ejemplo, de acuerdo al código mostrado hace unos momentos, si desea cerrar la tabla ASIGNA ejecute las siguientes ordenes: SELE 2 USE

Instituto Metropolitano de Educación – 512 44 40

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #2 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO EL ACCESO A UNA APLICACIÓN Lo normal en cualquier aplicación, es que una vez se carguen en el computador, nos reciban con una pantalla de acceso, solicitándonos datos de identificación tales como Código de la Compañía, Nombre de Usuario y Contraseña del Usuario. Es por esta razón, que se plantea como primer tema de clases, el diseñar una pantalla que permita controlar el acceso de los usuarios e internamente, enseñarle al sistema en que lugar del computador reside la información. En esta pantalla se maneja internamente variables públicas que se utilizarán en cuanto formulario se diseñe dentro de la aplicación. La variable pública _CodCia incluye el código de la compañía ingresada, _NomCia el nombre de la empresa (usada en los reportes), _DirCia es el directorio de datos de la compañía, _CodUsua es el código del usuario conectado al sistema. En la guía de clases #3 aparece un tip de programación que permite agilizar el diseño de aplicaciones que dependan de variables de configuración tal como las anteriores.

1: mCodigo 2: mUsuario 3: mClave 4: btnAceptar 5: btnCancelar

BtnAceptar.click *verificar información entrada por el usuario select cias _CodCia = alltrim( thisform.mCodigo.value) seek _CodCia if found() *verificar existencia tabla de usuarios mTabla = alltrim( cias.directorio) +"usuarios.dbf" if !file( mtabla) wait window"No existen Usuarios" nowait release thisform cancel endif *abrir tabla de usuarios de la cia entrada sele 2 use &mTabla order tag codigo _CodUsua = alltrim (thisform.mUsuario.value)

seek _CodUsua if found() *verificar clave mclave = alltrim( thisform.mclave.value) if alltrim (usuarios.clave)=mclave *dejar entrar wait window"Puede entrar el Sistema" nowait release thisform else wait window "Clave Incorrecta" nowait endif else *no existe usuario wait window "Usuario no Existe" nowait endif else wait window"Compañia no Existe" nowait endif

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #2

2

Formulario.Init set echo off set talk off set date to mdy *enrutar al directorio base de la aplicación set default to c:\clasefox

BtnCancelar.Click close all release thisform

public _CodCia, _NomCia, _DirCia, _CodUsua _CodCia = space( 2) _NomCia = space( 50) _DirCia = space( 100) _CodUsua = space( 10) *tabla de las compañías select 1 use cias order tag codigo NOTA: La técnica empleada para esta pantalla, es la de diseñar aplicaciones independientes de los datos. Muchos programdores “amarran” sus aplicaciones a las bases de datos. Los sistemas tienden a crecer día a día, puede que inicialmente diseñemos una aplicación con directorio de almacenamiento local (en el mismo disco duro), y cuando menos lo pensamos, se nos hace la petición de que se requiere almacenar las bases de datos en un servidor (algo normal en una empresa). Debemos diseñar aplicaciones que reconozcan el origen de los datos y que internamente en una sencilla operación, se dirijan al sitio de los datos y los utilicen en forma transparente para el usuario. La rutina planteada, permite que el sistema tome la información de instalación de los datos de la tabla de configuración empresa (cias.dbf), capture el campo directorio y se “enrute” hacia ese sitio para leer los datos de los usuarios. Observe que en la parte en donde se permite el acceso al sistema, no existe aún una instrucción que continúe la ejecución normal de la aplicación. Esta será explicado en otra guía de clases. Por el momento lo importante es captar la forma en que se debe diseñar una aplicación inteligente, con capacidad de hallar el origen de sus datos, bien sea que estén en el mismo disco duro, o en otro lugar (servidor o estación) en una red local. RETO DE PROGRAMACIÓN Trate de mejorar esta rutina colocando controles que le permitan al usuario ejecutar solo tres intentos de acceder al sistema.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #2

3

COMPLEMENTO A LA GUÍA #2 LA BÚSQUEDA DE INFORMACIÓN EN TABLAS INDEXADAS La búsqueda de información permite tener mayor control sobre los datos almacenados en las tablas. Para poder buscar información, es importante saber manipular las órdenes de indexados, activación de índices, ordenes de búsqueda y funciones para el chequeo de la efectividad de las búsquedas. FoxPro trae muchas órdenes suficientes para que nuestras aplicaciones tengan control de la información clave de nuestras tablas. •

USE Tabla ORDER TAG NombreTag Abre la tabla indicada y activa como índice el especificado por NombreTag. El éxito de ejecución de esta orden requiere que la tabla haya sido previamente indexada. Por ejemplo, esta instrucción abre la tabla PROGRAMA y activa CODIGO como orden de la tabla. Ahora, podremos listar la información de la tabla clasificada por este campo o podremos ejecutar búsquedas de datos basado en este campo clave. USE PROGRAMA ORDER TAG CODIGO



SET ORDER TO TAG NombreTag Permite activar el campo índice indicado por NombreTag. Por ejemplo, la siguiente orden abre la tabla PROGRAMA en una instrucción aparte, luego ejecuta SET ORDER TO TAG para establecer el campo clave a utilizar para el ordenado de los datos o ejecución de búsquedas: USE PROGRAMA SET ORDER TO TAG CODIGO En este caso, es mejor utilizar una línea para abrir la tabla y simultáneamente asignar el campo de ordenamiento. Esta orden resulta muy útil, cuando se necesita establecer un orden para la tabla, sin necesidad de volverla a abrir. Por ejemplo, abrimos la tabla PROGRAMA e inmediatamente asignamos la clasificación de los datos. USE PROGRAMA ORDER TAG CODIGO Si ejecutamos la siguiente orden, se listaría la información clasificada por el la entrada clave CODIGO. LIST Ahora, activaremos otro campo de ordenamiento y ejecutaremos nuevamente LIST. Esta vez se lista la información clasificada por el campo NOMBRE. SET ORDER TO TAG NOMBRE LIST

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #2 •

4

INDEX ON ExpIndice TAG NombreTag FOR !DELETED() Esta orden permite generar una entrada especial de índice compuesto, clasificando la información por la expresión de índice ExpIndice. EL nombre de la entrada sería el indicado por NombreTag. La cláusula FOR permite establecer un filtro para los datos clasificados. En este caso, se utiliza como filtrado de datos, a todos los registros que no se hallan borrado de la tabla. Acostúmbrese a utilizar esta cláusula en cuanto indexado construya. Esta instrucción le permitirá tener mayor control de los datos existentes en una tabla, y su respectivo manejo a través de los formularios (recuerde que cuando se retira un registro con la orden DELETE este no se borra físicamente -borrado lógico- de la tabla hasta no ejecutar PACK –borrado físico-). Si no utiliza esta cláusula, los informes, y muchas órdenes de recorrido de registros, incluirían a los borrados de las tablas. Por ejemplo, la siguiente instrucción crea una entrada índice denominada CODIGO para la tabla PROGRAMA. Adicionalmente, con la cláusula FOR se filtran todos los borrados de la tabla. En la tercer orden, se crea una entrada clave denominada NOMBRE. USE PROGRAMA INDEX ON CODIGO TAG CODIGO FOR ¡DELETED() INDEX ON NOMBRE TAG NOMBRE FOR !DELETED() Nota: Tenga en cuenta que esta órden crea inicialmente un fichero compuesto con el mismo nombre de la tabla y con la extensión .CDX. Para el ejemplo anterior, si miramos el sitio donde se encuentra almacenada la tabla PROGRAMA.DBF aparece un nuevo archivo denominado PROGRAMA.CDX. Las siguientes entradas índices se agregarán al índice compuesto. Expresiones de índices compuestos Muchas veces una aplicación requiere la construcción de índices compuestos para poder funcionar. Por ejemplo, el detalle de las notas de unos estudiantes, podría ser un claro ejemplo de ello. La tabla de notas (por diseño del software) contiene solo el campo CODIGO del estudiante y el campo CODASIGNA que incluye el código de las asignaturas. USE NOTAS INDEX ON CODIGO +CODASIGNA TAG CODASIGNA FOR ¡DELETED() La clase de Ingeniería de Software le enseñará el momento preciso en que se requieren índices compuestos para una aplicación. Esta clase de índices también se requieren a veces para listar información referente a una misma clave. Por ejemplo, si se tiene la tabla ESTGRUPO para almacenar los estudiantes en los grupos de clase, con un campo de CODGRP para el código de los grupos y otro campo denominado CODEST para guardar el código de los estudiantes, la instrucción para crear el campo clave compuesto es la siguiente: USE ESTGRP INDEX ON CODGRP +CODEST TAG CODEST FOR ¡DELETED() Esta forma especial de definir campos claves involucrando a más de un campo, debe considerarse al momento de ejecutar las búsquedas de información en tales tablas. El sistema FoxPro crea un solo campo clave, donde almacena la expresión resultante para clasificar la información de la tabla.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #2

5

Los campos involucrados en una expresión compuesta deben ser del mismo tipo de datos. Por ejemplo, si CODGRP es carácter, entonces CODEST también debe serlo. Si el diseño de la tabla indica que se deben involucrar campos con diverso tipo de datos, entonces se requiere la aplicación de funciones para la conversión de los datos. Funciones para conversión de datos Las funciones más utilizadas para formar expresiones de campos claves compuestos son las siguientes: STR( ExpresiónNumérica) : convierte la expresión numérica a cadena de caracteres. VAL( ExpresiónC aracter) : convierte la expresión de caracteres a un valor numérico. La expresión aunque sea de tipo carácter, debe tener forma o estructura numérica. DTOC( ExpresiónFecha): convierte la expresión fecha a una cadena o expresión de tipo carácter. CTOD( ExpresiónFecha): convierte una expresión tipo fecha a una cadena de caracteres. Tenga presente que la expresión de clave debe tener el mismo tipo de datos. Para saber que funciones utilizar para armar la expresión, analice los tipos de datos y la estuctura o forma de los campos onvolucrados y aplique las funciones para armar una expesión unificada de datos. Por ejemplo, si analiza los datos de un campo, y detecta uno de tipo carácter y otro de cualquier tipo, la clave es llevarlos a una expresión de tipo carácter. Por ejemplo, si se tiene una tabla de KARDEX y en ella tenemos unos campos CODREF para los códigos de los artículos y otro campo FECHA para almacenar la fecha en que se registro una referencia en el kardex. La forma de definir el índice es el siguiente: USE KARDEX INDEX ON CODREF +DTOC( FECHA) TAG CODFECHA FOR !DELETED() Debido a que el campo CODREF es carácter y FECHA es de tipo fecha, mejor se llevó la conversión a cadena de caracteres. La experiencia le enseñará a aplicar en forma adecuada la conversión de datos y la generación de expresiones para índices compuestos.

BUSCAR INFORMACIÓN EN UNA TABLA INDEXADA Una de las aplicaciones de los índices es la de permitir la búsqueda de información en las tablas. Además, el uso de funciones que permiten analizar si una búsqueda fue exitosa o no. Estas son las órdenes y funciones que permiten manipular búsquedas en campos claves activados (ver la orden SET ORDER TO). •

SEEK Expresión_a_buscar Ejecuta una búsqueda Expresión_a_buscar.

en

el

campo

clave,

utilizando

Instituto Metropolitano de Educación

como

criterio

de

búsqueda

la

Visual FoxPro - Guía de Clases #2

6

La Expresión_a_buscar debe ser del mismo tipo de datos de la expresión clave generada al momento de indexar. Si ocurre lo contrario, FoxPro generará un error de tipos de datos incompatibles. Esta expresión puede ser una variable. Tenga cuidado al definir variables para buscar información, por ejemplo, si define la variables CODIGO y resulta que en su tabla existe un campo llamado CODIGO, el sistema, simplemente no busca nada. Para evitar esto, agregue identificadores a los nombres de las variables para identificarlos de los nombres de los campo, por ejemplo, agregue una m a cuanta variable defina: mCODIGO o simplemente utilice el indicador de variable de memoria (.m) del FoxPro m.codigo. En este ejemplo, se busca el dato almacenado en la variable mCodigo, en el campo clave CODIGO de la tabla PROGRAMA. SELECT PROGRAMA SEEK mCodigo La orden Seek mueve automáticamente el puntero al registro hallado. Lo que significa que después de ejecutada tal orden, basta activar el área de trabajo de la tabla y ejecutar la orden deseada sobre el registro activo. •

FOUND() : Esta función retorna el estado de éxito de la orden buscar recién ejecutada. Retorna .t. si la búsqueda fue exitosa. Retorna .f. en caso contrario. Utilice una estructura de control de flujo para determinar las acciones a tomar acorde al estado de la búsqueda. Si a la secuencia de ordenes anteriores agregamos la siguiente, se obtiene un control de lo que deseamos hacer si se halló algo o no. IF FOUND() WAIT WINDOW “SE HALLÓ ALGO...” NOWAIT ELSE WAIT WINDOW “NO SE HALLÓ NADA...” NOWAIT ENDIF Nota: como caso curioso del FoxPro, muchas veces cuando se coloca algo de por medio entre la orden SEEK y la función FOUND() el sistema muestra resultados inesperados, como si se le olvidase el resultado de la búsqueda inmediatamente ejecutado el chequeo. Acostúmbrese a colocar el chequeo del resultado -IF FOUND()-, inmediatamente después del SEEK.



SEEK( mExpresion_a_buscar, Alias) : Función que permite buscar un registro y retornar si se halló algo o no (más o menos, SEEK más FOUND() combinadas). Esta función resulta útil para utilizar en sitios donde no se puede colocar la orden SEEK más el chequeo con FOUND(), tales como reportes, formularios, etc. Esta función no mueve el puntero al registro hallado, simplemente se limita a afirmar si el dato está o no en la tabla y campo clave seleccionado.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #2 •

7

LOCATE FOR Expresión_de_Condición Ejecuta una búsqueda secuencial, revisando registro a registro. Esta orden se puede utilizar para buscar información en tablas que no están indexadas. Esta orden permite un rango mayor de búsqueda, al permitir establecer la condición de búsqueda. Ejemplo 1: LOCATE FOR APELLIDOS = “CANO” .AND. NOMBRE = “MAURICIO” CONTINUE Este ejemplo, busca la primer ocurrencia de datos de la condición apellidos igual a “CANO” y nombre correspondiente a “MAURICIO”. La instrucción CONTINUE le indica al FoxPro que continúe con la búsqueda recién iniciada. Ejemplo 2: La posibilidad de aceptar condiciones como parámetro de búsqueda, convierte a esta sencilla instrucción en potente comando de programación, que bien utilizado, puede salvarnos el día. LOCATE FOR “MAURICIO” $ NOMBRE CONTINUE En este ejemplo, se buscarán todos los nombres iguales a “MAURICIO”. Comentarios La tabla no necesita estar indexada. Si LOCATE encuentra un registro coincidente, podrá utilizar RECNO( ) para devolver el número del registro coincidente. Si se encuentra un registro coincidente, FOUND( ) devolverá verdadero (.T.) y EOF( ) devolverá falso (.F.). Después de que LOCATE encuentre un registro coincidente, puede emitir CONTINUE para buscar registros coincidentes adicionales en el resto de la tabla. Cuando se ejecuta CONTINUE, se reanuda el proceso de búsqueda, empezando por el registro que sigue inmediatamente al registro coincidente. Puede emitir CONTINUE repetidamente hasta llegar al final del alcance o de la tabla. Si no se encuentra ninguna coincidencia, RECNO( ) devolverá el número de registros de la tabla más uno, FOUND( ) devolverá falso (.F.) y EOF( ) devolverá verdadero (.T.). LOCATE y CONTINUE son específicos del área de trabajo actual. Si se selecciona otro área de trabajo, el proceso de búsqueda original podrá continuarse cuando se vuelva a seleccionar el área de trabajo original.

Instituto Metropolitano de Educación

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #3 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO Las técnicas de programación varían de un programador a otro. Cada programador asume la técnica que desee para desarrollar sus aplicaciones. Sea cual sea la técnica empleada, lo más importante es que sea funcional. Se propone la siguiente técnica de programación diseñada por nuestra dependencia, muy útil para el trabajo en línea. Permitiendo mayor velocidad al entrar, buscar , retirar y consultar datos. Cada grupo de estudio deberá elaborar los diseños de las otras tablas diseñadas y propuestas por la guía de clases #1. Cada grupo deberá experimentar con el método de trabajo propuesto y hallar las posibles fallas técnicas de diseño (algo normal en grandes aplicaciones).

1: mCodigo 5: btnPrimero 9: btnAgregar 13: btnExaminar

2: btnCargar 6: btnAnterior 10: btnActual 14: btnCerrar

3: btnLimpiar 7: btnSiguiente 11: btnRetirar

4: mNombre 8: btnUltimo 12: btnReporte

BtnPrimero.click

BtnAnterior.Click

*ir al primero wait window "Primer registro..." nowait sele 1 go top scatter memvar memo thisform.refresh return

*ir al anterior sele 1 if !bof() skip -1 endif if bof() go top endif scatter memvar memo thisform.refresh return

BtnSiguiente.Click

BtnUltimo.Click

*ir al siguiente sele 1 if !eof() skip 1 endif if eof() go bottom endif scatter memvar memo thisform.refresh return

*ir al ultimo wait window "Último registro..." nowait sele 1 go bottom scatter memvar memo thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #3

2

BtnAgregar.Click

BtnActual.Click

*agregar registro con los datos en pantalla sele 1

*actualizar el contenido de un campo

*verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif if empty( thisform.mNombre.value) wait window "Nombre incorrecto..." nowait thisform.mNombre.setfocus return endif *verificar campo clave mCodigo = alltrim( thisform.mCodigo.value) sele 1 seek mCodigo if found() mMens1 = "Imposible agregar, el código " +mCodigo +" ya existe!" +chr(13) mMens2 = "Utilice otro código e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif *agregar nuevo registro con los datos en pantalla sele 1 insert into programa from memvar

*verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif if empty( thisform.mNombre.value) wait window "Nombre incorrecto..." nowait thisform.mNombre.setfocus return endif *actualizar datos del campo clave sele 1 mCodigo = alltrim( thisform.mCodigo.value) seek mCodigo if found() && actualizar registro hallado gather memvar memo wait window "Datos actualizados..." nowait else mMens1 = "Imposible actualizar, el código " +mCodigo +" no existe!" +chr(13) mMens2 = "Utilice otro código e intente actualizar de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif return

*cargar nuevos datos en blanco scatter memvar blank *ir al primer campo thisform.mCodigo.setfocus thisform.refresh

BtnExaminar.Click

BtnLimpiar.Click

*examinar registros sele 1 browse fields codigo, nombre noedit noappend nodelete *activar el seleccionado scatter memvar memo

*limpiar el contenido de los campos wait window "Datos en blanco..." nowait scatter memvar memo blank thisform.refresh

thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #3

3

BtnRetirar.Click *retirar el registro clave hallado sele 1 mCodigo = alltrim( thisform.mCodigo.value) seek mCodigo if !found() && no existe codigo mMens1 = "Imposible retirar, el código " +mCodigo +" no existe!" +chr(13) mMens2 = "Utilice otro código e intente retirar de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif mMens1 = "Desea retirar el código " + mCodigo +" del sistema!" +chr(13) mOpc = messagebox( mMens1 , 1+32, "Retirar registro!") if mOpc = 1 && Clic en botón Aceptar sele 1 delete wait window "Registro retirado del sistema..." nowait *mover puntero al próximo disponible if !eof() skip 1 endif if eof() go bottom endif

BtnCargar.Click *cargar el contenido de los campos con la clave entrada *verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif *cargar datos del campo clave sele 1 mCodigo = alltrim( thisform.mCodigo.value) seek mCodigo if found() && actualizar registro hallado scatter memvar memo wait window "Datos cargados..." nowait else mMens1 = "Imposible cargar datos, el código " +mCodigo +" no existe!" +chr(13) mMens2 = "Utilice otro código e intente cargar datos de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") endif thisform.refresh thisform.mCodigo.setfocus return

endif scatter memvar memo thisform.refresh

return BtnCerrar.Click

Form.Init *abrir entorno utilizando las variables públicas

thisform.release mFile1 = _dircia +"programa.dbf" if !file( mFile1) do cPrograma in prg\creartbl endif sele 1 use &mFile1 order tag codigo alias programa scatter memvar memo *ir al objeto inicial thisform.mCodigo.setfocus return Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #3

4

Rutinas adicionales para que este diseño funcione: Se requiere una rutina que defina las tablas en forma automática. Esta rutina dará un grado de inteligencia al sistema, al permitirle definir las tablas que no existan, en forma automática. Un sistema que incluya tal funcionalidad, simplemente, nunca fallará por falta de datos. CREATBL.PRG Esta rutina debe crearse en el generador del proyecto en Codigo/Programas. Defina la carpeta prg para almacenar las rutinas que definamos dentro de la carpeta del proyecto. *creatbl.prg * Definir las tablas del sistema * invocar: do cPrograma in prg\creatbl procedure cPrograma *chequear y definir tabla de asignaturas *definir una cadena de tal forma "c:\clasefox\01\programa.dbf" mTabla = _dircia + "programa.dbf" if !file( mTabla) create table &mTabla ; ( codigo c ( 10), ; nombre c ( 50)) index on codigo tag codigo for !deleted() index on nombre tag nombre for !deleted() close data wait window "Tabla "+mTabla +" definida..." nowait endif return && cPrograma * creatbl.prg TIP DE PROGRAMACIÓN Es muy útil el definir una rutina independiente denominada public con todas las variables públicas a utilizar durante el diseño del sistema. Con esto nos ahorramos tiempo al no tener que hacer todo el recorrido de la aplicación para verificar el funcionamiento de una aplicación. *public.prg * utilizar solo durante diseño de programas * los datos en este programa deben ser inicializados por * la pantalla de entrada al sistema public _codcia, _nomcia, _dircia, _codusua _codcia = "01" _nomcia = "COLEGIO 01" _dircia = "c:\clasefox\01\" _codusua = "01" * public.prg Instituto Metropolitano de Educación

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #4 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO Continuando con la técnica #1, ha llegado el momento de demostrar las habilidades que como programadores, hemos desarrollado hasta el momento. Gran parte del arte de la programación, se adquiere imitando modelos hechos por otros programadores. Si como programadores, desarrollamos rutinas que pueden ser perfectamente reutilizables en otras partes de la aplicación, lo normal es tomar el modelo base y copiarlo tantas veces lo necesitemos. Más adelante aprenderemos que cuando se requiere hacer esto muy a menudo, lo más práctico es definir una clase y basar todas nuestras pantallas en ella. EL FORMULARIO PARA EL MAESTRO DE ASIGNATURAS Para la elaboración del siguiente formulario abra el formulario de la guía #3 y grábelo (Menú Archivo/Salvar Como) con otro nombre (frmasigna) en la carpeta donde residen los formularios (c:\clasefox\documentos). Recuerde agregarlo al proyecto en la ventana donde aparecen listados los formularios (Ventana proyecto, clic en botón Agregar). Lo primero que haremos ahora, es abrir el formulario recién agregado, abrirlo en la ventana de diseño y modificar el Caption del formulario, para que diga “Maestro de Asignaturas”. Esto es importante, ya que el tener correctamente identificadas las pantallas, nos puede llegar a ayudar a ubicarnos rápidamente en la pantalla de trabajo, y evitar posibles dolores de cabeza al sobrescribir código de pantallas ya terminadas. Reorganice la pantalla original de programas (la recién copiada) para que incluya el campo programa de la tabla ASIGNA.DBF.

1: mPrograma

2: btnAgregar

3: btnActual

4: btnExaminar

Todos los controles continúan con los mismos nombres. El nuevo obje to de campo es el referenciado con el numeral 1 (mPrograma). Los objetos que aparecen referenciados con números (del 1 al 4) indican que el código del evento clic presenta variaciones. Los demás objetos, continúan con el mismo código programado en la lección anterior. Ahora lo que debemos hacer, es personalizar el formulario para que apunte a la tabla en cuestión, en nuestro caso, Asigna.dbf. Debe alterar el código del evento INIT del formulario, y modificar el código para que diseñe automáticamente la tabla Asigna y abra simultáneamente la tabla de programa (utilizando áreas de trabajo).

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #4 BtnAgregar.Clic

2 BtnActual.Click

*agregar registro con los datos en pantalla sele 1

*actualizar el contenido de un campo

*verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif if empty( thisform.mNombre.value) wait window "Nombre incorrecto..." nowait thisform.mNombre.setfocus return endif if empty( thisform.mPrograma.value) wait window "Programaincorrecto..." nowait thisform.mPrograma.setfocus return endif *verificar campo clave mCodigo = alltrim( thisform.mCodigo.value) sele 1 seek mCodigo if found() mMens1 = "Imposible agregar, el código " +mCodigo +" ya existe!" +chr(13) mMens2 = "Utilice otro código e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif *validar el programa entrado por el usuario mPrograma = alltrim( thisform.mPrograma.value) sele programa seek mPrograma if !found() mMens1 = "El código de Programa " +mPrograma +" no existe!" +chr(13) mMens2 = "Utilice un código válido e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mPrograma.setfocus return endif *agregar nuevo registro con los datos en pantalla sele 1 insert into asigna from memvar

*verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif if empty( thisform.mNombre.value) wait window "Nombre incorrecto..." nowait thisform.mNombre.setfocus return endif if empty( thisform.mPrograma.value) wait window "Programaincorrecto..." nowait thisform.mPrograma.setfocus return endif *validar el programa entrado por el usuario mPrograma = alltrim( thisform.mPrograma.value) sele programa seek mPrograma if !found() mMens1 = "El código de Programa " +mPrograma +" no existe!" +chr(13) mMens2 = "Utilice un código válido e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mPrograma.setfocus return endif *actualizar datos del campo clave sele 1 mCodigo = alltrim( thisform.mCodigo.value) seek mCodigo if found() && actualizar registro hallado gather memvar memo wait window "Datos actualizados..." nowait else mMens1 = "Imposible actualizar, el código " +mCodigo +" no existe!" +chr(13) mMens2 = "Utilice otro código e intente actualizar de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif sele 1

*cargar nuevos datos en blanco scatter memvar blank

return

*ir al primer campo thisform.mCodigo.setfocus thisform.refresh

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #4 BtnExaminar.Click

3

*examinar registros sele 1 browse fields codigo, nombre, programa noedit noappend nodelete *activar el seleccionado scatter memvar memo thisform.refresh return

Form.Init *abrir entorno utilizando las variables públicas *tabla mae stro asignaturas mFile1 = _dircia +"asigna.dbf" if !file( mFile1) do cAsigna in prg \creatbl endif sele 1 use &mFile1 order tag codigo alias asigna *tabla maestro programas mFile2 = _dircia +"programa.dbf" if !file( mFile2) do cPrograma in prg\creatbl endif sele 2 use &mFile2 order tag codigo alias programa sele 1 scatter memvar memo *ir al objeto inicial thisform.mCodigo.setfocus return

Observe que las modificaciones hechas al código, aparecen resaltadas en Negrita. Analice que cambios se hicieron al código elaborado en la guía #3 y analice el efecto que esas nuevas instrucciones tienen sobre el formulario. Nota: Para que cada formulario se ejecute independiente de los demás, ajuste la propiedad DataSession del formulario a 2-Sesion Privada de Datos. Esto le indicará al FoxPro que maneje el entorno de datos de cada formulario en porciones diferentes de la memoria. Si no se hace esto (1-Sesión predeterminada de datos), se generarían innumerables errores de “El archivo ya está en uso” cada vez que se ejecute un formulario, inmediatamente después de haber ejecutado otro. Esta configuración especial le permitirá al usuario abrir varias instancias de un mismo formulario, tantas veces como la memoria se lo permita (existe en la documentación del FoxPro sobre la programación utilizando instancias de formularios).

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #4

4

Rutinas adicionales para que este diseño funcione: Se requiere modificar la rutina que define las tablas en forma automática. Se debe agregar una nueva subrutina que permita definir la tabla Asigna.dbf. CREATBL.PRG Agregue este segmento de código a la rutina CREATBL.PRG procedure cAsigna *definir tabla de asignaturas mFile = "c:\clasefox\01\asigna.dbf" create table &mFile ; ( codigo c ( 10), ; nombre c ( 50), ; programa c ( 2)) index on codigo tag codigo for !deleted() index on nombre tag nombre for !deleted() close data return && cAsigna

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #4

5

RETO DE PROGRAMACIÓN Agregue al formulario un control de cuadro combiando que le permita al usuario el seleccionar de una lista de programas un código. Esto agilizará y ayudará al usuario a no tener que memorizar los códigos de los programas.

Para obtener una pantalla como la anterior, haga el siguiente proceso: 1. Elimine el objeto mPrograma del formulario Asigna. 2. Agregue un control de Cuadro Combinado de la barra de herramientas del formulario. Seleccione la herramienta Cuadro Combinado y demarque el área en el lugar donde estaba el objeto mPrograma. No exagere con el tamaño del nuevo objeto. Haga un diseño proporcional acorde a la cantidad de información a mostrar.

3. Modifique las siguientes propiedades del objeto recién agregado al formulario: • Name: mPrograma • ControlSource: m.programa • RowSource: programa.codigo, nombre • RowSourceType: 2-Alias • ColumnWidths: 40,200 4. Si hizo todo el trabajo bien hecho, al ejecutar el formulario, verá una forma muy efectiva de trabajo, al permitir que el usuario seleccione los datos de las tablas relacionadas con las tablas maestras. Esto descarga al usuario, la obligación de tener que aprenderse una serie de códigos para introducir en los formularios.

Instituto Metropolitano de Educación

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #5 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO

TÉCNICA DE PROGRAMACIÓN #2 – DISEÑO TIPO FOXPRO La técnica de programación tipo Visual FoxPro es un diseño propuesto desde hace mucho tiempo por los fabricantes del producto en los ejemplos y ayudas del producto. Los programadores desde entonces vienen imitando ese modelo de programación, que para el viejo sistema DOS y Windows 3.1. era bastante funcional. Muchos gerentes de sistemas prefieren que sus programadores diseñen de tal forma por ser un tipo de programación que controla bastante a las acciones del usuario. Esta técnica consiste en tener botones para indicarle a la aplicación cuando se desea Agregar, Modificar y Retirar registros. También posee unos botones para indicar si deseamos Guardar o Deshacer los cambios. Lo interesante de esta técnica radica en la forma en que activan y se activan elementos en la pantalla. Esto brinda un mayor control de las acciones de los usuarios, al bloquear los campos de datos y aquellos objetos que se desean. El activar y desactivar elementos va reduciendo el modo de operación del usuario, limitándolo a aquello que solo deseamos que el usuario manipule en un momento determinado. Recuerde que ahora que estamos en la etapa de principiantes, nos dedicaremos a construir cada pantalla sin los asistentes. Cuando tengamos los elementos básicos de la programación orientada a objetos aprenderemos a jugar con la clase Wystile para personalizar las pantallas de un proyecto. EL FORMULARIO PARA EL MAESTRO DE ASIGNATURAS Para esta pantalla, inicie un formulario en blanco y agregue los siguientes elementos:

1: mAgregar

2: btnModificar

3: btnRetirar

4: btnGuardar

5: btnDeshacer

Respecto a la técnica número 1, se han hecho cambios importantes en el funcionamiento de los botones Agregar y Retirar. Se han agregado los tres botones de Modificar, Guardar y Deshacer. Para esta técnica, el usuario se ve obligado a utilizar los botones de agregar o modificar para actualizar los datos. Cuando haga clic en el botón Agregar, el sistema debe habilitar los campos de datos y botones Guardar o Deshacer. El resto de los botones, debe deshabilitarse durante los procesos de agregar o modificar los datos. Para empezar, coloque la propiedad Enabled igual a .F. Falso para los botones btnGuardar, btnDeshacer y los campos de datos (mCodigo y mNombre).

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #5

2

Evento INIT del Formulario

BtnAgregar.click

*variables públicas public pAgregando, pEditando

*indicador (flag) de proceso para agregar datos pAgregando = .t. pEditando = .f.

*abrir entorno utilizando las variables públicas *cargar nuevos datos en blanco sele 1 scatter memvar blank

close data mFile1 = _dircia +"programa.dbf" if !file( mFile1) do cPrograma in prg\creartbl endif

*activar campos de datos thisform.mCodigo.enabled = .t. thisform.mNombre.enabled = .t.

sele 1 use &mFile1 order tag codigo alias programa scatter memvar memo *ir al objeto inicial thisform.btnCerrar.setfocus return

*desactivar botones innecesarios en el proceso *de agregar thisform.btnPrimero.enabled = .f. thisform.btnAnterior.enabled = .f. thisform.btnSiguiente.enabled = .f. thisform.btnUltimo.enabled = .f. thisform.btnAgregar.enabled = .f. thisform.btnModificar.enabled = .f. thisform.btnRetirar.enabled = .f. thisform.btnReporte.enabled = .f. thisform.btnExaminar.enabled = .f. thisform.btnCerrar.enabled = .f. *activar botones salvar y deshacer thisform.btnGuardar.enabled = .t. thisform.btnDeshacer.enabled = .t. *ir al primer campo thisform.mCodigo.setfocus thisform.refresh

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #5

3

BtnModificar.Clic *indicador (flag) de proceso para agregar datos pEditando = .t. pAgregando = .f. *cargar datos en memoria sele 1 scatter memvar memo *el campo clave debe permanecer inactivo thisform.mCodigo.enabled = .f. *activar el resto de los campos thisform.mNombre.enabled = .t. *desactivar botones innecesarios en el proceso *de agregar thisform.btnPrimero.enabled = .f. thisform.btnAnterior.enabled = .f. thisform.btnSiguiente.enabled = .f. thisform.btnUltimo.enabled = .f. thisform.btnAgregar.enabled = .f. thisform.btnModificar.enabled = .f. thisform.btnRetirar.enabled = .f. thisform.btnReporte.enabled = .f. thisform.btnExaminar.enabled = .f. thisform.btnCerrar.enabled = .f. *activar botones salvar y deshacer thisform.btnGuardar.enabled = .t. thisform.btnDeshacer.enabled = .t. *ir al siguiente campo disponible después *del campo clave thisform.mNombre.setfocus thisform.refresh

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #5

4

BtnRetirar.Clic *retirar el registro activo mCodigo = alltrim( thisform.mCodigo.value) mMens1 = "Desea retirar el código " + mCodigo +" del sistema!" +chr(13) mOpc = messagebox( mMens1 , 1+32, "Retirar registro!") if mOpc = 1 && Clic en botón Aceptar sele 1 delete wait window "Registro retirado del sistema..." nowait *mover puntero al próximo disponible if !eof() skip 1 endif if eof() go bottom endif endif scatter memvar memo thisform.refresh return Al igual que en las rutinas anteriores, se requiere ejecutar la rutina Public.prg para programar el acceso a los datos del sistema y la rutina creadora de la tabla de los programas académicos CREATBL.PRG y la rutina (procedure) cPrograma . Ver las guías anteriores para mayor información.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #5

5

BtnSalvar.clic *guardar los datos *verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif if empty( thisform.mNombre.value) wait window "Nombre incorrecto..." nowait thisform.mNombre.setfocus return endif *verificar el campo clave si se esta agregando if pAgregando sele 1 mCodigo = alltrim( thisform.mCodigo.value) seek mCodigo if found() mMens1 = "Imposible guardar, el código " +mCodigo +" existe!" +chr(13) mMens2 = "Utilice otro código e intente Agregar de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif endif *chequear indicador de proceso if pAgregando *agregar registro insert into programa from memvar wait window "Registro agregado..." nowait else *actualizar datos del registro gather memvar memo wait window "Registro modificado..." nowait endif

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #5

6

*colocar indicadores a falso pAgregando = .f. pEditando = .f. *desactivar campos de datos thisform.mCodigo.enabled = .f. thisform.mNombre.enabled = .f. *activar botones necesarios thisform.btnPrimero.enabled = .t. thisform.btnAnterior.enabled = .t. thisform.btnSiguiente.enabled = .t. thisform.btnUltimo.enabled = .t. thisform.btnAgregar.enabled = .t. thisform.btnModificar.enabled = .t. thisform.btnRetirar.enabled = .t. thisform.btnReporte.enabled = .t. thisform.btnExaminar.enabled = .t. thisform.btnCerrar.enabled = .t. *desactivar botones salvar y deshacer thisform.btnGuardar.enabled = .f. thisform.btnDeshacer.enabled = .f. return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #5

7

BtnDeshacer.clic *deshacer los cambios hechos a los datos sele 1 scatter memvar memo wait window "Proceso de Edición cancelado..." nowait *colocar indicadores a falso pAgregando = .f. pEditando = .f. *desactivar campos de datos thisform.mCodigo.enabled = .f. thisform.mNombre.enabled = .f. *activar botones necesarios thisform.btnPrimero.enabled = .t. thisform.btnAnterior.enabled = .t. thisform.btnSiguiente.enabled = .t. thisform.btnUltimo.enabled = .t. thisform.btnAgregar.enabled = .t. thisform.btnModificar.enabled = .t. thisform.btnRetirar.enabled = .t. thisform.btnReporte.enabled = .t. thisform.btnExaminar.enabled = .t. thisform.btnCerrar.enabled = .t. *desactivar botones salvar y deshacer thisform.btnGuardar.enabled = .f. thisform.btnDeshacer.enabled = .f. thisform.refresh return

Y ahora manos a la obra! Aplique esta técnica de programación, con la tabla maestro de Asignaturas.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #5

8

COMPLEMENTO A LA GUÍA #5 LA PROGRAMACIÓN MULTIUSUARIA (PARTE 1) En esta primer entrega estudiaremos un poco el concepto de la programación multiusuaria, un tema que pone a temblar a más de un programador. En realidad, el programar acceso múltiple de usuarios a las mismas tablas es algo sencillo en el FoxPro, basta con tener en cuenta las consideraciones planteadas en este documento, y usted quedará listo para desarrollar aplicaciones en el sistema operativo de red que sea (lógico está, siempre y cuando soporte Visual FoxPro). ACCESO EXCLUSIVO (EXCLUSIVE) Y COMPARTIDO (SHARED) A LAS TABLAS Cuando se desarrolla una aplicación que se requiere funcionando en redes, el programador debe considerar la posibilidad de muchos usuarios accesando a las mismas tablas. Para esto es importante saber que existe el acceso exclusivo por parte de un usuario a una tabla y el acceso compartido a las mismas. Cuando se ejecuta acceso exclusivo a una tabla, el sistema solo le permite el acceso a la tabla al usuario que hizo la solicitud, cuando otros usuarios traten de acceder a la tabla abierta como de uso exclusivo para otro usuario, se generará un error de acceso a la tabla, lo cual puede paralizar una aplicación si no se tienen controles adecuados de error. El acceso compartido, FoxPro permite que varios usuarios utilicen la información de las mismas tablas simultáneamente. BLOQUEO (RECORD LOCK) DE REGISTROS Y ARCHIVOS (FILE LOCK) El bloqueo de un registro consiste en que el sistema asegura el registro solicitado con el objetivo de que otras personas no puedan utilizarlo durante el tiempo en que se halle bloqueado por otro usuario. Muchos procesos requieren que los registros estén bloqueados con el objetivo de mantener la integridad de la información de una tabla determinada. Procesos tales como la modificación de registros, el borrado, etc, requieren ejecutar una orden de bloqueo; una vez el usuario suelte el registro, la aplicación debe desbloquear el registro (UNLOCK) para dejarlo disponible a los otros usuarios, de lo contrario, el registro seguiría bloqueado hasta que se cierre la sesión del usuario en la aplicación. El bloqueo de archivos (FILE LOCK) consiste en asegurar un archivo completo con el objetivo de utilizar un archivo, ejecutar algún proceso delicado, y estar seguros de que nadie más manipulará la información o registros del mismo. Procesos como la generación de entradas de índices (INDEX ON), el empaquetamiento (PACK) de los registros marcados para borrar (con la orden DELETE), la modificación de la estructura de una tabla (MODIFY STRUCTURE), etc, requieren del bloqueo total de una tabla para su ejecución. Es importante además, el tener en cuenta que muchas órdenes y funciones del FoxPro requieren el bloqueo de registros o archivos para su ejecución. Cada vez que el programador requiere utilizar una de estas órdenes, deberá ejecutar el respectivo bloqueo, ejecutar la orden, y liberar el registro o la tabla bloqueada para hacerla disponible al resto de los usuarios. Debe consultar el manual del sistema FoxPro con el objetivo de conocer las órdenes que requieren tales bloqueos en los registros y en las tablas. Nota: En la siguiente entrega, mostraremos las órdenes requeridas para la programación de aplicaciones multiusarias. Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #5

9

LA RUTINA PARA EL CONTROL DE ERRORES El FoxPro permite la manipulación de los errores ocurridos durante la ejecución de una aplicación. A estas alturas, el alumno ya habrá descubierto que existen varias clases de errores cuando se trabaja en una aplicación: Errores en tiempo de compilación (errores de sintaxis): estos errores ocurren cuando se ha escrito mal un comando o función. Cuando se ha escrito mal un comando o se han utilizado parámetros incorrectos, FoxPro paralizará la ejecución del programa y sacará un mensaje de error en una caja de diálogo. Este tipo de errores son causa de una mala programación, y el programador deberá ejecutar y probar sus rutinas para depurar el código de su aplicación y estar “tranquilo” de que todo funciona. El mismo programador, es el único responsable de que su aplicación trabaje sin errores y el solo, debe analizar la causa del error encontrado durante la ejecución de sus aplicaciones. Errores en tiempo de ejecución: Estos errores aparecen cuando, una vez depurado el código de una aplicación, el FoxPro paraliza la ejecución por alguna razón que se sale de nuestras manos; sin embargo, con una buena rutina de control de errores, podremos indicarle a la aplicación que hacer cuando sucedan tales errores. Errores tales como disco lleno, Registro o archivo bloqueado por otro usuario, archivo no existe, etc, son errores que pueden ser controlados y manipulados por una buena rutina de control de errores. Más adelante en las clases, se tratará el tema de el manejo de los errores dentro de los programas. Con una rutina de control de errores, el programador controlará la situación de si permite la continuación o no de la aplicación, o determinar soluciones para continuar con la rutina iniciada. Un error por ejemplo, se presentaría cuando el sistema trate de abrir una tabla que por algún motivo fue retirada del sistema por otro usuario; la rutina de control de errores se encontraría con la ausencia de tal tabla, generando automáticamente un error de archivo no existe, esa misma rutina podría determinar el nombre origen de la tabla faltante y por supuesto, crearla automáticamente dentro del directorio de datos. Luego de definido el nuevo archivo, puede indicarle al FoxPro que repita la orden que generó el error y que siga la ejecución de la aplicación como si nada hubiese pasado. Para adelantar trabajo, busque en el manual del sistema FoxPro, el comando ON ERROR y analice el ejemplo que acompaña a la teoría para ir comprendiendo este tema tan importante a la hora de programar aplicaciones.

Instituto Metropolitano de Educación

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #5 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO

TÉCNICA DE PROGRAMACIÓN #3 – FORMULARIOS TIPO FACTURA Existe una rutina muy popular entre los programadores y la cual se constituye en el “quebradero de cabeza” de más de un iniciado en la programación: el diseño de formularios que permitan la captura de información en documentos tales como la factura. Un documento como la factura (bien sea de compra o de venta) tiene un encabezado y un detalle. También tienen esta característica los pedidos, los documentos soporte de inventario, una lista de grupos, un proceso de calificaciones, etc. Cualquier documento empleado por una empresa y que tenga una presentación que incluya encabezado del documento y una descripción de detalle, debe ser automatizado empleando la técnica número 3. Es de aclarar que tal situación de programación se puede solucionar de muchas formas, planteamos en este curso, un método sencillo y práctico de automatización. La siguiente gráfica muestra un posible documento de factura de compra. Aunque es bastante sencillo ilustra la característica de los documentos que requieren aplicar la técnica de programación propuesta en esta guía.

En donde reside lo complic ado de programar un formulario para este documento? Cuando se efectúa el diseño de la base de datos, se descubre que es necesario dos tablas para solucionar el requerimiento del documento: la principal y el detalle, relacionando ambas tablas por un campo común, usualmente el campo clave de la tabla principal, en este caso Número de factura. Lo cual indica, que en la parte del detalle, el programa deberá visualizar solamente a los registros que posean el mismo número de factura del documento visualizado en la parte del encabezado. Otro asunto importante, es el de permitir manipular en forma ágil el detalle, permitiendo agregar, modificar y retirar información de las líneas que constituyen el detalle, y actualizando el total del documento en el pie de página del documento. Es decir, cada vez que se actualice la cantidad o el valor unitario de una de las líneas del detalle, se debe reflejar tales cambios en todo el documento.

Instituto Metropolitano de Educación

Visua l FoxPro - Guía de Clases #6

2

FORMULARIOS TIPO FACTURA PROPUESTO Como modelo de programación utilizaremos el control de los grupos de clase de una institución. Como parte principal del documento aparecerá la información relevante a un grupo de clases y como detalle, se colocarán todos los estudiantes pertenecientes a cada grupo. Utilizaremos además, uno de los mejores objetos incluidos en el Visual FoxPro, el Grid (cuadrícula). Como parámetro de los elementos a mostrar en el grid, utilizaremos una instrucción Select de SQL. El diseño utilizará las siguientes tablas: Programas, Asignaturas, Profesores, Hoja de vida, Matrícula, Grupos y Estudiantes por Grupo. 1. Grupos (Grupos) Nombre Campo Tipo de datos Codigo Carácter Nombre Carácter Asignatura Carácter Horario Carácter Aula Carácter Profesor Carácter

Ancho 10 50 10 50 50 15

Campo clave ascendente: Codigo 3. Hojas de vida (Hvida) Nombre Campo Tipo de datos Codigo Carácter Nombre Carácter Apellidos Carácter Programa Carácter TelResiden Carácter DirResiden Carácter FechaNac Fecha

Ancho 10 50 50 2 20 40 8

2. Estudiantes por Grupo (EstGrupo) Nombre Campo Tipo de datos Ancho Codigo Carácter 10 CodEstud Carácter 10 ExParcial Numerico 4,2 Seguim Numerico 4,2 ExFinal Numerico 4,2 Wfinal Numerico 4,2 NotaFinal Numerico 4,2 Estado Carácter 1 Campo clave ascendente: Codigo + CodEstud 4. Matrícula (Matric) Nombre Campo Tipo de datos Codigo Carácter Fecha Fecha Nivel Carácter Jornada Carácter Estado Carácter Observa Memo

Ancho 10 8 2 1 1 10

Campo clave ascendente: Codigo Campo clave ascendente: Codigo 5. Maestro de Profesor (Profe) Nombre Campo Tipo de datos Codigo Carácter Nombre Carácter TelResiden Carácter TelTrabajo Carácter Asignatura Carácter Campo clave ascendente: Codigo

Ancho 15 50 15 15 100

6. Maestro de Programas (Programa) Nombre Campo Tipo de datos Ancho Codigo Carácter 2 Nombre Carácter 50 Campo clave ascendente: Codigo 7. Maestro de Asignaturas (Asigna) Nombre Campo Tipo de datos Ancho Codigo Carácter 10 Nombre Carácter 50 Programa Carácter 2 Campo clave ascendente: Codigo

Instituto Metropolitano de Educación

Visua l FoxPro - Guía de Clases #6

3

Esta clase de rutina es un poco compleja debido al gran número de tablas que se requieren para su funcionamiento. Observe que para la rutina de grupos se requiere tener almacenados datos de programas, asignaturas, profesores, hojas de vida y datos de matrícula de los estudiantes. Si no se tienen datos en tales tablas, el diseño no funcionará debido a los controles de datos que efectúa sobre los datos entrados por el usuario.

Instituto Metropolitano de Educación

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #6 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO

TÉCNICA DE PROGRAMACIÓN #3 – FORMULARIOS TIPO FACTURA Existe una rutina muy popular entre los programadores y la cual se constituye en el “quebradero de cabeza” de más de un iniciado en la programación: el diseño de formularios que permitan la captura de información en documentos tales como la factura. Un documento como la factura (bien sea de compra o de venta) tiene un encabezado y un detalle. También tienen esta característica los pedidos, los documentos soporte de inventario, una lista de grupos, un proceso de calificaciones, etc. Cualquier documento empleado por una empresa y que tenga una presentación que incluya encabezado del documento y una descripción de detalle, debe ser automatizado empleando la técnica número 3. Es de aclarar que tal situación de programación se puede solucionar de muchas formas, planteamos en este curso, un método sencillo y práctico de automatización. La siguiente gráfica muestra un posible documento de factura de compra. Aunque es bastante sencillo ilustra la característica de los documentos que requieren aplicar la técnica de programación propuesta en esta guía.

En donde reside lo complic ado de programar un formulario para este documento? Cuando se efectúa el diseño de la base de datos, se descubre que es necesario dos tablas para solucionar el requerimiento del documento: la principal y el detalle, relacionando ambas tablas por un campo común, usualmente el campo clave de la tabla principal, en este caso Número de factura. Lo cual indica, que en la parte del detalle, el programa deberá visualizar solamente a los registros que posean el mismo número de factura del documento visualizado en la parte del encabezado. Otro asunto importante, es el de permitir manipular en forma ágil el detalle, permitiendo agregar, modificar y retirar información de las líneas que constituyen el detalle, y actualizando el total del documento en el pie de página del documento. Es decir, cada vez que se actualice la cantidad o el valor unitario de una de las líneas del detalle, se debe reflejar tales cambios en todo el documento.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

2

FORMULARIOS TIPO FACTURA PROPUESTO Como modelo de programación utilizaremos el control de los grupos de clase de una institución. Como parte principal del documento aparecerá la información relevante a un grupo de clases y como detalle, se colocarán todos los estudiantes pertenecientes a cada grupo. Utilizaremos además, uno de los mejores objetos incluidos en el Visual FoxPro, el Grid (cuadrícula). Como parámetro de los elementos a mostrar en el grid, utilizaremos una instrucción Select de SQL. El diseño utilizará las siguientes tablas: Programas, Asignaturas, Profesores, Hoja de vida, Matrícula, Grupos y Estudiantes por Grupo. 1. Grupos (Grupos) Nombre Campo Tipo de datos Codigo Carácter Nombre Carácter Asignatura Carácter Horario Carácter Aula Carácter Profesor Carácter

Ancho 10 50 10 50 50 15

Campo clave ascendente: Codigo 3. Hojas de vida (Hvida) Nombre Campo Tipo de datos Codigo Carácter Nombre Carácter Apellidos Carácter Programa Carácter TelResiden Carácter DirResiden Carácter FechaNac Fecha

Ancho 10 50 50 2 20 40 8

2. Estudiantes por Grupo (EstGrupo) Nombre Campo Tipo de datos Ancho Codigo Carácter 10 CodEstud Carácter 10 ExParcial Numerico 4,2 Seguim Numerico 4,2 ExFinal Numerico 4,2 Wfinal Numerico 4,2 NotaFinal Numerico 4,2 Estado Carácter 1 Campo clave ascendente: Codigo + CodEstud 4. Matrícula (Matric) Nombre Campo Tipo de datos Codigo Carácter Fecha Fecha Nivel Carácter Jornada Carácter Estado Carácter Observa Memo

Ancho 10 8 2 1 1 10

Campo clave ascendente: Codigo Campo clave ascendente: Codigo 5. Maestro de Profesor (Profe) Nombre Campo Tipo de datos Codigo Carácter Nombre Carácter TelResiden Carácter TelTrabajo Carácter Asignatura Carácter Campo clave ascendente: Codigo

Ancho 15 50 15 15 100

6. Maestro de Programas (Programa) Nombre Campo Tipo de datos Ancho Codigo Carácter 2 Nombre Carácter 50 Campo clave ascendente: Codigo 7. Maestro de Asignaturas (Asigna) Nombre Campo Tipo de datos Ancho Codigo Carácter 10 Nombre Carácter 50 Programa Carácter 2 Campo clave ascendente: Codigo

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

3

Esta clase de rutina es un poco compleja debido al gran número de tablas que se requieren para su funcionamiento. Observe que para la rutina de grupos se requiere tener almacenados datos de programas, asignaturas, profesores, hojas de vida y datos de matrícula de los estudiantes. Si no se tienen datos en tales tablas, el diseño no funcionará debido a los controles de datos que efectúa sobre los datos entrados por el usuario. EL FORMULARIO TIPO FACTURA Utilizaremos la tabla de grupos y el detalle de grupos para ilustrar el funcionamiento de la técnica de programación en cuestión. Note que para esta clase de formularios, es normal combinar gran cantidad de tablas a la hora de la programación. Verifique el código visto en rutinas anteriores, debido a que cambia gran cantidad de instrucciones, para dar soporte a la nueva técnica.

1.mCodigo 5. mHorario 9. btnExaminar 13. btnRetirarDet 17. btnPrimero 21. btnAgregar 25. btnCargar

2. mNombre 6. mNomAsigna 10. btnReporte 14. btnModificarDet 18. btnAnterior 22. btnActual 26. btnLimpiar

3. mAsignatura 7. mNomProfesor 11. mCodEstMaestro 15. DetalleGrupo 19. btnSiguiente 23. btnRetirar

Instituto Metropolitano de Educación

4. mProfesor 8. mAula 12. btnAgregarDet 16. mEstado 20. btnUltimo 24. btnCerrar

Visual FoxPro - Guía de Clases #6

4

Para crear los objetos 3, 4 y 11 utilice la técnica enseñada en clases anteriores para definir listas desplegables basadas en otras tablas. Objeto 3 indica la asignatura para el grupo: ControlSource: m.asignatura RowSource: asigna.codigo, nombre RowSourceType: 2-Alias ColumnCount: 2 ColumnWitdh: 40,300 Objeto 4 indica el profesor asignado al grupo: ControlSource: m.profesor RowSource: profe.codigo,nombre RowSourceType: 2-Alias ColumnCount: 2 ColumnWitdh: 40,300 Objeto 11 sirve para seleccionar estudiantes e integrarlos al grupo activo en el formulario: RowSource: hvida.codigo, apellidos, nombre RowSourceType: 2-Alias ColumnCount: 3 ColumnWitdh: 70,200,200 El objeto 16 es una lista basada en valores entrados a la hora de programar que indica el estado dentro del grupo para el estudiante: ControlSource: m.estado RowSource: A,Activo,S,Suspendido,C,Cancelado,N,No Matriculado RowSourceType: 1-Valor ColumnCount: 2 ColumnWitdh: 40, 100 Desactive los siguientes objetos en el formulario (propiedad enabled igual a .F.-Falso): 6, 7, 12, 13, 14 y 16.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

5

LA RUTINA QUE INICIA TODO EL PROCESO Como caso particular de este formulario, es que no se puede ejecutar directamente. Por problemas técnicos del Visual FoxPro, cuando se inicializan tablas en un formulario y a la vez en este se incluyen elementos de cuadrícula (grid) o cuadro de listas (combo list) simplemente no funcionan. Por tal razón, debemos crear una rutina que abra todas las tablas a usar en el sistema y llamar al formulario al final de la rutina. Como origen de datos para una cuadrícula o combo list, resulta muy útil el declarar una instrucción SELECT - SQL. Este es el contenido de la rutina I_GRUPOS.PRG (no olvide almacenarla en el sitio destinado para los programas): I_GRUPOS.PRG * Esta rutina invoca al formulario Grupos *abrir entorno para el formulario grupos utilizando *las variables publicas *tabla de grupos mFile1 = _dircia +"grupos.dbf" if !file( mFile1) do cGrupos in prg\creatbl endif sele 1 use &mFile1 order tag codigo alias grupos *tabla estudiantes por grupo mFile2 = _dircia +"estgrupo.dbf" if !file( mFile2) do cEstGrupo in prg\creatbl endif sele 2 use &mFile2 order tag codigo alias estgrupo *tabla maestro asignaturas mFile3 = _dircia +"asigna.dbf" if !file( mFile3) do cAsigna in prg\creatbl endif sele 3 use &mFile3 order tag codigo alias asigna *tabla maestro programas mFile4 = _dircia +"programa.dbf" if !file( mFile4) do cPrograma in prg\creatbl endif sele 4 use &mFile4 order tag codigo alias programa Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

6

*tabla maestro profesores mFile5 = _dircia +"profe.dbf" if !file( mFile5) do cProfe in prg\creatbl endif sele 5 use &mFile5 order tag codigo alias profe *tabla hojas de vida mFile6 = _dircia +"hvida.dbf" if !file( mFile6) do cHvida in prg\creatbl endif sele 6 use &mFile6 order tag codigo alias hvida *tabla matricula mFile7 = _dircia +"matric.dbf" if !file( mFile7) do cMatric in prg\creatbl endif sele 7 use &mFile7 order tag codigo alias matric sele 1 *apuntar a la carpeta de los formularios do form forms\grupos return

Lo único que hace esta rutina es abrir las tablas requeridas en diferentes áreas de trabajo, asignar los respectivos alias y por supuesto, pasar el control de ejecución, al formulario tipo factura.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

7

RUTINAS EN LOS OBJETOS DEL FORMULARIO Formulario.INIT *continuación del codigo iniciado en i_grupos public pCodEstud pCodEstud = "" set delete on sele 1 go top scatter memvar memo *ir al objeto inicial thisform.mCodigo.setfocus *actualizar grid (cuadrícula) thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " + ; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh thisform.refresh En esta rutina se hace uso de la instrucción SELECT-SQL y se asigna como parámetro al objeto DetalleGrupo. Cada vez que se requiera actualizar el detalle de cada grupo, simplemente invocaremos esta sección de código y refrescaremos el objeto en el formulario. Observe que la instrucción se arma como una cadena. Esa es la razón del porqué de tantas “ y ; en la instrucción. Esta orden podría colocarse en una sola línea, pero resulta conveniente dividirla en secciones, para poderla entender. El docente guía le indicará que hace la orden SQL empleada.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

8

Objeto BtnPrimero.Click *ir al primero wait window "Primer registro..." nowait sele 1 go top scatter memvar memo sele asigna seek alltrim( m.asignatura) sele profe seek alltrim( m.profesor) *actualizar grid (cuadrícula) thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " + ; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh *controlar botones del detalle pCodEstud = "" thisform.btnRetirarDet.enabled = .f. thisform.btnModificarDet.enabled = .f. thisform.mEstado.enabled = .f. thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

9

Objeto BtnAnterior.Click *ir al anterior sele 1 if !bof() skip -1 endif if bof() go top endif scatter memvar memo sele asigna seek alltrim( m.asignatura) sele profe seek alltrim( m.profesor) *actualizar grid (cuadrícula) thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " +; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh *controlar botones del detalle pCodEstud = "" thisform.btnRetirarDet.enabled = .f. thisform.btnModificarDet.enabled = .f. thisform.mEstado.enabled = .f. thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

10

Objeto btnSiguiente.click *ir al siguiente sele 1 if !eof() skip 1 endif if eof() go bottom endif scatter memvar memo sele asigna seek alltrim( m.asignatura) sele profe seek alltrim( m.profesor) *actualizar grid (cuadrícula) thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " + ; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh *controlar botones del detalle pCodEstud = "" thisform.btnRetirarDet.enabled = .f. thisform.btnModificarDet.enabled = .f. thisform.mEstado.enabled = .f. thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

11

Objeto btnUltimo.click *ir al ultimo wait window "Último registro..." nowait sele 1 go bottom scatter memvar memo sele asigna seek alltrim( m.asignatura) sele profe seek alltrim( m.profesor) *actualizar grid (cuadrícula) thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " + ; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh *controlar botones del detalle pCodEstud = "" thisform.btnRetirarDet.enabled = .f. thisform.btnModificarDet.enabled = .f. thisform.mEstado.enabled = .f. thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

12

Objeto BtnAgregar.clic *agregar registro con los datos en pantalla sele 1 *verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif if empty( thisform.mNombre.value) wait window "Nombre incorrecto..." nowait thisform.mNombre.setfocus return endif *verificar campo clave mCodigo = alltrim( thisform.mCodigo.value) sele 1 seek mCodigo if found() mMens1 = "Imposible agregar, el código " +mCodigo +" ya existe!" +chr(13) mMens2 = "Utilice otro código e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif *validar la asignatura entrada por el usuario mAsignatura = alltrim( thisform.mAsignatura.value) sele asigna seek mAsignatura if !found() mMens1 = "El código de Asignatura " +mAsignatura +" no existe!" +chr(13) mMens2 = "Utilice un código válido e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mAsignatura.setfocus return endif

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

13

*validar el profesor entrado por el usuario mProfesor = alltrim( thisform.mProfesor.value) sele profe seek mProfesor if !found() mMens1 = "El código de Profesor " +mAsignatura +" no existe!" +chr(13) mMens2 = "Utilice un código válido e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mProfesor.setfocus return endif *agregar nuevo registro con los datos en pantalla sele 1 insert into grupos from memvar *cargar nuevos datos en blanco scatter memvar blank *ir al primer campo thisform.mCodigo.setfocus *actualizar nuevo detalle thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " +; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.refresh

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

14

Objeto btnActual.click *actualizar el contenido de un campo *verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif if empty( thisform.mNombre.value) wait window "Nombre incorrecto..." nowait thisform.mNombre.setfocus return endif if empty( thisform.mAsignatura.value) wait window "Código de Asignatura incorrecto..." nowait thisform.mAsignatura.setfocus return endif if empty( thisform.mProfesor.value) wait window "Código de Profesor incorrecto..." nowait thisform.mProfesor.setfocus return endif *validar asignatura entrada por el usuario mAsignatura = alltrim( thisform.mAsignatura.value) sele asigna seek mAsignatura if !found() mMens1 = "El código de Asignatura " +mAsignatura +" no existe!" +chr(13) mMens2 = "Utilice un código válido e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mAsignatura.setfocus return endif *validar profesor entrado por el usuario mProfesor = alltrim( thisform.mProfesor.value) sele profe seek mProfesor if !found() mMens1 = "El código de Profesor " +mProfesor +" no existe!" +chr(13) mMens2 = "Utilice un código válido e intente de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mProfesor.setfocus return endif Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

15

*actualizar datos del campo clave sele 1 mCodigo = alltrim( thisform.mCodigo.value) seek mCodigo if found() && actualizar registro hallado gather memvar memo wait window "Datos actualizados..." nowait else mMens1 = "Imposible actualizar, el código " +mCodigo +" no existe!" +chr(13) mMens2 = "Utilice otro código e intente actualizar de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif *actualizar detalle thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " +; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " sele 1 thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

16

Objeto btnRetirar.click *retirar el registro clave hallado sele 1 mCodigo = alltrim( thisform.mCodigo.value) seek mCodigo if !found() && no existe codigo mMens1 = "Imposible retirar, el código " +mCodigo +" no existe!" +chr(13) mMens2 = "Utilice otro código e intente retirar de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodigo.setfocus return endif mMens1 = "Desea retirar el código " + mCodigo +" del sistema!" +chr(13) mOpc = messagebox( mMens1 , 1+32, "Retirar registro!") if mOpc = 1 && Clic en botón Aceptar sele 1 delete wait window "Registro retirado del sistema..." nowait *mover puntero al próximo disponible if !eof() skip 1 endif if eof() go bottom endif *retirar estudiantes del grupo eliminado sele estGrupo dele all for alltrim( estGrupo.codigo) = mCodigo sele 1 endif sele 1 scatter memvar memo *actualizar detalle thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " +; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

17

Objeto btnExaminar.click *examinar registros sele 1 browse fields codigo, nombre ; noedit noappend nodelete *activar el seleccionado scatter memvar memo *actualizar grid (cuadrícula) sele estGrupo thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " + ; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh thisform.refresh return

Objeto btnLimpiar.clic *limpiar el contenido de los campos wait window "Datos en blanco..." nowait sele 1 scatter memvar memo blank *actualizar grid (cuadrícula) sele estGrupo thisform.DetalleGrupo.rowsource = "" thisform.DetalleGrupo.refresh thisform.refresh

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

18

Objeto btnCargar.click *cargar el contenido de los campos con la clave entrada *verificar si hay datos en blanco if empty( thisform.mCodigo.value) wait window "Código incorrecto..." nowait thisform.mCodigo.setfocus return endif *cargar datos del campo clave sele 1 mCodigo = alltrim( thisform.mCodigo.value) seek mCodigo if found() && actualizar registro hallado scatter memvar memo wait window "Datos cargados..." nowait else mMens1 = "Imposible cargar datos, el código " +mCodigo +" no existe!" +chr(13) mMens2 = "Utilice otro código e intente cargar datos de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") endif *actualizar grid (cuadrícula) sele estGrupo thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " + ; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh thisform.refresh thisform.mCodigo.setfocus return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

19

Objeto mCodEstMaestro.valid *activar los otros botones para el detalle thisform.btnAgregarDet.enabled = .t. thisform.btnRetirarDet.enabled = .t. thisform.btnModificarDet.enabled = .t. mCodEstMaestro.when return !empty( m.codigo)

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

20

Objeto btnAgregarDet.when return !empty( m.codigo) .and. !empty( thisform.mCodEstMaestro.value) BtnAgregarDet.valid *agregar codigo seleccionado al detalle del grupo mCodEstud = alltrim( thisform.mCodEstMaestro.value) *validar código en maestro estudiantes sele hvida seek mCodEstud if !found() mMens1 = "Imposible agregar al detalle, el código " +mCodEstud +" no existe en el maestro!" +chr(13) mMens2 = "Utilice otro código e intente agegar al detalle de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodEstMaestro.setfocus return endif *verificar estudiante en el grupo sele estgrupo mGrupo = alltrim( m.codigo) seek mGrupo + mCodEstud if found() mMens1 = "Imposible agregar estudiante al grupo, el código " +mCodEstud +" ya existe!" +chr(13) mMens2 = "Utilice otro código e intente agegar al detalle de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") thisform.mCodEstMaestro.setfocus return endif *agregar linea al detalle insert into estGrupo ; ( codigo, codEstud, estado) ; values ; ( mGrupo, mCodEstud, "A") *actualizar grid (cuadrícula) thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " +; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh *keyboard "{ctrl+w}" thisform.refresh Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

21

Objeto BtnRetirarDet.valid *retirar el registro seleccionado en el detalle *utilizar pCodEstud como clave de seleccion if empty( pCodEstud) mMens1 = "Seleccione un código del detalle e intente retirar de nuevo..." mOpc = messagebox( mMens1, 0+64, "Atención!") thisform.DetalleGrupo.setfocus return endif sele estGrupo mCodigo = alltrim( m.codigo) +alltrim( pCodEstud) seek mCodigo if !found() && no existe codigo mMens1 = "Imposible retirar, el código " + pCodEstud +" no existe en el detalle!" +chr(13) mMens2 = "Seleccione un código del detalle e intente retirar de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") pCodEstud = "" thisform.DetalleGrupo.setfocus return endif mMens1 = "Desea retirar el código " + pCodEstud +" del grupo!" +chr(13) mOpc = messagebox( mMens1 , 1+32, "Retirar estudiante del Grupo!") if mOpc = 1 && Clic en botón Aceptar sele estGrupo delete pCodEstud = "" wait window "Registro retirado del sistema..." nowait endif sele 1 scatter memvar memo

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

22

*actualizar detalle thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " + ; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh thisform.refresh return BtnRetirarDet.when *habilitar cuando hagan clic en el detalle del grupo return !empty( pCodEstud)

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

23

Objeto btnModificarDet.valid *actualizar el registro seleccionado en el detalle *utilizar pCodEstud como clave de seleccion if empty( pCodEstud) mMens1 = "Seleccione un código del detalle e intente actualizar de nuevo..." mOpc = messagebox( mMens1, 0+64, "Atención!") thisform.DetalleGrupo.setfocus return endif sele estGrupo mCodigo = alltrim( m.codigo) +alltrim( pCodEstud) seek mCodigo if !found() && no existe codigo mMens1 = "Imposible actualizar, el código " + pCodEstud +" no existe en el detalle!" +chr(13) mMens2 = "Seleccione un código del detalle e intente retirar de nuevo..." mOpc = messagebox( mMens1 +mMens2, 0+64, "Atención!") pCodEstud = "" thisform.DetalleGrupo.setfocus return endif mMens1 = "Desea actualizar los datos del código " + pCodEstud +"!" +chr(13) mOpc = messagebox( mMens1 , 1+32, "Actualizar datos del estudiante!") if mOpc = 1 && Clic en botón Aceptar sele estGrupo replace estGrupo.estado with alltrim( thisform.mEstado.value) wait window "Datos actualizados..." nowait endif sele 1 scatter memvar memo *actualizar detalle thisform.DetalleGrupo.rowsource = "select all estgrupo.codEstud, " + ; "hvida.programa, estgrupo.estado, " +; "alltrim( hvida.apellidos) +space(1)+alltrim( hvida.nombre) " +; "from estGrupo join hvida " +; "on alltr( estGrupo.codEstud) = alltr( hvida.codigo) " + ; "where alltrim( estGrupo.codigo) = alltrim( m.codigo) " + ; ".and. !deleted() order by codEstud noconsole nowait " + ; "into cursor miconsulta " thisform.DetalleGrupo.refresh thisform.refresh return Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

24

BtnModificarDet.when *habilitar cuando hagan clic en el detalle del grupo return !empty( pCodEstud)

Objeto DetalleGrupo.click *codigo seleccionado para borrar o modificar pCodEstud = alltrim( this.value) *buscar codigo en detalle para que funcione *modificacion de datos mCodigo = alltrim( m.codigo) +alltrim( pCodEstud) sele estGrupo seek mCodigo *datos disponibles para actualizar m.estado = estgrupo.estado thisform.mEstado.enabled = .t. thisform.btnRetirarDet.enabled = .t. thisform.btnModificarDet.enabled = .t. thisform.refresh return

Observaciones: •

El objeto DetalleGrupo debe definirse como un Combo List y debe contemplar los siguientes parámetros: RowSourceType: 3-SQL ColumnCount: 5 ColumnLines:..F.-Falso



El objeto mNomAsigna debe tener la propiedad ControlSource igual a: asigna.nombre



El objeto mNomProfesor debe tener la propiedad ControlSource igual a: profe.nombre

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #6

25

ADICION DE SUBPROGRAMAS A LA RUTINA CREATBL El archivo de procedimientos CREATBL.PRG, debe contener dos subprogramas que permitan crear las tablas de Grupos.dbf y EstGrupo.dbf. Debe insertar el siguiente código en la el archivo de procedimientos CREATBL.PRG:

procedure cGrupos *definir tabla grupos mFile = _dircia + "grupos.dbf" create table &mFile ; ( codigo c ( 10), ; nombre c ( 50), ; asignatura c ( 10), ; profesor c ( 15), ; horario c ( 50), ; aula c ( 50)) index on codigo tag codigo for !deleted() index on nombre tag nombre for !deleted() close data return procedure cEstGrupo *definir tabla grupos mFile = mFile = _dircia + "estgrupo.dbf" create table &mFile ; ( codigo c ( 10), ; codestud c ( 10), ; exparcial n (4,2), ; seguim n (4,2), ; exfinal n (4,2), ; wfinal n (4,2), ; estado c ( 1)) index on alltrim( codigo) + alltrim( codestud) tag codigo for !deleted() close data return

Nota: Observe que el campo índice de la tabla Estudiantes por Grupo es de tipo compuesto. Revise la teoría ofrecida en las guías de clase anteriores para comprender mejor la situación y el manejo de campos claves compuestos. Revise en el código de la rutina Grupos para analizar en que puntos se hace el uso de los índices compuestos y su forma correcta de utilizarlos.

Instituto Metropolitano de Educación

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #7 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO

LOS REPORTES Y LAS CONSULTAS EN LAS APLICACIONES La potencia de las aplicaciones, viene marcada por la cantidad de informes y consultas que permitan hacer sobre la información almacenada en las tablas que componen a un sistema de información. La cantidad de informes queda limitada a la capacidad de cada programador y a los reportes que solicite la persona que nos ha contratado para desarrollar un proyecto. Lo cual significa, que un sistema por pequeño que sea puede incluir una serie de reportes que harían que el proyecto se viese como un “gigante”. Las consultas pueden ser utilizadas para enviar resultados de búsquedas basadas en criterios ofrecidos por los usuarios y su resultado se puede enviar a la pantalla o a la impresora. EL GENERADOR DE REPORTES El FoxPro incluye un generador de reportes bastante potente. Dentro de un reporte se pueden incluir texto, campos, imágenes, líneas, cuadros, campos calculados, unión de campos, funciones, etc. Si se domina (como programador) el tema de las funciones, se pueden ejecutar una serie de acciones que ahorrarían mucho tiempo a la hora de diseñar reportes. Las expresiones que conjuguen una serie de funciones, capos y cadenas de caracteres, permiten ampliar aún más las posibilidades del generador de reportes del FoxPro. Tenga presente que el FoxPro “amarra” las tablas utilizadas para sacar la información, al reporte que las utiliza. Si analizamos la forma en que hemos venido trabajando hasta el momento, en ningún momento debemos permitir que tal cosa pase. Nuestra aplicación utiliza tablas ubicadas en directorios diferentes dependiendo del campo DIRECTORIO en la tabla CIAS.DBF. Como no podemos dejar que el FoxPro amarre las tablas a los reportes, iniciaremos el generador en blanco y diseñaremos el reporte teniendo a la mano los campos requeridos para el informe. Seleccione la pestaña Docs en el administrador de proyectos y seleccione los objetos formularios para que FoxPro nos muestre los reportes diseñados. Si es un reporte a modificar, haga clic en la lista sobre el nombre del reporte, luego haga clic en el botón Modificar. Si lo que desea es agregar un reporte que hace falta dentro del proyecto, haga clic en Agregar y seleccione el nombre del reporte desde sus unidades de disco. Si lo que se desea es crear un nuevo formulario, haga clic en nuevo, seleccione de la pantalla de diálogo que aparece el botón Nuevo Informe . Esta acción abrirá un formulario en blanco, sobre el cual iniciaremos las actividades que definirán el nuevo reporte. Recuerde que el reporte no es funcional en este punto debido a que no existe ninguna tabla abierta en memoria. Una técnica utilizada por muchos programadores, consiste en crear una rutina que abre las tablas necesarias para la funcionalidad del reporte, ejecutarla antes de entrara la creación de mismo, y verificar el correcto funcionamiento del reporte en el sistema. Si no se utiliza ninguna técnica de estas, nuestro reporte solo será funcional cuando lo llamemos desde el formulario que hace uso de las tablas requeridas por el reporte.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

2

Para este ejemplo, crearemos el reporte Programa.frt para mostrar la información de la tabla Programas. Recuerde que el reporte no funcionará desde el modo diseño, así que no intente ejecutar un vista preliminar del reporte.

La barra controles de informes nos facilita el manejo de los objetos que pueden aparecer dentro de un informes. Si no parece, haga clic en el menú Ver y Barra de herramientas Controles de informes.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

3

Utilice el siguiente esquema para diseñar el reporte para la tabla programas:

Como aspecto importante a considerar a la hora de diseñar reportes, es la inclusión del nombre de la empresa para la cual se diseña la aplicación. En algún sitio del encabezado del reporte debe aparecer el nombre del reporte. Incluir la fecha del sistema es también una buena idea para el usuario que tome uno de los reportes en un futuro posterior a la impresión. Los objetos 1, 2 y 3 se diseñan con el botón Campos de Tablas. Utilice estos parámetros para indicarle al generador de reportes de donde proviene la información: #Objeto 1 2 3

Expresión origen de datos "Fecha: " +dtoc( date()) programa.codigo Programa.nombre

En la pantalla de Propiedades del campo, coloque el parámetro de Posición a Flotante.

Instituto Metropolitano de Educación

Formato @! @!

Visual FoxPro - Guía de Clases #7

4

EL FORMULARIO PARA SELECCIONAR EL DESTINO DE UN REPORTE El siguiente paso después de diseñar el reporte, es construir un formulario de uso global que nos permita llamarla desde cualquier formulario, permitirle al usuario seleccionar el destino de un reporte (pantalla o impresora), recoger la selección hecha por el usuario y ejecutar el reporte seleccionado. En cada formulario diseñado hasta el momento, se venia dejando un botón denominado Reporte . En este botón insertaremos el código necesario para activar el formulario que se diseñará a continuación. Vea más adelante en esta guía, la serie de ordenes que utilizan el formulario Reportes. El formulario se diseñará una sola vez, en los demás formularios, se invocará a este formulario para permitirle al usuario que seleccione el destino de un reporte. Construya el siguiente formulario y guárdelo con el nombre de reportes.

1: btnPantalla

2: btnImpresora

3: btnCerrar

CÓDIGO EN LOS OBJETOS DEL FORMULARIO REPORTES En las propiedades del formulario, active la pestaña Otras, busque la propiedad WindowType y colóquela al valor 1-Modal. Si no hace esto, el formulario generará un error al tratar de ejecutarlo. Esto sucede debido a que se retornarán datos que indicarán la selección hecha por el usuario. EVENTO INIT DEL FORMULARIO REPORTES (REPORTES.INIT) public _porPantalla, _porImpresora, _btnCerrar

EVENTO UNLOAD DEL FORMUARIO (REPORTE.UNLOAD) if _porPantalla _resultado = 1 endif if _porImpresora _resultado = 2 endif if _btnCerrar _resultado = 0 endif return( _resultado)

Este evento se ejecuta cuando se cierra el formulario. Observe que cada vez que el usuario hace clic en cada botón, se le asignan valores a unas variables lógicas, indicadoras al final de sobre cual botón se hizo clic. En esta parte del formulario, se recogen los valores de esas variables y se asigna un valor para retornar a la aplicación que llamó al formulario. La instrucción RETURN es la encargada de devolver el parámetro a la aplicación que llame a esta rutina.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7 btnPantalla.Click

5 btnImpresora.Click

*botón Pantalla

*botón Impresora

_porPantalla = .t. _porImpresora = .f. _btnCerrar = .f.

_porPantalla = .f. _porImpresora = .t. _btnCerrar = .f.

thisform.release

thisform.release

BtnCerrar.Click *botón Cerrar _porPantalla = .f. _porImpresora = .f. _btnCerrar = .t. thisform.release

Observe que cada botón libera al formulario y a su vez, asigna unos valores lógicos equivalentes a los tres únicos botones en la pantalla. Existe una variable por cada botón y cuando se hace clic en cada botón, este coloca el valor de verdadero sobre la variable equivalente al botón pulsado y coloca el valor de falso a las otras variables. En la rutina del evento Unload del formulario, se chequea el estado de esas tres variables y se asigna un nuevo valor al parámetro que se debe retornar. Se ha determinado que la rutina devolverá 0 cuando el usuario no escoja nada o haga clic en el botón Cerrar. Retorna 1 cuando se hace clic sobre el botón Pantalla y retorna un 2 cuando se hace clic sobre el botón Impresora.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

6

FORMA DE UTILIZAR EL FORMULARIO REPORTE Hasta el momento tenemos un reporte diseñado (Programas.frt), un formulario llamado Reportes que permite seleccionar el destino de un reporte y un formulario, diseñado en clases anteriores llamado Programas. En ese formulario, aparece un botón que hasta el momento no se había utilizado, denominado btnReporte. Cuando el usuario haga clic sobre este botón, el sistema debe mostrar una pantalla donde el usuario pueda seleccionar el destino del reporte. Eso es lo programaremos a continuación: Abra el formulario Programa en modo de diseño, ubique el botón btnReporte y haga doble clic sobre este. Busque el evento Clic y escriba el código que se especifica a continuación.

BtnReporte.Click *generar reporte de programas *consultar el destino para el reporte do form forms\reportes to mDestino do case case mDestino = 1 && pantalla report form informes\programa preview case mDestino = 2 && impresora *verificar estado de la impresora if printstatus() && verificar el estado de la impresora report form informes\programa to print noeject noconsole else mMens1 = "La impresora no esta lista. Preparela e intente de nuevo..." +chr(13) mOpc = messagebox( mMens1, 0+48, "Atención!") endif endcase *regresar a la pantalla go top scatter memvar memo thisform.refresh return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

7

Observe que el código incluye la instrucción: do form forms\reportes to mDestino Con ésta orden lo que se hace es invocar al formulario Reportes e indicarle al FoxPro que deseamos almacenar el valor que retorne el formulario en la variable mDestino. El formulario Reportes se ejecuta, permite que el usuario haga su selección, retorna el valor en la variable mDestino, y lo único que resta es verificar el valor retornado. Recuerde que un valor de 1 indica que seleccionaron Pantalla, un valor de 2, Impresora, y un valor de 0, indica que el usuario no seleccionó nada.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

8

LAS CONSULTAS EN LAS APLICACIONES Una de las características potentes en un gestor de bases de datos, lo constituye la capacidad de generar consultas a la información almacenada en las tablas de un sistema de información determinado. La forma en que se puede generar consultas a las tablas son muchas, pero una de las más sencillas y que permiten gran flexibilidad durante la ejecución, son las ofrecidas por la instrucción SELECT-SQL. Esta orden es verdaderamente potente y permite programar instrucciones de consultas en forma fácil. Por ejemplo, se puede diseñar un formulario, unos datos en los cuales se recogen los parámetros de la consulta, y basado en esos datos entrados por el usuario, ejecutar una consulta en tiempo real. Abra el diseñador de formulario con un formulario en blanco y diseñe el siguiente formulario. Cuando termine guárdelo en la carpeta de los formularios con el nombre de SQLProg. El anteponer SQL a los formularios de consulta, hará que estos se agrupen visualmente en el administrador de proyectos, permitiéndonos en un futuro, administrar de forma fácil las pantallas de consultas.

1: mNombreSQL

2: btnEjecutarSQL

3: btnCerrar

El usuario deberá entrar en el campo 1 un texto. Cuando haga clic en el botón Ejecutar Consulta, el sistema ejecutará una instrucción SELECT-SQL y traerá de la tabla PROGRAMA los programas que incluyan en su nombre el texto entrado. FORMULARIO.INIT *abrir entorno utilizando las variables públicas close data mFile1 = _dircia +"programa.dbf" if !file( mFile1) do cPrograma in prg\creartbl endif sele 1 use &mFile1 order tag codigo alias programa return

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

9

En botón ejecutar lanza la consulta en el sistema. Observe el uso que se hace del parámetro entrado por el usuario. Si entra algo, se usa como parámetro, si deja el campo en blanco, simplemente se traen todos los registros. El resultado de la consulta es mostrado en una ventana examinar, que debe ser cerrada con ctrl.+w. BtnEjecutarSQL.Click *ejecutar consulta copn los parámetros entrados mNombreSQL = alltrim( thisform.mNombreSQL.value) if empty( mNombreSQL) select * from programa else select * from programa where mNombreSQL $ programa.nombre endif return

BtnCerrar.Click thisform.release

Por ejemplo, si introducimos como parámetro la palabra “PROG” obtendremos como resultado la siguiente pantalla:

Para cerrar esta pantalla, pulse Ctrl.+W. Aunque en este ejemplo se hizo una búsqueda basado una clase datos, no indica que siempre se tenga que hacer de tal forma. Las posibilidades de programar parámetros son muchas y la capacidad de programar tales ordenes dentro de una instrucción SELECT-SQL hacen de esta orden lo máximo para controlar consultas. Para mayor información acerca de la orden SELECT-SQL, consulte el manual de comandos y funciones del Visual FoxPro.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

10

ANEXO A LA GUÍA DE CLASES – LA INSTRUCCIÓN SELECT – SQL El siguiente texto fue tomado de la ayuda del FoxPro. Recupera datos de una o más tablas. Sintaxis SELECT [ALL | DISTINCT] [TOP nExpresión [PERCENT]] [Alias.] Elemento_Selección [AS Nombre_Columna] [, [Alias.] Elemento_Selección [AS Nombre_Columna] ...] FROM [FORCE] [NombreBaseDatos!]Tabla [Local_Alias] [[INNER | LEFT [OUTER] | RIGHT [OUTER] | FULL [OUTER] JOIN NombreBaseDatos!]Tabla [Alias_Local] [ON CondiciónCombinación …] [[INTO Destino] | [TO FILE NombreArchivo [ADDITIVE] | TO PRINTER [PROMPT] | TO SCREEN]] [PREFERENCE NombrePreferencia] [NOCONSOLE] [PLAIN] [NOWAIT] [WHERE CondiciónCombinación [AND CondiciónCombinación ...] [AND | OR CondiciónFiltro [AND | OR CondiciónFiltro ...]]] [GROUP BY ColumnaGrupo [, ColumnaGrupo ...]] [HAVING CondiciónFiltro] [UNION [ALL] SELECTCommand] [ORDER BY Elemento_Orden [ASC | DESC] [, Elemento_Orden [ASC | DESC] ...]] Argumentos SELECT consulta.

Especifica los campos, constantes y expresiones que se mostrarán en el resultado de la

ALL De forma predeterminada, se muestran todas la filas del resultado de la consulta. DISTINCT Excluye duplicados de cualquier fila del resultado de la consulta. Nota Puede utilizar DISTINCT únicamente una vez por cláusula SELECT. TOP nExpresión [PERCENT] Especifica que el resultado de la consulta contenga un número determinado de filas o un porcentaje de filas en el resultado de la consulta. Es necesario incluir una cláusula ORDER BY si incluye la cláusula TOP. La cláusula ORDER BY especifica las columnas en las que la cláusula TOP determinará el número de filas que se va a incluir en el resultado de la consulta. Puede especificar desde 1 a 32,767 filas. Las filas de valores idénticos para las columnas especificadas en la cláusula ORDER BY se incluyen en el resultado de la consulta. A partir de entonces, si especifica 10 para nExpr, el resultado de la consulta podrá obtener más de 10 filas si hay más de 10 filas con valores idénticos para las columnas especificadas en la cláusula ORDER BY. Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

11

Si se incluye la palabra clave PERCENT, se redondeará al número entero más alto el número de columnas devuelto en el resultado. Los valores permitidos para nExpr cuando se incluye la palabra clave PERCENT son 0.01 a 99.99. Alias. Califica nombres de elementos coincidentes. Cada elemento que especifique con Elemento_Selección genera una columna de los resultados de la consulta. Si dos o más elementos tienen el mismo nombre, incluya el alias de la tabla y un punto antes del nombre del elemento para impedir la duplicación de las columnas. Elemento_Selección especifica un elemento a incluir en el resultado de la consulta. Un elemento puede ser uno de los siguientes: · El nombre de un campo de una tabla de la cláusula FROM. · Una constante especificando que el mismo valor constante ha de aparecer en cada fila del resultado de la consulta. · Una expresión que puede ser el nombre de una función definida por el usuario (FDU). AS Nombre_Columna Especifica el título de una columna en el resultado de la consulta. Esta opción resulta muy útil cuando Elemento_Selección es una expresión o contiene una función de campo y desea dar un nombre significativo a la columna. Nombre_Columna puede ser una expresión pero no puede contener caracteres (por ejemplo, espacios) que no estén permitidos para nombres de campos de tablas. FROM Enumera las tablas que contienen los datos que obtuvo la consulta. Si no hay ninguna tabla abierta, Visual FoxPro mostrará el cuadro de diálogo Abrir para permitirle especificar la ubicación del archivo. Una vez abierta, la tabla permanecerá abierta cuando la consulta se haya terminado. FORCE Especifica que las tablas se combinarán en el orden de aparición en la cláusula FROM. Si se omite FORCE, Visual FoxPro intentará optimizar la consulta. Sin embargo, es posible que la consulta se ejecute más rápido si se incluye la palabra clave FORCE para desactivar la optimización de consultas de Visual FoxPro. NombreBaseDatos! Especifica el nombre de una base de datos inactiva que contiene la tabla. Es necesario incluir el nombre de la base de datos que contiene la tabla en caso de que no sea la base de datos activa. Incluya el delimitador de signo de exclamación (!) después del nombre de la base de datos y antes del nombre de la tabla. Alias_Local Especifica un nombre temporal para la tabla indicada en Tabla. Si especifica un alias local, debe utilizar el alias local en lugar de la tabla a través de todo el SELECT. INNER JOIN Especifica que el resultado de la consulta contenga sólo filas para una tabla con la que coincidan una o varias filas en otra tabla. LEFT [OUTER] JOIN Especifica que el resultado de la consulta contenga todas las filas de la tabla a la izquierda de la palabra clave JOIN y sólo las filas que concuerden procedentes de la tabla a la derecha de la palabra clave JOIN. La palabra clave OUTER es opcional; se puede incluir para resaltar que se ha creado una combinación externa.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

12

RIGHT [OUTER] JOIN Especifica que el resultado de la consulta contenga todas las filas desde la tabla hasta la derecha de la palabra clave JOIN y sólo las filas que concuerden desde la tabla hasta la izquierda de la palabra clave JOIN. La palabra clave OUTER es opcional; puede incluirse para resaltar la creación de una combinación externa. FULL [OUTER] JOIN Especifica que el resultado de la consulta contenga todas las filas, concuerden o no, de ambas tablas. La palabra clave OUTER es opcional; se puede incluir para resaltar que se ha creado una combinación externa. ON CondiciónCombinación Especifica las columnas según las cuales se combinan las tablas. INTO Destino Determina donde se almacenan los resultados de la consulta. Si incluye una cláusula INTO y una cláusula TO en la misma consulta, la cláusula TO se pasará por alto. Si no incluye la cláusula INTO, los resultados de la consulta se mostrarán en la ventana Examinar. Los resultados de la consulta pueden dirigirse también a la impresora o a un archivo mediante la cláusula TO. Destino puede ser uno de los siguientes: · ARRAY NombreMatriz, que almacena los resultados de la consulta en una matriz de variable de memoria. Si la consulta selecciona 0 registros, la matriz no se creará. · CURSOR NombreCursor [NOFILTER], que almacena los resultados de la consulta en un cursor. Si especifica el nombre de una tabla abierta, Visual FoxPro generará un mensaje de error. Después de que se ejecute SELECT, el cursor temporal permanecerá abierto y estará activo pero solamente para lectura. Una vez que cierre este cursor temporal, se borrará. Los cursores pueden existir como un archivo temporal en la unidad SORTWORK. Incluya NOFILTER para crear un cursor que se pueda usar en consultas posteriores. En versiones anteriores de Visual FoxPro, era necesario incluir una expresión o una constante adicional como un filtro para crear un cursor utilizable en consultas posteriores. Por ejemplo, la adición de un Logical verdadero como una expresión de filtro creaba una consulta utilizable en consultas posteriores: SELECT *, .T. FROM customers INTO CURSOR myquery Si se incluye NOFILTER es posible que disminuya el rendimiento de la consulta, puesto que se creará una consulta temporal en el disco. Cuando se cierre el cursor se eliminará del disco la consulta temporal. · DBF | TABLE NombreTabla [DATABASE NombreBaseDatos [NAME NombreLargoTabla]] que almacena el resultado de la consulta en una tabla. Si especifica una tabla que ya esté abierta y SET SAFETY está en OFF, Visual FoxPro sobrescribirá la tabla sin previo aviso. Si no ha especificado ninguna extensión, Visual FoxPro dará una extensión .DBF a la tabla. La tabla permanecerá abierta y activa después de ejecutar SELECT. Incluya DATABASE NombreBaseDatos para especificar una base de datos a la que se agregará la tabla. Incluya NAME NombreLargoTabla para especificar un nombre largo para la tabla. Los nombres largos pueden contener un máximo de 128 caracteres y pueden utilizarse en lugar de nombres cortos en la base de datos. TO FILE NombreArchivo Si incluye una cláusula TO pero no una cláusula INTO, podrá dirigir el resultado de la consulta a un archivo de texto ASCII llamado NombreArchivo, o a la impresora además de al escritorio o la ventana principal de Visual FoxPro.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

13

ADDITIVE añade la salida de la consulta al contenido existente del archivo de texto especificado en TO FILE NombreArchivo. TO PRINTER [PROMPT] Dirige la salida de la consulta a una impresora. Utilice la cláusula PROMPT opcional para que aparezca en pantalla un cuadro de diálogo antes de que empiece la impresión. En este cuadro de diálogo podrá modificar la configuración de la impresora. Los valores de la impresora modificables dependen del controlador de impresora instalado en este momento. Sitúe la palabra clave PROMPT inmediatamente después de TO PRINTER. TO SCREEN Dirige la salida de la consulta a la ventana principal de Visual FoxPro o a una ventana definida por el usuario que esté activa. PREFERENCE NombrePreferencia Guarda los atributos y opciones de la ventana Examinar para uso posterior, si se envía el resultado de la consulta a una ventana Examinar. Emitiendo SELECT con un NombrePreferencia de PREFERENCE, la primera vez se crea la preferencia. Emitiendo posteriormente SELECT con el mismo nombre de preferencia, se restaurará la ventana Examinar con el mismo estado de preferencia. Cuando se cierra la ventana Examinar, se actualiza la preferencia. Si sale de una ventana Examinar presionando CTRL+Q+W, no se guardarán los cambios de la ventana Examinar en el archivo de recurso. NOCONSOLE Impide que el resultado de la consulta se envíe a un archivo, a la impresora o a la ventana principal de Visual FoxPro. PLAIN Impide que aparezcan las cabeceras de las columnas al mostrar la salida de la consulta. PLAIN puede utilizarse tanto si está presente una cláusula TO como si no. Si se incluye una cláusula TO, se pasará por alto PLAIN. NOWAIT Continúa la ejecución del programa después de abrir la ventana Examinar y de dirigir a ella los resultados de la consulta. El programa no esperará a que la ventana Examinar se cierre, sino que continuará con la ejecución de la línea de programa inmediatamente siguiente a la instrucción SELECT. Cuando se incluye TO SCREEN para dirigir la salida hacia la ventana principal de Visual FoxPro o una ventana definida por el usuario, la salida se detiene cuando la ventana principal de Visual FoxPro se llena con resultados de la consulta. Presione una tecla para ver el siguiente conjunto de resultados de la consulta. Si se incluye NOWAIT, los resultados de la consulta se desplazarán fuera del escritorio, la ventana principal de Visual FoxPro o una ventana definida por el usuario sin esperar a que se presione una tecla. NOWAIT se pasa por alto si se incluye con la cláusula INTO. WHERE Indica a Visual FoxPro que incluya únicamente ciertos registros en el resultado de la consulta. WHERE es necesario para recuperar datos de varias tablas. CondiciónCombinación especifica los campos que vinculan las tablas de la cláusula FROM. Si incluye más de una tabla en una consulta, deberá especificar una condición de combinación para cada tabla después de la primera.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

14

Las condiciones de combinación múltiple deben conectarse mediante el operador AND. Cada condición de combinación tiene la forma siguiente: NombreCampo1 Comparación NombreCampo2 NombreCampo1 es el nombre de un campo de una tabla, NombreCampo2 es el nombre de un campo de otra tabla y Comparación es uno de los operadores siguientes: Operador Comparación = Igual == Exactamente igual LIKE SQL LIKE , !=, # Distinto de > Mayor que >= Mayor o igual que < Menor que = 1000

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

15

Ejemplo 3 En el Ejemplo 3 se muestra CondiciónFiltro en el formulario de NombreCampo Comparación ALL (Subconsulta) Cuando la condición de filtro incluye ALL, el campo debe cumplir la condición de comparación para todos los valores generados por la subconsulta antes de que se incluya el registro en el resultado de la consulta. company < ALL ; (SELECT company FROM customer WHERE country = "Reino Unido") Ejemplo 4 En el Ejemplo 4 se muestra CondiciónFiltro en el formulario de NombreCampo Comparación ANY | SOME (Subconsulta) Cuando la condición de filtro incluye ANY o SOME, el campo debe cumplir la condición de comparación en al menos uno de los valores generados por la subconsulta. company < ANY ; (SELECT company FROM customer WHERE country = "Reino Unido") Ejemplo 5 En el Ejemplo 5 se muestra CondiciónFiltro en el formulario de NombreCampo [NOT] BETWEEN Inicio_Rango AND Fin_Rango Este ejemplo comprueba si los valores del campo están dentro de un intervalo de valores especificado. customer.postalcode BETWEEN 90000 AND 99999 Ejemplo 6 En el Ejemplo 6 se muestra CondiciónFiltro en el formulario de [NOT] EXISTS (Subconsulta) Este ejemplo comprueba si al menos una línea cumple los criterios de la subconsulta. Cuando la condición de filtro incluye EXISTS, la condición de filtro se evalúa como verdadera (.T.) a no ser que la subconsulta sea un conjunto vacío. EXISTS ; (SELECT * FROM orders WHERE customer.postalcode =

orders.postalcode)

Ejemplo 7 En el Ejemplo 7 se muestra CondiciónFiltro en el formulario de NombreCampo [NOT] IN Conjunto_Valor Cuando una condición de filtro incluye IN, el campo debe contener uno de los valores antes de que el registro se incluya en los resultados de la consulta. customer.postalcode NOT IN ("98052","98072","98034") Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

16

Ejemplo 8 En el Ejemplo 8 se muestra CondiciónFiltro en el formulario de NombreCampo [NOT] IN ( Subconsulta) Aquí, el campo debe contener uno de los valores devueltos por la subconsulta antes de que su registro se incluya en los resultados de la consulta. customer.cust_id IN ; (SELECT orders.cust_id FROM orders WHERE orders.city="Seattle") Ejemplo 9 En el Ejemplo 9 se muestra CondiciónFiltro en el formulario de NombreCampo [NOT] LIKE cExpresión customer.country NOT LIKE "Reino Unido" Esta condición de filtro busca cada uno de los campos que coinciden con cExpresión. Puede utilizar el signo de porcentaje (%) y subrayado ( _ ) como parte de cExpresión. El signo de porcentaje representa a cualquier secuencia de caracteres desconocidos en la cadena. El subrayado representa un solo carácter desconocido en la cadena. GROUP BY ColumnaGrupo [, ColumnaGrupo ...] Agrupa las filas de la consulta basándose en los valores de una o más columnas. ColumnaGrupo puede ser el nombre de un campo normal de una tabla, o un campo que incluya una función de campo SQL, o una expresión numérica indicando la posición de la columna en la tabla resultado (la columna más a la izquierda tiene el número 1). HAVING CondiciónFiltro Especifica una condición de filtro que los grupos deben satisfacer para quedar incluidos en el resultado de la consulta. HAVING debe utilizarse con GROUP BY. Puede incluir tantas condiciones de filtro como se deseen, conectadas con el operador AND u OR. También puede utilizar NOT para invertir el valor de una expresión lógica. CondiciónFiltro no puede contener una subconsulta. Una cláusula HAVING sin una cláusula GROUP BY actúa como una cláusula WHERE. Puede utilizar alias locales y funciones de campo en la cláusula HAVING. Utilice una cláusula WHERE para acelerar el rendimiento si su cláusula HAVING no contiene funciones de campo. No olvide que la cláusula HAVING debería de aparecer antes de una cláusula INTO porque, de lo contrario, se producirá un error de sintaxis. [UNION [ALL] ComandoSELECT] Combina el resultado final de una SELECT con el resultado final de otra SELECT. De forma predeterminada, UNION comprueba el resultado combinado y elimina las filas duplicadas. Puede utilizar paréntesis para combinar múltiples cláusulas UNION. Utilice la palabra clave opcional ALL para impedir que UNION elimine filas duplicadas de los resultados combinados.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

17

Las cláusulas UNION siguen las reglas siguientes: · No puede utilizar UNION para combinar subconsultas. · La salida de ambos SELECT debe tener el mismo número de columnas. · Cada columna de los resultados de la consulta de un SELECT debe tener el mismo tipo de dato y anchura que su columna correspondiente en el otro SELECT. · Únicamente el SELECT final puede tener una cláusula ORDER BY, que debe referirse a las columnas de salida por su número. Si se incluye otra cláusula ORDER BY, afectará al resultado completo. También puede usar la cláusula UNION para simular una combinación externa. Cuando combina dos tablas en una consulta, solamente se incluyen en la salida los registros que tengan valores coincidentes en los campos de combinación. Si un registro de la tabla primaria no tiene un registro correspondiente en la tabla secundaria, el registro de la tabla primaria no se incluye en la salida. Una combinación externa le permite incluir todos los registros de la tabla primaria en la salida, junto con los registros coincidentes de la tabla secundaria. Para crear una combinación externa en Visual FoxPro, necesita utilizar un comando SELECT anidado, como en el siguiente ejemplo: SELECT customer.company, orders.order_id, orders.emp_id ; FROM customer, orders ; WHERE customer.cust_id = orders.cust_id ; UNION ; SELECT customer.company, " ", " " ; FROM customer ; WHERE customer.cust_id NOT IN ; (SELECT orders.cust_id FROM orders) Nota Asegúrese de incluir el espacio que aparece justo delante de cada punto y coma. De lo contrario, recibirá un error. La sección del comando situada antes de la cláusula UNION selecciona los registros de ambas tablas que contienen valores coincidentes. Las empresas cliente que no tengan facturas asociadas no se incluyen. La sección del comando situada tras la cláusula UNION selecciona los registros de la tabla customer que no tienen registros coincidentes en la tabla orders. En lo que respecta a la segunda sección del comando, observe lo siguiente: · La instrucción SELECT incluida entre paréntesis se procesa en primer lugar. Esta instrucción da como resultado una selección de todos los números de clientes de la tabla orders. · La cláusula WHERE busca todos los números de cliente de la tabla customer que no están en la tabla orders. Puesto que la primera sección del comando proporcionó todas las empresas que tenían un número de cliente en la tabla orders, todas las empresas de la tabla customer están incluidas en los resultados de la consulta. · Puesto que las estructuras de las tablas incluidas en UNION deben ser idénticas, hay dos marcadores de posición en la segunda instrucción SELECT para representar orders.order_id y orders.emp_id de la primera instrucción SELECT. Nota Los marcadores de posición deben ser del mismo tipo que los campos que representan. Si el campo es de tipo Date, el marcador de posición deberá ser { / / }. Si el campo es de tipo Character, el marcador de posición deberá ser la cadena vacía (""). Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

18

ORDER BY Elemento_Orden Ordena el resultado de la consulta basándose en los datos de una o varias columnas. Cada Elemento_Orden debe corresponder a una columna del resultado de la consulta, y puede ser uno de los siguientes: · Un campo de una tabla FROM que también es un elemento de selección en la cláusula principal SELECT (no en una subconsulta). · Una expresión numérica que indica la ubicación de la columna en la tabla resultante. (La columna de la izquierda es la número 1.) ASC Especifica un orden ascendente para los resultados de la consulta, de acuerdo con el elemento o los elementos de orden, y es el valor predeterminado para ORDER BY. DESC Especifica un orden descendente para los resultados de la consulta. Los resultados de la consulta aparecerán desordenados si no especifica un orden con ORDER BY. Comentarios SELECT es un comando SQL que está incorporado en Visual FoxPro como cualquier otro comando de Visual FoxPro. Cuando utiliza SELECT para componer una consulta, Visual FoxPro interpreta la consulta y recupera los datos especificados de las tablas. Puede crear una consulta SELECT: · · ·

En la ventana Comandos En un programa Visual FoxPro (como cualquier otro comando de Visual FoxPro) El Diseñador de consultas

Cuando emite SET TALK ON y ejecuta SELECT, Visual FoxPro muestra la duración de la consulta y el número de registros del resultado. _TALLY contiene el número de registros del resultado de la consulta. SELECT no respeta la condición de filtro actual especificada con SET FILTER. Una subconsulta, a la que se hace referencia en los argumentos siguientes, es un comando SELECT dentro de otro SELECT y debe incluirse entre paréntesis. Puede tener múltiples subconsultas al mismo nivel (no anidadas) en la cláusula WHERE (consulte esta sección de los argumentos). Las subconsultas pueden contener múltiples condiciones de combinación. Cuando se obtiene el resultado de una consulta, las columnas se denominarán según las siguientes reglas: · Si un elemento seleccionado es un campo con un nombre único, el nombre de la columna de resultado es el nombre del campo. · Si hay más de un elemento seleccionado con el mismo nombre, se añadirán un signo de subrayado y una letra al nombre de la columna. Por ejemplo, si una tabla llamada Cliente tiene un campo llamado CALLE, y una tabla llamada Empleados también tiene un campo llamado CALLE, las columnas de resultado se llamarán Extensión_A y Extensión_B (CALLE _A y CALLE _B). En el caso de un elemento seleccionado con un nombre de 10 caracteres, se truncará el nombre para añadir el símbolo de subrayado y la letra. Por ejemplo, DEPARTMENT se convertiría en DEPARTME_A. · Si un elemento seleccionado es una expresión, su columna de resultado se llamará EXP_A. Cualquier otra expresión recibirá el nombre de EXP_B, EXP_C, y así sucesivamente. · Si un elemento seleccionado contiene una función de campo como, por ejemplo, COUNT( ), la columna de resultado se llamará CNT_A. Si otro elemento seleccionado contiene SUM( ), su columna de resultado se llamará SUM_B. Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7

19

Funciones definidas por el usuario con SELECT Aunque la utilización de funciones definidas por el usuario en la cláusula SELECT ofrece unas ventajas evidentes, también debería tener en cuenta las siguientes limitaciones: · Es posible que la velocidad de realización de las operaciones con SELECT se vea limitada por la velocidad a la que se ejecutan las funciones definidas por el usuario. Las manipulaciones de un gran volumen que impliquen funciones definidas por el usuario se pueden realizar mejor utilizando funciones API y funciones definidas por el usuario escritas en C o en lenguaje ensamblador. · No se puede prever nada acerca de la entrada/salida de Visual FoxPro (E/S) ni del entorno de la tabla en funciones definidas por el usuario invocadas a partir de SELECT. Generalmente, no se puede saber qué área de trabajo se ha seleccionado, ni el nombre de la tabla actual, ni los nombres de los campos que se están procesando. El valor de dichas variables depende del lugar específico, dentro del proceso de optimización, en el que se invoque la función definida por el usuario. · En funciones definidas por el usuario invocadas desde SELECT, no es seguro cambiar la E/S de Visual FoxPro ni el entorno de la tabla. Por norma general, los resultados son impredecibles. · La única forma segura de pasar valores a funciones definidas por el usuario invocadas desde SELECT es mediante la lista de argumentos pasada a la función cuando es invocada. · Si prueba y descubre una manipulación teóricamente prohibida que funciona correctamente en una versión determinada de FoxPro, eso no significa que también funcione en versiones posteriores. Salvando dichas limitaciones, las funciones definidas por el usuario son aceptables en la cláusula SELECT. Sin embargo, recuerde que la utilización de SELECT puede ralentizar el rendimiento. Las siguientes funciones de campo están disponibles para ser utilizadas con un elemento seleccionado que sea un campo o una expresión que implique a un campo: · AVG(Elemento_Selección), que realiza una media de una columna de datos numéricos. · COUNT(Elemento_Selección), que cuenta el número de elementos seleccionados en una columna. COUNT(*) cuenta el número de filas en el resultado de la consulta. · MIN(Elemento_Selección) determina el menor valor de Elemento_Selección en una columna. · MAX(Elemento_Selección) determina el mayor valor de Elemento_Selección en una columna. · SUM(Elemento_Selección) que proporciona el total de la suma de una columna de datos numéricos. No se pueden probar las funciones de campo. Combinaciones Visual FoxPro acepta sintaxis de combinación de 1992 SQL ANSI, lo que le permite crear consultas que vinculen las filas en dos o más tablas mediante la comparación de los valores de campos especificados. Por ejemplo, una combinación interna selecciona filas procedentes de dos tablas sólo cuando los valores de los campos combinados son iguales. Visual FoxPro admite combinaciones anidadas. Dado que SQL se basa en la teoría de conjuntos matemática, se puede representar a cada tabla con un círculo. La cláusula ON que especifica las condiciones de la combinación determina el punto de intersección, el cual representa el conjunto de filas que coinciden. En el caso de una combinación interna, la intersección tendrá lugar en el interior o en una parte “interna” de los dos círculos. Una combinación externa incluye tanto las filas coincidentes que se han encontrado en la sección de intersección interna de las tablas, como las filas de la parte externa del círculo a la izquierda, o a la derecha, de la intersección.

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #7 Importante

20

Tenga presente la siguiente información a la hora de crear condiciones de combinación:

· Si incluye dos tablas en una consulta y no especifica una condición de combinación, cada registro de la primera tabla se combinará con cada registro de la segunda tabla hasta que surtan efecto las condiciones del filtro. Una consulta tal puede producir unos resultados interminables. · Sea prudente al utilizar, en condiciones de combinación, funciones tales como DELETED( ), EOF( ), FOUND( ), RECCOUNT( ), y RECNO( ), que aceptan un área de trabajo o un alias opcional. La inclusión de un alias o de un área de trabajo en dichas funciones puede producir resultados inesperados. SELECT no utiliza sus áreas de trabajo; realiza lo equivalente a USE ... AGAIN. Las consultas de una única tabla que utilizan estas funciones sin un área de trabajo o un alias opcional, tendrán resultados correctos. De todas formas, las consultas de varias tablas que utilicen dichas funciones (incluso sin un área de trabajo o un alias opcional) pueden tener resultados inesperados. · Sea prudente al combinar tablas que contengan campos vacíos porque Visual FoxPro concuerda campos vacíos. Por ejemplo, si combina CUSTOMER.ZIP e INVOICE.ZIP, y CUSTOMER contiene 100 códigos postales vacíos e INVOICE contiene 400 códigos postales vacíos, el resultado de la consulta contendrá 40.000 registros más, como resultado de los campos vacíos. Use la funció n EMPTY( ) para eliminar los registros vacíos del resultado de la consulta. Para obtener más información sobre combinaciones, consulte “Definición y modificación de condiciones de combinación” en el capítulo 8, “Creación de vistas”, en el Manual del programador.

Instituto Metropolitano de Educación

INSTITUTO METROPOLITANO DE EDUCACIÓN PROGRAMACIÓN DE COMPUTADORES GUIA #8 DE VISUAL FOXPRO DOCENTE: MAURICIO CANO

EL SISTEMA COMPLETO Hasta el momento hemos generado formularios, reportes y consultas, partes básicas de un sistema de información automatizado. Para que ese sistema esté completo, agregaremos el menú principal, el formulario de entrada (clave de acceso) y las utilidades del sistema. Como paso final, aprenderemos a compilar la aplicación, generar un programa autoejecutable (.EXE) y los respectivos discos de instalación del proyecto.

EL GENERADOR DE MENUS DEL FOXPRO El FoxPro tiene un generador de menús que permite crear, probar y generar el código de un menú para agregar a nuestra aplicación. El docente explicará el manejo de este potente generador de menús.

El menú creado en clase debe llamarse “MENUPPAL” y debe crearse en la pestaña OTROS del administrador de proyectos en la sección Menús. Cuando modifique las opciones del menú, recuerde siempre ejecutar la opción Menú/Generar. Esta opción genera un archivo de código con las órdenes suficientes para crear nuestro sistema de menús. El archivo de código fuente quedará almacenado con el mismo nombre del menú y la extensión .MPR. Este es el programa que ejecutaremos desde cualquier formulario o programa para cargar el menú en el sistema (MENUPPAL.MPR). Por el momento diseñaremos el siguiente menú principal: Maestros Programas Asignaturas

Secretaría Hojas de vida Matrícula

Profesor

Grupos

Utilidades Indexar Copias de soporte Restaurar datos Empresas del sistema Usuarios del sistema

Salir Ventana de Comandos

Instituto Metropolitano de Educación

Visual FoxPro - Guía de Clases #8

2

Las opciones Programas, Asignaturas, Profesor, respectivamente un submenú con las opciones:

Hojas

de

vida,

Matrícula

y

Grupos,

tienen

Actualizar Consultar El entorno de trabajo del generador de reportes es bastante sencillo de manipular. Para pasar de un submenú a otro, recuerde hacerlo haciendo clic en la lista desplegable Nivel de Menú . Para verificar el funcionamiento del sistema de menús diseñado, haga clic en el botón Vista Previa.

Una tecla caliente (Hot Key) se programa anteponiendo los signos \< antes de la letra que uno desea programar como la tecla caliente. Por ejemplo, \