La Guía del programador contiene información útil para escribir aplicaciones de dBASE.
Está concebida para ayudar a trabajar en Visual dBASE a los usuarios que tienen poca o
nula experiencia de programación. Si ya tiene experiencia de programación, este
manual le puede servir como una introducción acelerada al lenguaje dBASE.
La Guía del programador y la Referencia del lenguaje son libros complementarios; juntos,
describen el lenguaje dBASE y proporcionan información para escribir programas de
aplicación en dBASE.
• La Referencia del lenguaje contiene información detallada sobre la sintaxis y
funcionalidad de cada elemento del lenguaje, cuyo uso se demuestra de forma
individual con ejemplos de código.
• La Guía del programador contiene introducciones conceptuales, descripciones de tareas
y ejemplos que abarcan a grupos de elementos del lenguaje. Utilice este manual para
crear aplicaciones de Visual dBASE con interfaces de usuario controlados por sucesos
mediante un diseño orientado a objetos.
La Tabla Intro.1 proporciona ejemplos de dónde buscar diferentes tipos de información
referente al lenguaje dBASE.
Tabla Intro.1 Lo que necesita y dónde encontrarlo
Ejemplo de lo que necesita Dónde encontrarlo
Un ejemplo del uso de la función TAGNO() Referencia del lenguaje
Un ejemplo que muestre cómo se complementan las funciones Guía del programador
de índice
Una lista de las propiedades de la clase Form Referencia del lenguaje
Una descripción de cómo funciona un programa controlado por Guía del programador
sucesos
La longitud máxima de un nombre de variable de memoria Referencia del lenguaje
Una explicación de los diferentes ámbitos de las variables de Guía del programador
memoria
Introducción 1
intro.dwp Page 2 Friday, December 1, 1995 7:01 PM
Nota Para usuarios zurdos, Windows permite invertir la función de los botones del ratón.
Si lo hace, lea “derecho” donde dice “izquierdo” (y viceversa) en la Tabla Intro.2.
Introduction 3
intro.dwp Page 4 Friday, December 1, 1995 7:01 PM
Capítulo
Introducción a la programación
Capítulo 1
1
en dBASE
Bienvenido a Visual dBASE, el lenguaje de desarrollo de aplicaciones más productivo
para el entorno Windows. El lenguaje dBASE se ha mejorado significativamente en
Visual dBASE. Este capítulo presenta las novedades más importantes del lenguaje y le
indica dónde se describe cada una en este manual.
Para ayuda sobre la ejecución de aplicaciones de dBASE DOS, consulte el Apéndice A.
Para ayuda sobre la mejora de estas aplicaciones con las características de Windows,
consulte el Apéndice B.
Objetos y clases
Los objetos son un medio de encapsular conjuntos de variables, algunos de los cuales
contienen datos, mientras que otros hacen referencia a código. Las clases son un
mecanismo para crear grupos reutilizables de objetos. Con Visual dBASE, es posible:
• Crear objetos a partir de clases estándar o de clases declaradas por el usuario.
• Añadir propiedades personalizadas a un objeto con una sentencia de asignación
simple.
Fichas
En Visual dBASE, las aplicaciones se construyen creando las fichas que constituyen el
interface de usuario.
Ventanas de ficha
Mediante las clases estándar, es posible crear cualquiera de las ventanas de
visualización estándar para pantallas de introducción de datos, cuadros de diálogo y
cuadros de mensaje. Definiendo unas pocas propiedades, es posible hacer que las fichas
puedan maximizarse, minimizarse, moverse, cambiar de tamaño y tener otras
características. Ábralas con READMODAL( ) para que tengan un control exclusivo del
escritorio; ábralas con OPEN( ) para activar un interface de usuario totalmente
controlado por sucesos. El Capítulo 13 compara los enfoques que pueden plantearse al
crear aplicaciones con las fichas.
Controladores de sucesos
Las ventanas de ficha, y los objetos que contienen, reconocen y pueden responder de
forma automática a sucesos, que son acciones iniciadas por el usuario o el sistema. Es
posible definir cómo responde la ficha a los sucesos mediante la definición de
controladores de sucesos, es decir, procedimientos que se ejecutan cuando tiene lugar un
suceso. Para una introducción sobre cómo funcionan los programas controlados por
sucesos, consulte el Capítulo 2. Para información sobre cómo escribir controladores de
sucesos, consulte el Capítulo 14.
Sesiones
Un nuevo comando, CREATE SESSION, le permite encapsular tablas con fichas
mediante la creación de un nuevo conjunto de áreas de trabajo (con punteros de registro
distintos) dedicadas exclusivamente a la ficha, como si hubiera iniciado otra copia de
dBASE. En un entorno controlado por sucesos, donde el usuario puede cambiar entre
tareas y abrir y cerrar tablas libremente, una sesión es similar a otro usuario en un
sistema de varios usuarios. Para más información sobre la programación para un
entorno compartido, consulte el Capítulo 21.
Entorno Windows
El entorno Windows proporciona muchas características (DDE, OLE) y recursos
compartidos (controladores de impresora y fuentes) que puede utilizar para mejorar sus
aplicaciones.
Fuentes de Windows
El entorno Windows permite el uso de fuentes comunes que pueden compartir todas las
aplicaciones Windows.
Visual dBASE permite el uso de las fuentes de Windows. Es posible mostrar el texto en
pantalla o en la impresora con cualquier fuente instalada, y personalizar el aspecto del
texto de pantalla con propiedades de fuentes, como FontBold, FontItalic o
FontUnderline. El Capítulo 8 de Referencia del lenguaje describe las propiedades de las
fuentes.
DDE y OLE
El Intercambio dinámico de datos (DDE) es una característica de Windows que permite
que dos aplicaciones compartan e intercambien datos e instrucciones. Visual dBASE
permite el uso de DDE como cliente y como servidor. Para más información sobre DDE,
consulte el Capítulo 27.
Otra función de intercambio de datos, Vinculación e incrustación de objetos (OLE), le
permite utilizar aplicaciones externas directamente desde una tabla o ficha de dBASE.
Incluso es posible controlar otra aplicación desde Visual dBASE mediante la
automatización OLE. Para más información sobre OLE, consulte la Guía del usuario.
Tablas
Las tablas son el medio principal de guardar datos en Visual dBASE. En Visual dBASE,
un solo archivo de datos se denomina tabla, y se conoce como base de datos a un
conjunto de tablas y otros archivos asociados.
Visual dBASE añade varias características nuevas para trabajar con las tablas en los
programas.
Soporte SQL
Visual dBASE permite el uso de SQL para trabajar con tablas locales, así como tablas de
bases de datos SQL. Tanto si trabaja con tablas dBASE o Paradox locales, como con
datos SQL en un servidor de base de datos, tiene la opción de utilizar sintaxis de dBASE
o de SQL.
Visual dBASE permite la creación de vistas actualizables de datos de servidor SQL
mediante SQL incrustado. Para más información, consulte el Capítulo 23.
Fichas escalables
Visual dBASE permite transparentemente el uso de bases de datos de servidores de
dBASE, Paradox y SQL. Las fichas y aplicaciones pueden adaptarse fácilmente para
trabajar con datos locales o de servidor, normalmente con sólo cambiar la base de datos
a que señalan.
Integridad referencial
Nuevas opciones del comando SET RELATION aplican una estricta integridad
referencial entre tablas .DBF relacionadas. La opción CONSTRAIN limita el acceso de la
tabla secundaria a los registros que coinciden con la principal. Así, no es necesario un
filtro adicional en la tabla secundaria. La opción INTEGRITY CASCADE borra
automáticamente los registros secundarios cuando se borra el registro principal
correspondiente, mientras que INTEGRITY RESTRICTED impide el borrado de los
registros secundarios si el principal aún existe. Visual dBASE también permite el uso de
las funciones de integridad referencial de las tablas Paradox. Además, cuando se trabaja
con una tabla de servidor de base de datos, Visual dBASE permite el uso de diccionarios
de datos y reglas de integridad referencial de las bases de datos de servidor. Para más
información, consulte el Capítulo 19.
Seguridad
Visual dBASE permite el cifrado de tablas de dBASE y la seguridad con contraseñas a
nivel de aplicación, tabla y campo. Visual dBASE también permite el uso de la seguridad
con contraseñas en las tablas de Paradox y de la seguridad en servidores de base de
datos. Para más información sobre la definición de seguridad, consulte la
Guía del usuario.
Indicadores
Las tablas de Paradox y SQL no tienen números de registro fijos como las de dBASE. Los
indicadores proporcionan toda la funcionalidad del número de registro de dBASE a las
tablas de Paradox, SQL y dBASE. La función BOOKMARK( ) establece un puntero a un
registro que puede utilizarse como si se tratara de un número de registro. Los
indicadores tienen la ventaja de que sus valores siempre se basan en el orden actual de
los registros de una tabla, por lo que la comparación de los valores de BOOKMARK( )
con >, = ó < indicará la posición relativa de dos registros en el orden del índice actual.
Para más información, consulte el Capítulo 23.
Programación general
Las siguientes son algunas de las nuevas características de programación general
añadidas en dBASE.
Preprocesador
Visual dBASE tiene un preprocesador incorporado similar al utilizado en los
compiladores de lenguaje C. Cuando se compila un programa, el preprocesador explora
el código en busca de directivas de preprocesador y las evalúa, generando un archivo
intermedio temporal que compila el compilador. Mediante el uso de directivas de
preprocesador en el código, es posible insertar archivos de programa, definir constantes,
expandir expresiones y realizar una compilación condicional. El preprocesador concede
al programador un mayor control sobre el proceso de compilación. Para más
información, consulte el Capítulo 7.
Depurador
El Depurador incorpora un completo conjunto de utilidades de depuración. Los puntos
de evaluación, los puntos de ruptura, el código fuente y la pila de llamada pueden verse
todos al mismo tiempo o de forma individual. Un potente inspector le permite ver las
variables, campos y objetos y cambiar sus valores durante la ejecución. Para más
detalles sobre el uso del Depurador, consulte el Capítulo 8.
Matrices versátiles
Visual dBASE añade nuevas y versátiles características a las matrices. Es posible:
• Declarar matrices con cualquier número de dimensiones.
• Añadir, borrar, ordenar y buscar elementos de una matriz con nuevas funciones
como AINS( ), ADEL( ), ASORT( ) y ASCAN( ), y muchas otras.
• Trabajar con matrices como objetos accediendo a sus propiedades y métodos.
• Crear matrices dispersas con un número variable de elementos no contiguos.
• Crear matrices asociativas que utilizan etiquetas de texto, en lugar de números, para los
índices de los elementos.
Para más información sobre las nuevas funciones de matrices, consulte el Capítulo 5.
El Capítulo 10 describe cómo trabajar con matrices como objetos, incluyendo la creación
de matrices dispersas.
Análisis de cobertura
El análisis de cobertura es una característica potente que le informa exactamente de qué
secciones de código se activan cuando se ejecuta un programa. Esta información es
esencial en la mejora de protocolos de pruebas y para garantizar que se han
comprobado todas las partes de una aplicación. El Analizador de cobertura de
Visual dBASE es una de las pocas utilidades de análisis no intrusivas de su especie para
lenguajes de desarrollo de aplicaciones. Para más detalles, consulte el Capítulo 3.
Amplias capacidades
Las amplias capacidades de Visual dBASE —el número de campos de una tabla, el
número de áreas de trabajo activas, la longitud de los nombres de variables de
memoria— se han diseñado para que nunca sean un impedimento en el desarrollo de
aplicaciones. Para ver una lista de capacidades, consulte el Apéndice B de la
Referencia del lenguaje.
Parte
I
Conceptos básicos de programación
Parte I
Esta parte presenta los programas controlados por sucesos y trata los temas generales de
programación en dBASE.
Si nunca antes ha programado en dBASE:
1 Lea el Capítulo 2 para una introducción básica.
2 Lea los apartados relacionados con la creación y compilación de programas en el
Capítulo 3.
3 Lea los Capítulos 4, 5 y 6 para aprender los principios fundamentales sobre la
escritura de código de dBASE.
Esta sección contiene los siguientes capítulos:
• Capítulo 2, “Principios de la programación en dBASE”
• Capítulo 3, “Creación, compilación y comprobación de programas”
• Capítulo 4, “Uso de los procedimientos y bloques de código”
• Capítulo 5, “Uso de las variables de memoria”
• Capítulo 6, “Uso de los tipos de datos”
• Capítulo 7, “Uso de las directivas de preprocesador”
• Capítulo 8, “Depuración de programas”
Capítulo
Principios de la programación
Capítulo 2
2
en dBASE
Este capítulo presenta los programas controlados por sucesos, describe cómo funcionan
y ofrece una introducción al proceso de crear programas controlados por sucesos con
Visual dBASE.
Para ayuda sobre la ejecución de aplicaciones de dBASE DOS, consulte el Apéndice A.
Para mostrar los datos con otro estilo tipográfico u otro tamaño, seleccione el objeto y
defina sus propiedades de fuente. Para mostrar una imagen gráfica en una ficha,
arrastre un objeto de imagen desde la Paleta hasta la ficha y vincúlelo a un archivo de
mapa de bits o a un campo memo.
El Capítulo 14 describe paso a paso cómo escribir controladores de sucesos y vincularlos
a sucesos con el Diseñador de fichas. Para una introducción general al Diseñador de
fichas y sus utilidades, consulte el Capítulo 8 de la Guía del usuario.
El resultado de programar visualmente son aplicaciones fáciles de crear y fáciles de
usar. Y son fáciles de usar porque están controladas por sucesos.
Factura
Factura Archivo Edición Ayuda
Buscar. . .
Cliente Cliente
Buscar cliente Elegir
Artº Cantidad Precio Artº Cantidad Precio Edición|Buscar
TOTAL TOTAL
PAGADO
Marcar como Pagado Hacer clic en el
pagado botón “Pagado”
El controlador de sucesos
OnClick del botón se
ejecuta cuando el usuario
hace clic en él.
El código siguiente, un archivo .WFM generado por el Diseñador de fichas, crea la ficha
que se muestra en la Figura 2.2. Este código sigue la estructura general de todas las
fichas generadas por el Diseñador de fichas. De momento, no intente comprender todas
las líneas. Observe solamente la estructura general para tener una idea de cómo se crean
las fichas, se definen las propiedades y se asignan controladores a los sucesos.
LOCAL f
f = NEW Hello()
f.Open()
CLASS Hello OF Form
This.Text = "My first dBASE form"
This.Width = 50
This.Top = 4
This.Left = 54
This.Height = 15
DEFINE Text Text1 OF This;
PROPERTY;
ColorNormal "N/W",;
FontSize 23,;
Height 3,;
Left 11,;
Text "Hello world!",;
Top 3,;
Width 33
DEFINE PushButton Button1 OF This;
PROPERTY;
Height 2,;
Left 19,;
OnClick Class::Button1_OnClick,;
StatusMessage "Click button to exit",;
Text "Goodbye",;
Top 9,;
Width 13
PROCEDURE Button1_OnClick
DO WHILE (Form.Height > 0) .AND. (Form.Width > 0)
Form.Text1.Text = "Goodbye"
Form.Height = Form.Height - 1
Form.Width = Form.Width - 1
Form.Top = Form.Top + .5
Form.Left = Form.Left + .5
ENDDO
Form.Close()
RETURN
ENDCLASS
Capítulo
Creación, compilación y
Capítulo 3
3
comprobación de programas
Visual dBASE permite tanto la programación procedural mediante un editor de texto
como la programación visual interactiva mediante el Diseñador de fichas y el Diseñador
de consultas. Es posible combinar los dos sistemas de programación en el mismo
programa e integrar código generado por el Diseñador de fichas en las estructuras de
programación tradicionales de dBASE para crear aplicaciones con interfaces de usuario
al estilo de Windows.
Este capítulo trata la creación de archivos de programa, las convenciones estilísticas de
programación, la compilación con comparación automática de la fecha de los archivos,
la compilación con análisis de cobertura y la comprobación de programas.
• Divida las sentencias largas. El editor de textos de dBASE permite 1024 bytes en una
línea de código; no obstante, no es una longitud adecuada para su visualización en
pantalla o su impresión. Para dividir las sentencias de código largas, emplee el
carácter de continuación de dBASE, el signo de punto y coma (;). Cuando se pone un
punto y coma al final de una línea de programa seguido por un retorno de carro o un
carácter de avance de línea, dBASE continúa en la línea siguiente antes de interpretar
la sentencia del programa.
• Utilice los nombres y las mayúsculas de forma coherente en los elementos del lenguaje.
dBASE no distingue entre mayúsculas y minúsculas, por lo que puede utilizarlas
para mejorar la legibilidad de las variables de memoria y los nombres de campo. Esto
es optativo; si tiene experiencia programando en C y está acostumbrado a distinguir
entre mayúsculas y minúsculas, quizá no le sea conveniente.
Comience las variables de memoria con los mismos caracteres, ya que podrá buscar
sus nombres con caracteres comodín para encontrarlas con mayor facilidad y de
forma secuencial.
• Utilice notación que identifique el ámbito y tipo de las variables de memoria. Hay cuatro
ámbitos diferentes para las variables de memoria en Visual dBASE: local, estático,
público y privado. Pueden combinarse con los tipos de datos de carácter, numérico,
fecha y lógico para crear prefijos de dos letras al objeto de lograr nombres de
variables de memoria significativos, por ejemplo:
ll_pagado && variable lógica local
ne_Balance && variable numérica estática
cl_archtempo && variable carácter local
Nota dBASE utiliza un carácter de subrayado inicial en los nombres de sus variables
predefinidas, a las que se denomina variables de memoria del sistema. Para evitar la
duplicación, no utilice el subrayado inicial en los nombres de sus variables.
Compilación de programas
Después de terminar de escribir un programa, necesita compilar el archivo de texto en
un archivo de código objeto. En este capítulo, compilación y ejecución hacen referencia a
programas que funcionan en el entorno interpretado de dBASE. Estos archivos objeto
compilados contienen pseudocódigo (también llamado pcódigo o tokens). En general,
estos programas precisan que se ejecute dBASE y son diferentes de los programas que
están compilados al nivel del sistema operativo y pueden ejecutarse como aplicaciones
independientes en ordenadores que pueden no tiener dBASE. Si requiere la capacidad
de distribuir programas a usuarios que quizá no dispongan de Visual dBASE, los
archivos de código objeto de dBASE pueden vincularse en un ejecutable Windows
mediante el compilador opcional de Visual dBASE.
Dependiendo del tipo de código que esté escribiendo o generando con las utilidades de
diseño, dBASE emplea diferentes extensiones de archivo por defecto. Dado que estas
extensiones son significativas para el compilador e implican relaciones entre código
fuente y código compilado, no debería cambiarlas.
No utilice ninguna extensión que termine con la letra o para los nombres de los archivos
fuente de sus programas. Si lo hace, cuando compile el programa, el archivo objeto lo
sustituirá. Los archivos objeto compilados están en formato binario y no pueden
visualizarse ni modificarse.
Por defecto, dBASE crea archivos objeto compilados en el mismo directorio en que se
encuentren los archivos de código fuente. Las extensiones por defecto del código fuente
y del código compilado se muestran en la Tabla 3.1.
Tabla 3.1 Extensiones por defecto de los archivos de programa fuente y objeto
Extensión de archivo Extensión de
Descripción de archivo de código fuente archivo compilado
Archivo de programa .PRG .PRO
Archivo de ficha generada .WFM .WFO
Archivo de consulta .QBE .QBO
generada
Archivo de menú generado .MNU .MNO
Archivo de menú de .POP .POO
ventana generado
Archifo de ficha .CFM .CFO
personalizada
Archivo de control .CC .CO
personalizado
Archivo de ficha de .FMT .FMO
dBASE IV
Archivo de informe de .FRG .FRO
dBASE IV
Archivo de etiqueta de .LBG .LBO
dBASE IV
Los tipos de archivo de dBASE DOS no pueden crearse en Visual dBASE, pero sí se
permite su uso al objeto de lograr la compatibilidad con versiones anteriores.
Hay varios comandos de dBASE que compilan archivos de programa. COMPILE crea
programas a partir de uno o más archivos sin ejecutar el código objeto resultante. Los
comandos siguientes compilan un programa como parte de su acción:
• DO compila un programa y lo ejecuta si la compilación se produce sin errores.
• SET PROCEDURE TO <archivo> busca un archivo de programa ya compilado. Si no
encuentra un archivo .PRO, compila un archivo .PRG.
COMPILE tiene varias ventajas sobre la compilación de archivos con DO o SET
PROCEDURE.
• COMPILE no ejecuta ni abre los archivos especificados.
• COMPILE acepta caracteres comodín en los nombres de archivo y puede compilar
archivos relacionados o no relacionados.
• COMPILE tiene una opción AUTO que compila los archivos de programa llamados
por los programas que compila explícitamente.
• COMPILE puede crear un archivo de respuesta para el compilador opcional si éste
está instalado. Para más información sobre esta opción, consulte la sección que trata
de la creación de ejecutables.
Cuando se compila un programa, dBASE detecta todos los errores de sintaxis existentes
en el archivo fuente y muestra un mensaje de error en el cuadro de diálogo Error, donde
se muestran cuatro botones que puede seleccionar como respuesta al mensaje de error
durante la compilación:
• El botón Cancelar cancela la compilación. Equivale a pulsar Esc.
• El botón Ignorar cancela la compilación del programa que contiene el error de
sintaxis pero continúa compilando los demás archivos que cumplan el filtro de
caracteres comodín, si ha utilizado uno.
• El botón Solucionar abre el código fuente en una ventana de edición y sitúa el punto
de inserción en la línea de código en que se produjo el error de sintaxis.
• El botón Ayuda proporciona ayuda contextual.
Creación de ejecutables
Si dispone del compilador opcional de Visual dBASE, puede vincular los archivos de
código objeto que constituyen una aplicación, así como otros tipos de archivos que
requiera el programa, en un ejecutable Windows (.EXE). Si realiza apliaciones que van a
utilizar otras personas, el compilador de Visual dBASE ofrece varias ventajas:
• El usuario no necesita una copia de Visual dBASE para ejecutar la aplicación.
• El programador tiene derechos de distribución gratuitos (sin tener que pagar
derechos de autor) e ilimitados para la aplicación.
• Para ejecutar la aplicación, es necesario distribuir muchos menos archivos.
• Hay menos posibilidades de que un usuario corrompa accidentalmente el entorno
del programa, porque la ventana de comandos y los menús de Visual dBASE no están
disponibles.
• Los programas tienen un aspecto más profesional porque los usuarios no tienen
necesidad de comenzar un sistema aparte en tiempo de ejecución para utilizar la
aplicación.
Consulte la documentación que acompaña al compilador de Visual dBASE para obtener
información específica sobre la generación de ejecutables.
Comprobación de programas
La comprobación de un programa implica ejercitar todos sus módulos y forzar sus
límites para localizar errores y debilidades en el programa. Mediante la comprobación,
puede asegurarse de disponer de la gestión de errores adecuada para los casos en que el
programa reciba datos inadecuados —por ejemplo, que muestre un mensaje de error
cuando el usuario introduzca valores numéricos en un campo de texto—.
Para comprobar una aplicación de Visual dBASE, necesita comprobar datos en las tablas
que utiliza la aplicación y también debe saber qué partes de la misma se ejecutan en
realidad al ejecutarla. Existen dos comandos que proporcionan esas capacidades:
GENERATE y SET COVERAGE.
La depuración es otra forma de comprobar la presencia de errores y puntos débiles en
un programa. El Depurador de Visual dBASE dispone de potentes utilidades de
depuración para seguir la ejecución del programa. Para una descripción del Depurador,
consulte el Capítulo 8.
Bloques lógicos
Los archivos de cobertura son archivos binarios que contienen información acumulativa
sobre cuántas veces accede y sale Visual dBASE (y por tanto ejecuta por completo) de
cada bloque lógico de un programa. Los bloques lógicos no incluyen líneas comentadas ni
líneas de comandos de control de flujo, como IF y ENDIF. Por el contrario, sí incluye las
líneas de comandos situadas dentro de esas líneas de comandos de flujo.
Si un programa no contiene comandos de control de flujo (IF...ENDIF, DO
WHILE...ENDDO, FOR...NEXT, SCAN...ENDSCAN, DO CASE...ENDCASE,
DO...UNTIL), el programa tiene un único bloque lógico que consiste en todas las líneas
de comandos, excluidas las de comentarios.
El archivo de cobertura identifica los bloques lógicos por su número o números
correspondientes de línea de programa. Por ejemplo, los comentarios del programa
siguiente indican qué líneas identificaría el análisis de cobertura como bloques lógicos.
(Esto no es lo que se genera en un archivo de cobertura.)
* ACTUALI.PRG
SET TALK OFF && Línea 2, Bloque 1 (Líneas 2-3)
USE Cliente INDEX Vendedor
SCAN
DO CASE
CASE Vendedor = "S-12"
SELECT 2 && Línea 7, Bloque 2 (Líneas 7-8)
USE S12
CASE Vendedor = "L-5"
SELECT 2 && Línea 10, Bloque 3 (Líneas 10-11)
USE L5
CASE Vendedor = "J-25"
SELECT 2 && Línea 13, Bloque 4 (Líneas 13-14)
USE J25
ENDCASE
DO Cambios && Línea 16, Bloque 5 (Líneas 16-17)
SELECT 1
ENDSCAN
CLOSE ALL && Línea 19, Bloque 6 (Líneas 19-20)
SET TALK ON
Capítulo
Declaración de procedimientos
Para declarar un procedimiento en un programa, es necesario codificarlo, compilarlo
para comprobar que se ejecuta sin errores y, entonces, copiarlo al final del archivo de
programa. O bien, puede crear un archivo de procedimiento aparte que contenga
muchas subrutinas que utilice con frecuencia.
La primera línea de un procedimiento es PROCEDURE <nombre procedimiento>.
Escriba, a continuación, las sentencias que realizan la tarea. La última línea del
procedimiento es RETURN.
Para la descripción completa del comando RETURN, consulte la Referencia del lenguaje.
Sitúe los procedimientos en el archivo de programa en que desea llamar el
procedimiento.
El ejemplo siguiente declara un procedimiento que avanza por una tabla de registro en
registro. En lugar de repetir estas sentencias en el programa cada vez que desea
desplazarse por una tabla, puede incluir la sentencia DO SaltaRegs o anexar el
procedimiento al suceso OnClick de un botón llamado Registro siguiente.
PROCEDURE SaltaRegs
SKIP && Salta al siguiente registro si es posible
IF EOF() && Si es el final del archivo
GO TOP && Ir al primer registro de la tabla
ENDIF
RETURN
Declaración de parámetros
Los parámetros cambian el comportamiento de un procedimiento haciendo que éste
funcione con muchos valores diferentes. Los parámetros permiten modificar el valor
devuelto cambiando los valores que se transmiten al procedimiento para su proceso. La
transmisión de parámetros suele utilizarse para enviar valores a un procedimiento y
devolver valores al programa que lo llamó.
Los parámetros son una o más variables de memoria que se mencionan en la
declaración de un procedimiento con la intención de pasarle valores. Los parámetros
modifican el comportamiento del procedimiento o intercambian valores con otros
módulos del programa.
Los parámetros se declaran en un procedimiento encerrándolos entre paréntesis
después del nombre del procedimiento. Cuando se utilizan paréntesis, los parámetros
declarados son locales del procedimiento en cuanto a su ámbito. Las variables de
memoria locales no pueden modificarse con las siguientes subrutinas que se llamen.
Para más información sobre los ámbitos de las variables de memoria, consulte el
Capítulo 5.
PROCEDURE MiProc
LOCAL Y
Y = 20
? Y && muestra 20
PARAMETERS Y&& el parámetro anula las variables locales
? Y && muestra 10
RETURN
Las dos formas de declarar parámetros no pueden mezclarse. Para un procedimiento
dado, puede declararlos usando o bien paréntesis o bien una sentencia PARAMETERS.
No es posible declarar algunos parámetros con paréntesis y otros con PARAMETERS.
Los dos declaraciones de clase siguientes son idénticas, excepto en que una declara un
parámetro con paréntesis y la otra con PARAMETERS.
Figura 4.1 Declaración de parámetros con ámbito local y privado
PROCEDURE MiProc(n)
? n && Muestra 10 en la primera llamada, 11 en la segunda
n = n+1
? n && Muestra 11 en la primera llamada, 12 en la segunda
?
RETURN
PROCEDURE MiProc
ƒ
RETURN
PROCEDURE MiOtroProc
Mvar = DATE() + 30
RETURN Mvar
* Fin de MiProgs.prg
Capítulo
* Programa XYZ
mvar1 = mvar + 170 && Como antes, dBASE busca una variable privada, local o
&& estática llamada mVar. Si no la encuentra busca una
&& pública. Si tampoco la encuentra, se produce un error
Públicas
Las variables públicas, en ocasiones denominadas variables globales, tienen el ámbito
más amplio. Están disponibles para cualquier subrutina y no se liberan hasta que se
utilice RELEASE o CLEAR ALL o se salga de Visual dBASE.
Las variables públicas son muy útiles para definiciones que se aplican a toda una
aplicación, como nombres de acceso de un usuario o vías de acceso por defecto a los
datos. Sin embargo, no proporcionan protección contra la sobreescritura. En general,
una aplicación bien diseñada utiliza pocas variables públicas, o ninguna.
La Figura 5.1 ilustra la disponibilidad de las variables públicas. MiPub, declarada pública
en Sub1, está disponible en todas las subrutinas. MiPub nunca se libera a menos que se
haga explícitamente con RELEASE o CLEAR ALL.
Figura 5.1 Disponibilidad de las variables públicas
Ppal
Sub1
Sub2
PUBLIC MiPub
Sub1A Sub1B
= La variable está disponible después de ejecutar Sub1; sigue disponible cuando termina Ppal
Privadas
Las variables privadas están disponibles en la subrutina que las crea y en las de nivel
inferior.
La Figura 5.2 ilustra la disponibilidad de las variables privadas. MiPrv, declarada privada
en Sub1, está disponible en Sub1, Sub1A y Sub1B. MiPrv se libera cuando Sub1 termina
de ejecutarse.
Figura 5.2 Disponibilidad de las variables privadas
Ppal
Sub1
Sub2
PRIVATE MiPrv
Sub1A Sub1B
Locales
Las variables locales están disponibles sólo para el procedimiento o función en que se
declaran. Puesto que el ámbito local limita la disponibilidad de la variable a una sola
subrutina, el termino ocultación de datos se utiliza en ocasiones para describir la
asignación de un ámbito local a las variables.
La Figura 5.3 ilustra la disponibilidad de las variables locales. MiLoc, declarada local en
Sub1, está disponible sólo en Sub1. Cada vez que se llama Sub1, se reinicializa MiLoc.
Ppal
Sub1
Sub2
LOCAL MiLoc
Sub1A Sub1B
Estáticas
Las variables estáticas son locales en disponibilidad pero públicas en cuanto a vida.
Es decir, una variable estática continúa existiendo cuando la subrutina que la declaró
termina de ejecutarse (como una variable pública), pero no está disponible a menos que
se llame la subrutina de nuevo. Al igual que una variable local, una estática sólo está
disponible en la subrutina que la creó; sin embargo, a diferencia de aquella, una variable
estática mantiene su valor anterior cada vez que se llama la subrutina que la creó.
En consecuencia, las variables estáticas son muy útiles para almacenar valores que no se
incrementan, como totales acumulados en un informe.
A diferencia de los otros tipos de variables, las estáticas pueden declararse e inicializarse
en una sola sentencia, por medio de la sintaxis siguiente:
STATIC <varmem> = <valor>
La Figura 5.4 ilustra la disponibilidad de las variables estáticas. MiEst, declarada estática
en Sub1, está disponible sólo para Sub1. La primera vez que se llama Sub1, MiEst se
inicializa con un valor de 100. Las siguientes llamadas de Sub1 no reinicializan MiEst,
sino que se mantiene el valor anterior de MiEst.
Figura 5.4 Disponibilidad de las variables estáticas
Ppal
Sub1
Sub2
STATIC MiEst=100
Sub1A Sub1B
Importante Cuando se declaran e inicializan variables estáticas en una sola sentencia, Visual dBASE
las inicializa en una subrutina sólo la primera vez que se llama la subrutina; las
siguientes llamadas no reinicializan la variable estática. El ejemplo siguiente ilustra esta
conducta.
* Programa Prog1
PUBLIC nTotal
nTotal = 1000
Do Prog2
.
.
.
Do Prog2
* Programa Prog2
STATIC nVentas = 500 && nVentas se inicializa a 500 sólo la primera vez que se llama a
&& prog2
STATIC nProfPct
nProfPct = .03 && nProfPct se inicializa a .03 cada vez que se llama a Prog2
? nVentas && Devuelve 500 la primera vez que se llama a Prog2
&& Devuelve 800 (500 + 300) la segunda vez que se llama a Prog2
&& ya que a nVentas se le suma 300 más tarde en este programa
STATIC nMargen=0 && Se inicializa a 0 sólo la primera vez que se ejecuta Prog2
nMargen = nMargen + (nVentas * nProfPct)
? nMargen && Devuelve 15 (0+(500*.03)) la primera vez que se ejecuta Prog2
&& Devuelve 39 (15+(800*.03)) la segunda vez que se ejecuta Prog2
nTotal = nTotal + nVentas
? nTotal && Devuelve 1500 (1000 + 500) la primera vez que se llama a Prog2
&& Devuelve 2300 (1500 + 800) la segunda vez que se llama a Prog2
nVentas = nVentas + 300
RETURN
Subíndice 2
Número de elemento 1 2 3 4
Para hacer referencia a un elemento individual de una matriz mediante sus subíndices:
aMatriz[3,3] = 50 && Guarda el valor 50 en la tercera fila, tercera columna
Tabla 5.2 Resumen de las tareas de matrices y los comandos y funciones relacionados (continuación)
Tarea de matriz Funciones Descripción
ARESIZE() Aumenta o disminuye el tamaño de una matriz.
ARESIZE() puede convertir una matriz unidimensional
en bidimensional.
Copia y ordenación de ACOPY() Copia elementos de una matriz a otra.
elementos
ASORT() Ordena los elementos de una matriz unidimensional o
las filas de una bidimensional.
Determinación del ALEN() Devuelve el número de elementos, filas o columnas de
tamaño una matriz dada.
Copia entre matrices y COPY TO ARRAY Copia datos de una tabla de base de datos a una matriz.
tablas
APPEND FROM Añade datos de una matriz en una tabla de base de datos.
ARRAY
REPLACE FROM Sustituye los datos de una tabla de base datos por los de
ARRAY una matriz.
ARESIZE()
Este ejemplo muestra cómo cambiar el tamaño de la matriz del ejemplo anterior para
poder añadir más valores. En este caso, se añaden dos columnas en la matriz.
ARESIZE(aMatriz,nRegistros,5,1) && La matriz tiene ahora 5 columnas
&& El 1 final indica que los valores originales deben
&& continuar en su lugar
ALEN(), AGROW()
En este ejemplo se supone que no se sabe cuántas filas o columnas contiene la matriz, y
es necesario saberlo para poder realizar ciertas funciones. Se sabe que el sueldo de cada
empleado está en la primera columna, el nombre en la quinta, el apellido en la sexta y la
fecha de nacimiento en la última columna. Se quiere dar un aumento a todos y, además,
enviar tarjetas de felicitación a los que cumplan años en el mes actual. Para almacenar
los nombres de estas personas, se crea una segunda matriz.
DECLARE aCumplean[1,2] && Crea una matriz para guardar los nombres de las
&& personas a las que enviar tarjeta de felicitación
nNuevaFila = 1
nFilas = ALEN(aMatriz,1) && Devuelve el número de filas de la matriz de empleados
nCols = ALEN(aMatriz,2) && Devuelve el número de columnas de la matriz de empleados
nMesActual = MONTH(DATE()) && Devuelve el mes actual (1-12)
FOR mvar = 1 TO nFilas && Recorre todas las filas de la matriz de empleados
aMatriz[mvar,1] = aMatriz[mvar,1] * 1.03 && Dar a todos un 3% de aumento
IF MONTH(aMatriz[mvar,nCols]) = nMesActual && Compara mes de nacimiento con mes en
&& curso
aCumplean[nNuevafila,1] = aMatriz[mvar,5] && Nombre en primera fila de la matriz de
&& tarjetas
aCumplean[nNuevafila,2] = aMatriz[mvar,6] && Apellidos en la segunda columna de la
&& matriz de tarjetas
AGROW(aCumplean,1) && Añadir una fila a la matriz de tarjetas
nNuevaFila = nNuevaFila+1
ENDIF
NEXT
Capítulo
Al igual que los tipos de datos tradicionales, éstos nuevos tienen reglas que controlan
cómo se trabaja con ellos. Un bloque de código puede asignarse a una propiedad,
pasarse como parámetro o ejecutarse. Sin embargo, no es posible realizar cálculos con
un bloque de código.
Con estos tipos de datos nuevos, Visual dBASE amplía el concepto de lo que son datos
en las aplicaciones. En versiones anteriores de dBASE, los datos son con lo que trabaja el
usuario en las tablas. Con Visual dBASE, los datos son cualquier información sobre la
que actúa el programador o el usuario. La información puede ser la dirección de una
persona que se imprime o un objeto de botón sobre el que se hace clic.
La Tabla 6.1 enumera los tipos de datos existentes en Visual dBASE.
Tabla 6.1 Tipos de datos de Visual dBASE
Tipo de datos Símbolo
Carácter C
Variables o
campos de las Fecha D
tablas de dBASE Lógico (booleano) L
Numérico N
Sólo variables Indicador BM
Bloque de código CB
Puntero de función FP
Objeto O
Matriz A
Nulo U
Sólo campos de Binario B
tablas de dBASE (Coma) flotante F
Memo M
OLE O
Comparación fonética
La comparación de cadenas carácter por carácter funciona bien si ambas cadenas están
escritas correctamente. Sin embargo, los errores ortográficos y de tecleo por parte del
usuario son inevitables. Para encontrar cadenas similares pero escritas de forma
incorrecta, compárelas por la forma en que sonarían. Para comparar cadenas
fonéticamente, genere un código fonético, o de sonido similar, para cada cadena.
Dicho código es una fórmula utilizada habitualmente para generar el valor fonético de
las palabras. Visual dBASE proporciona dos funciones para generar y comparar valores
por su código fonético:
• SOUNDEX() devuelve el código fonético de una cadena de caracteres.
• DIFFERENCE() devuelve un número (0 a 4) que representa el grado de similitud
fonética entre dos cadenas.
Los códigos fonéticos son específicos de cada idioma. Es decir, cada controlador de
idioma tiene su propia fórmula para generarlos. Para más información sobre los
controladores de idioma, consulte el Apéndice C.
Estos son algunos ejemplos de comparación fonética:
? "Juan"="Juana" && Devuelve .F.
? SOUNDEX("Juan")=SOUNDEX("Juana") && Devuelve .T.
DIFFERENCE("Juan","Juana") && Devuelve 4 (muy similares)
DIFFERENCE("Coche","Cochera") && Devuelve 3 (menos similares)
DIFFERENCE("dBASE","C") && Devuelve 1 (nada similares)
Eliminación de espacios
En algunas ocasiones, es necesario eliminar espacios al principio o al final de una
cadena.
• TRIM() y RTRIM() son funciones idénticas que eliminan espacios del lado derecho de
una cadena.
• LTRIM() elimina espacios del lado izquierdo de una cadena.
Los campos de una tabla, o los campos de entrada de una ficha, tienen anchos fijos para
albergar la longitud máxima de una cadena. Cuando se muestra una cadena en
particular, es posible eliminar los espacios extra del lado derecho para poder mostrar
otra cadena junto a ella. Este ejemplo elimina los espacios del campo Ciudad para
mostrar una dirección:
? TRIM(Ciudad) + ", " + Provincia + " "+Cod_Post && Muestra "Madrid, M 28015"
La sección “Concatenación de cadenas de caracteres” de este capítulo muestra otra
técnica para eliminar espacios mediante el operador menos (–).
Repetición de caracteres
Visual dBASE dispone de dos funciones para repetir caracteres en una cadena, evitando
así la necesidad de teclearlos manualmente:
• SPACE() repite el carácter de espacio el número especificado de veces, lo cual es útil
para inicializar las variables de caracteres.
• REPLICATE() repite cualquier carácter, o cadena, que especifique el número
indicado de veces, lo cual es útil para crear efectos visuales simples, como una fila de
asteriscos o caracteres de subrayado.
mNombre = SPACE(30) && Inicializa la variable con 30 espacios
mOcupacion = SPACE(45) && Inicializa la variable con 45 espacios
mLinComienzo = REPLICATE("*",30) && Crea una fila con 30 asteriscos
? mLinComienzo && Muestra ******************************
El Capítulo 20 describe CALCULATE, SUM y otros comandos que resumen los datos
numéricos de las tablas.
El código siguiente define un campo de entrada para mostrar el nombre de una persona.
El valor de la propiedad Picture restringe la introducción de datos sólo a letras; la
propiedad Function trunca los espacios iniciales y finales:
DEFINE ENTRYFIELD Peso OF This PROPERTY;
Width 3, Top 11, Left 21, Height 1, ColorNormal "bg+/b", ;
Border .F., Picture "XXXXXXXXXXXXXXXXXXXXXXXXXXXX", Function "T", ;
DataLink "Diagnosis"
El ejemplo siguiente halla la longitud de una viga de par de tejado para una habitación
de 40 pies de ancho con un ángulo de 30 grados y un alero de 18 pulgadas (1.5 pies):
mViga = (40/2)/COS(DTOR(30)) + 1.5
? mViga && Devuelve 24.59
El código siguiente utiliza las funciones de hora para calcular cuánto dura la ejecución
de una subrutina:
mComienzo = TIME() && Guarda la hora actual
DO rutina
mFin = TIME() && Guarda la hora en la que terminó de
&& ejecutarse el código
mDuracion = ELAPSED(mFin,mComienzo) / 3600 && Convierte segundos a horas
? mDuracion && Muestra las horas transcurridas
Para ver un ejemplo de validación de datos de hora en una ficha, consulte la página 225.
Capítulo
.PRG .PRO
Cada directiva comienza con el símbolo #; toda línea de código que tenga un signo #
inicial se considera una directiva de preprocesador. El carácter # puede ir precedido por
espacios. La Tabla 7.1 resume las directivas de preprocesador.
Tabla 7.1 Resumen de las directivas de preprocesador de Visual dBASE
Directiva Descripción
#define Define un identificador.
#if ... #endif Compila una sección de código si un identificador tiene cierto valor.
#ifdef ... #endif Compila una sección de código si un identificador está definido (con
#define).
#ifndef ... #endif Compila una sección de código si un identificador no está definido.
#include Inserta un archivo de código fuente (también denominado archivo include)
en la posición actual.
#pragma Especifica una opción del compilador.
#undef Anula la definición de un identificador.
Definición de constantes
Una forma sencilla de mejorar la velocidad de un programa es representar las
constantes con identificadores. Un identificador es un nombre descriptivo que se asigna a
un texto del programa mediante la directiva #define. Las ventajas de utilizar
identificadores se hacen palpables cuando se consideran las otras dos formas de
representar constantes en dBASE: valores literales y variables de memoria. Las secciones
siguientes comparan estas tres formas de definir constantes.
Expansión de expresiones
La sintaxis de la directiva #define le permite especificar parámetros que se insertarán en
el texto que sustituirá las apariciones del identificador. Puede ahorrar tiempo creando
identificadores que se expandan durante la compilación en expresiones incómodas o
que se utilizan con frecuencia.
Este es un resumen de la sintaxis de los parámetros de #define. Para una descripción
completa, consulte la Referencia del lenguaje:
#define <identificador> ( <lista parámetros> ) <texto de sustitución>
En ocasiones es necesario crear una expresión que utiliza varias llamadas de función
incrustadas. Teclear estas expresiones y controlar los paréntesis son una tarea pesada, en
especial si se utilizan de forma repetida. La expresión siguiente convierte un valor
numérico en cadena, elimina los espacios iniciales y centra el texto.
nValor = 1200
? CENTER(LTRIM(STR(nValor)))
Para simplificar la introducción de esta expresión, puede crear un identificador que
combine las tres funciones en una e inserte el valor. Entonces, bastaría teclear el nombre
del identificador y los parámetros (entre paréntesis), en lugar de toda la expresión.
#define Val_Centrado(num) CENTER(LTRIM(STR(num)))
nValor = 12
?Val_Centrado(nValor) && centra '12'
?Val_Centrado(nValor + 20) && centra '32'
En el momento de la compilación, Val_Centrado(nValor) se expande en
CENTER(LTRIM(STR(nValor))).
Compilación condicional
El lenguaje dBASE siempre ha proporcionado comandos de control de flujo, como
IF...ELSE...ENDIF, que sirven para controlar qué comandos se activan durante la
ejecución. De forma análoga, por medio de las directivas condicionales de Visual
dBASE, como #if...#else...#endif, es posible controlar qué comandos se compilan.
Esta técnica, denominada compilación condicional, es especialmente útil para depurar o
desarrollar diferentes versiones de una aplicación.
Las condiciones para determinar qué comandos se compilan dependen de los
identificadores definidos con #define. Es posible definir dos tipos de condiciones:
• Es posible comprobar si existe un identificador con #ifdef (si está definido) o #ifndef
(si no lo está). Utilice #ifdef o #ifndef para comprobar los identificadores que se
definen sin ningún valor, como #define Debug.
• Es posible comprobar el valor de un identificador con #if. Utilice #if para comprobar
los identificadores que se definen con un valor, como #define Version 1.
Cada directiva condicional también tiene una opción “en los demás casos” (#else) para
seleccionar los comandos que se compilan cuando no se cumple la condición.
El ejemplo siguiente establece una compilación condicional para depuración. Si se ha
definido un identificador denominado Depurar, se compila el código de depuración;
de lo contrario, se compila DO MiProc.
* Comprueba la existencia del identificador Depurar
#ifdef Depurar && Si existe Depurar compila este código
SET ALTERNATE TO DEPURA.TXT
SET ALTERNATE ON && Abre un archivo ALTERNATE
LIST STATUS && y lista el entorno actual en dicho
LIST MEMORY && archivo
SET ALTERNATE TO
SET ALTERNATE OFF
#else && Si no existe Depurar compila este código.
DO MiProc
#endif
Puede lograr resultados similares con el comando IF...ELSE...ENDIF, pero las directivas
condicionales se evalúan durante la compilación, permitiéndole compilar sólo el código
que desea ejecutar, lo cual puede, a su vez, mejorar el rendimiento del programa.
Además, el código que no se depura por completo puede no compilarse. Con las
directivas condicionales, puede marcar con facilidad secciones incompletas de código y
compilarlas sólo cuando esté preparado para depurarlas.
También puede utilizar las directivas condicionales para desarrollar versiones
diferentes de un programa sin necesidad de mantener conjuntos distintos de código
fuente. La técnica es similar al ejemplo de la depuración anterior, excepto que se
comprueba el valor de un identificador, no su existencia.
#define Ver1
#define Depurar
#define Verdad 1
#define Falso 0
ƒ
#include MISDEFS.H #include MISDEFS.H #include MISDEFS.H
*Código dBASE *Código dBASE *Código dBASE
MISDEFS.H ƒ ƒ #if Ver = 1
(archivo #if Ver = 1 #ifdef Depurar DO V1
include) ? "Versión 1" * Código a depurar #else
#else #else DO V2
? "Versión 2" * Otro código #endif
#endif #endif ƒ
ƒ ƒ
La Tabla 7.2 muestra algunos ejemplos de lo que puede almacenarse en los archivos
include:
Tabla 7.2 Ejemplos de archivos include
Lo que puede guardarse en un archivo include Ejemplo
Identificadores que representan valores de colores RGB. #define MiColor 56,62,155
Identificadores que representan valores devueltos por #define CTRL-W 23
INKEY(), READKEY(), LASTKEY(), NEXTKEY().
Constantes específicas de la aplicación. #define MAXARTICULOS 10000
Prototipos de función que se declaran con el comando EXTERN CWORD MiFunc() MiBibl.DLL
EXTERN. (Para más información, consulte el Capítulo 26.)
Constantes utilizadas en funciones del API de Windows. #define MB_ICONHAND HTOI("0010")
Definiciones de clases personalizadas. CLASS MiBoton OF PUSHBUTTON
ƒ
ENDCLASS
Capítulo
Depuración de programas
Capítulo 8
8
Depurar significa localizar y eliminar los errores de un programa. Visual dBASE dispone
de un potente Depurador que puede mostrar código de programa, inspeccionar
programas, definir puntos de ruptura, mostrar valores de variables y ver la pila en las
ventanas abiertas actualmente. La ejecución de un programa puede seguirse línea a
línea, o ir a puntos de ruptura específicos para ver dónde se producen los errores en el
programa. Después de corregir el código, es posible compilar y volver a ejecutar el
programa en el Depurador para comprobar si se ha solucionado el problema.
Tipos de errores
Los programas pueden contener tres tipos de errores:
• Errores de compilación o sintaxis
• Errores en tiempo de ejecución
• Errores lógicos
Errores lógicos
El código de un programa podría ser correcto sintácticamente y ejecutarse sin
experimentar ningún error en tiempo de ejecución, y aún así podría producir resultados
incorrectos. Por ejemplo, si hay un procedimiento que debe ejecutarse después de que
tenga lugar algún suceso, pero el suceso nunca ocurre al ejecutar el programa, podría
tratarse de un error lógico.
En dBASE DOS, algunos comandos activan el depurador y realizan otras tareas de
depuración:
• SET STEP
• SET ECHO
• SET TRAP
Estos comandos ya no son necesarios en Visual dBASE, porque todas las tareas de
depuración se realizan en el Depurador. Cuando Visual dBASE encuentra SET STEP ON
y SET ECHO ON, abre el Depurador. Cuando encuentra SET TRAP ON, no tiene en
cuenta este comando. Los valores OFF de estos tres comandos tampoco se tienen en
cuenta en Visual dBASE.
La ventana Ruptura contiene puntos de ruptura La ventana Pila controla todas las llamadas del
definidos por el programador de detención de la programa a módulos y procedimientos.
ejecución del programa. La última línea describe la subrutina actual.
Cuando se inicia el Depurador, está activa la ventana Módulo. Para cambiar el foco de
ventana, haga clic en la que desea activar o elíjala en el menú Ventana. También puede
elegir Mosaico o Cascada en ese menú para disponer las ventanas en mosaico o en
cascada. Si minimiza alguna de las ventanas, elija Ventana|Organizar iconos para
ordenar los iconos de las ventanas.
Sale del Detiene la Ejecuta la Inspecciona el campo, Evalúa una Reduce la vista del
Depurador. ejecución del línea fuente variable, matriz u expresión y Depurador a sólo su
programa. actual. objeto que indique. cambia el valor. menú y la Barra rápida.
Carga de subrutinas
Una vez que un programa está cargado en el Depurador, puede cargar una o todas sus
subrutinas. Si ejecuta un programa principal que llama otros archivos de programa, el
Depurador carga los archivos de subrutina conforme son necesarios. No obstante, es
posible cargar una subrutina en el Depurador antes de que la llame el programa.
Para cargar una subrutina desde el menú del Depurador:
1 Elija Archivo|Cargar módulo.
2 En el cuadro de diálogo Seleccionar módulo, especifique el archivo de programa de la
subrutina que desea cargar además del archivo de programa actual (el principal).
Para cargar una subrutina desde la ventana Módulo:
1 Haga clic con el botón derecho en la ventana Módulo para acceder a su Menú rápido.
2 Elija Cargar módulo.
3 En el cuadro de diálogo Seleccionar módulo, especifique el archivo de programa que
desea cargar en el Depurador.
Si elige Archivo|Nuevo al cargar un programa en el Depurador, Visual dBASE le
pregunta si desea terminar la sesión actual de depuración.
Búsqueda de texto
Para encontrar una cadena de texto en el archivo de programa actual:
1 Elija Programa|Buscar en el menú del Depurador, o haga clic con el botón derecho
en la ventana Módulo y elija Buscar en el Menú rápido.
2 Especifique el texto que desea encontrar en el cuadro de diálogo Buscar.
La búsqueda comienza en la posición actual del cursor y distingue entre mayúsculas y
minúsculas. Si Visual dBASE encuentra el texto, la ventana se desplaza a la línea que
contiene el texto y el cursor se sitúa al principio de ese texto. Para encontrar apariciones
sucesivas del mismo texto, elija Programa|Buscar siguiente en el menú del Depurador o
Buscar siguiente en el Menú rápido de la ventana.
El Depurador mantiene una historia de todas las cadenas de texto que se buscan en una
sesión de depuración. Para encontrar cualquiera de estas cadenas de nuevo:
1 Elija Programa|Buscar en el menú del Depurador, o haga clic con el botón derecho
en la ventana Módulo y elija Buscar en el Menú rápido.
2 Haga clic en la flecha abajo situada a la derecha del cuadro de texto Cadena de
búsqueda en el cuadro de diálogo Buscar.
3 Elija una cadena de texto anterior en el menú desplegable.
Desplazamiento a un procedimiento
Para ir a un procedimiento o función del archivo de programa actual o de uno de sus
archivos de procedimientos o biblioteca:
1 Elija Programa|Ir a procedimiento en el menú del Depurador o haga clic con el botón
derecho en la ventana Módulo y elija Ir a procedimiento en el Menú rápido.
2 Especifique el nombre del procedimiento en el cuadro de diálogo Ir a procedimiento.
La búsqueda del procedimiento comienza en la posición actual del cursor en la ventana
Módulo. Si se halla en el programa que está depurando, el Depurador sitúa el cursor en
la primera línea del procedimiento. Si se halla en un archivo de procedimientos no
abierto, el Depurador lo carga en la ventana Módulo. Si el Depurador no puede
encontrarlo, el archivo de programa actual permanece en la ventana Módulo.
El Depurador mantiene una historia de todos los procedimientos que se buscan en una
sesión de depuración. Para ir de nuevo a cualquiera de estos módulos de programa:
1 Elija Programa|Ir a procedimiento en el menú del Depurador, o haga clic con el
botón derecho en la ventana Módulo y elija Ir a procedimiento en su Menú rápido.
2 Haga clic en la flecha abajo situada a la derecha del cuadro de texto Nombre de
procedimiento en el cuadro de diálogo Ir a procedimiento.
3 Elija un nombre de procedimiento en el menú desplegable.
Animación
Cuando se anima un programa, el Depurador ejecuta el programa de forma continua
haciendo una pausa en cada línea de comando y actualizando la información en todas
las ventanas del Depurador con cada pausa. El programa realiza sus tareas como si lo
estuviera ejecutando en Visual dBASE, excepto que puede controlar su velocidad de
ejecución. El código fuente se desplaza en la ventana Módulo conforme se ejecutan las
líneas, y la palabra Ejecutando aparece a la derecha de la barra de estado.
Para animar un programa, elija Ejecutar|Animación en el menú del Depurador.
Para controlar la velocidad de animación, elija Opciones|Velocidad de animación y
especifique la velocidad en el cuadro de diálogo Velocidad de animación moviendo el
cuadro de la barra de desplazamiento. Si lo mueve hacia la derecha, aumenta la
velocidad de animación; a la izquierda, disminuye la velocidad de animación.
La velocidad de animación que especifique se aplica a todos los programas que anime.
Puede cambiarla antes de la animación de un programa o durante ella. Si ya está
animando un programa cuando elige Opciones|Velocidad de animación, la selección
con la barra de desplazamiento afecta a la velocidad de la animación actual.
Seguimiento
El Depurador permite ejecutar un programa línea a línea, es decir, seguir el programa, y
detenerlo en cualquier línea. El seguimiento, o rastreo, ejecuta y detiene en cada línea el
programa principal y todas las subrutinas que llama. El método paso a paso (que se
explica en la sección siguiente) también ejecuta el programa principal, pero excluye las
llamadas a las subrutinas.
Cuando incluye la llamada a una subrutina, el Depurador carga ese módulo en la ventana
Módulo y se detiene en la primera línea de la subrutina. Puede continuar el rastreo en la
subrutina y en las subrutinas inferiores que llame ella, o puede excluir las llamadas que
haga a subrutinas inferiores.
Para incluir la llamada a una subrutina, comience con el programa principal y avance
paso a paso o sígalo hasta la sentencia que llama a la subrutina; a continuación, incluya
la llamada para comprobar su ejecución línea por línea en la ventana Módulo.
Para seguir un programa e incluir la llamada a una subrutina:
• Haga clic en el icono Incluir llamadas en la Barra rápida.
• Elija Ejecutar|Incluir llamadas.
• Pulse F7.
Figura 8.3 Seguimiento de una subrutina
La ejecución del programa se detiene en la primera línea de la función CallChangeEqForm, una
subrutina de la ficha Vuelos. Así se ha seguido CallChangeEqForm, no se ha excluido. En este
punto, el seguimiento o paso a paso de cada línea puede continuar en CallChangeEqForm.
Paso a paso
La ejecución paso a paso de un programa realiza un seguimiento del programa
principal, pero excluye las líneas que llaman subrutinas. Si ya ha determinado que no
hay errores en una subrutina en particular, puede excluir su ejecución y concentrarse en
el resto del programa. Aún así, la llamada a la subrutina se produce y ésta se ejecuta,
pero no se muestra su ejecución línea a línea en la ventana Módulo, por lo que no es
posible detenerla en ninguna de las líneas. El Depurador se detiene en la primera línea
de comando después de la subrutina.
Para ejecutar paso a paso un programa y excluir las líneas de comando que llaman
subrutinas:
• Haga clic en el icono Excluir llamadas en la Barra rápida.
• Elija Ejecutar|Excluir llamadas.
• Pulse F8.
Figura 8.4 Exclusión de la llamada a una subrutina
La línea que llama a la función CallChangeEqForm, es la línea siguiente que se ejecuta. Aunque la excluya,
CallChangeEqForm se ejecutará, pero no verá su ejecución línea a línea en la ventana Módulo ni podrá detenerla.
Restablecimiento de programas
El restablecimiento de un programa en el Depurador hace lo siguiente:
1 Detiene el programa si se está ejecutando.
2 Borra el programa de la memoria.
3 Carga el programa de nuevo en memoria y en el Depurador, comenzando en la
primera línea.
Para restablecer un programa que se está ejecutando, haga una de estas acciones:
• Haga clic en el botón Restablecer de la Barra rápida.
• Elija Ejecutar|Restablecer en el menú del Depurador.
Visualización de la pila
Cuando se ejecuta un programa en el Depurador, éste controla las llamadas que aquél
hace a otros programas, procedimientos o funciones en la ventana Pila. Cada línea de la
ventana Pila indica el nombre de archivo y número de línea de las llamadas a subrutinas
y de las rutinas que efectúan la llamada en el orden en que se llamaron (vea la
Figura 8.3, “Seguimiento de una subrutina”). La ventana Pila es por tanto una vista del
flujo desde el programa a una subrutina, de vuelta al programa principal, o más abajo a
otro nivel de subrutina, y así sucesivamente.
Cada vez que se detiene la ejecución del programa, por ejemplo en cada línea cuando lo
procesa paso a paso, lo sigue y lo anima o en cada punto de ruptura, el Depurador
actualiza la ventana Pila.
Para mover el foco en la ventana Módulo a la posición de la llamada a una subrutina:
1 En la ventana Pila, seleccione la línea de la subrutina que desea ver en la ventana
Módulo.
2 Elija Stack|Ir a línea de fuente en el menú del Depurador o haga clic con el botón
derecho en la ventana Pila y elija Ir a línea de fuente en el Menú rápido.
Cuando la ventana Módulo desplace el código fuente hasta la línea de comando que
llama la subrutina, la ejecución del programa continúa detenida en el mismo lugar.
Si reanuda su ejecución, lo hará desde el punto en que se detuvo y la ventana Módulo
vuelve a la siguiente de línea de comando que se ejecuta.
Inspección de expresiones
La inspección de una expresión es diferente a su evaluación. Aunque puede definir un
punto de evaluación para una expresión en cualquier momento, la inspección de una
expresión puede establecerse sólo después de que se hayan inicializado las variables,
campos, matrices u objetos de la expresión. En otras palabras, la expresión debe tener
significado en el contexto actual del programa. Un punto de evaluación también
muestra un único valor de una matriz u objeto, mientras que la inspección de una
matriz o un objeto revela el valor de todos sus elementos o propiedades.
Establecimiento de inspecciones
Para inspeccionar una expresión:
• Resalte la expresión o desplace el cursor hasta ella en el código fuente de la ventana
Módulo y haga una de las acciones siguientes:
• Haga clic en el botón Inspeccionar de la Barra rápida.
• Elija Programa|Inspeccionar en el menú del Depurador o haga clic con el botón
derecho en la ventana Módulo y elija Inspeccionar en su Menú rápido.
• Pulse Ctrl+I.
La expresión seleccionada aparece en el cuadro de diálogo Inspeccionar.
• Haga clic en el botón Inspeccionar de la Barra rápida e introduzca la expresión en el
cuadro de diálogo Inspeccionar.
• Elija Programa|Inspeccionar en el menú del Depurador o haga clic con el botón
derecho en la ventana Módulo y elija Inspeccionar en el Menú rápido de la ventana;
entonces, introduzca la expresión que desea inspeccionar en el cuadro de diálogo
Inspeccionar.
• Pulse Ctrl+I e introduzca la expresión en el cuadro de diálogo Inspeccionar.
Cuando elija Aceptar, se abre la ventana de inspección que contiene la expresión
especificada y su valor. Si ha especificado una matriz o un objeto, también se muestran
todos los valores de los elementos de la matriz o de las propiedades del objeto.
Figura 8.14 Ventana de inspección
La ventana de inspección contiene, para Principal, los
valores de las propiedades del objeto.
Ventana de inspección
Cada ventana de inspección tiene su propio Menú rápido, que puede abrir haciendo clic
con el botón derecho en la ventana. Cuando seleccione un elemento mencionado en una
ventana de inspección y abra su Menú rápido, tiene las opciones siguientes:
• Rango: define un rango (límites superior e inferior) para el elemento seleccionado.
• Modificar: cambia el valor del elemento seleccionado.
• Descender: establece una inspección (abre una ventana de inspección aparte) para el
elemento seleccionado en la ventana de inspección actual.
• Expandir Hex: muestra el valor hexadecimal del elemento seleccionado si dicho
elemento es una variable de cadena binaria.
• Inspeccionar nueva expresión: inspecciona otra expresión.
Las secciones siguientes describen cada una de estas opciones del Menú rápido.
Definición de fuentes
Para definir la fuente de visualización por defecto para el texto en el Depurador, elija
Opciones|Fuente de visualización. Especifique sus preferencias en el cuadro de diálogo
Fuentes.
Parte
II
Objetos y clases
Parte II
Esta parte presenta y trata las extensiones orientadas a objetos que se han añadido en el
lenguaje dBASE.
Si trabaja con la orientación a objetos por primera vez:
1 Comience con el Capítulo 9 para aprender la terminología y los conceptos básicos.
2 Hojee los Capítulos 10 y 11 para familiarizarse con los comandos y técnicas.
3 Lea el Capítulo 12 para aprender cómo diseñar aplicaciones orientadas a objetos.
Cuando comience a programar con objetos y clases, consulte los Capítulos 10 y 11 para
conocer detalles sobre la realización de tareas específicas.
Esta sección contiene los capítulos siguientes
• Capítulo 9, “Introducción a la programación orientada a objetos”
• Capítulo 10, “Uso de los objetos”
• Capítulo 11, “Uso de las clases”
• Capítulo 12, “Diseño orientado a objetos”
Capítulo
Introducción a la programación
Capítulo 9
9
orientada a objetos
Este capítulo presenta los objetos y las clases y describe cómo trabajar con ellos
empleando el lenguaje dBASE. Aprenderá qué son los objetos y las clases, cómo crear
objetos y cómo manipularlos cambiando sus propiedades.
La orientación a objetos emplea técnicas avanzadas para la gestión de variables de
memoria. Antes de aprender acerca de los objetos, debería familiarizarse con los
conceptos básicos del uso de las variables de memoria. Para más información, consulte
el Capítulo 5.
Los objetos son extensibles. Es decir, es posible añadir nuevos miembros en un objeto
con una simple sentencia de asignación. Teclee estas líneas en la ventana de comandos
para añadir dos nuevas propiedades en la ficha:
CompProp.MiPropN = 123 && Añade una nueva propiedad llamada MiPropN
CompProp.MiPropC = "¡Hola!" && Añade una nueva propiedad llamada MiPropC
La adición de propiedades no tiene ningún efecto sobre la ficha —aún—. Para que una
propiedad haga algo con la ficha, puede añadir un método que lea su valor y realice
alguna acción con él. El código siguiente añade un método en CompProp asignando un
bloque de código a MiMetodo. Teclee esta línea en la ventana de comandos:
CompProp.MiMetodo = {;CompProp.Text = CompProp.text+CompProp.MiPropC}
Al ejecutarlo, MiMetodo añade la cadena almacenada en MiPropC en la barra de título de
la ficha. Para ejecutar MiMetodo, utilice el operador de llamada como sigue:
CompProp.MiMetodo() && Cambia el título
Definir propiedades tecleando comandos es divertido, pero puede ser más fácil ver y
editar todas las propiedades de un objeto de forma interactiva. Para ello, arranque el
Inspector como sigue:
INSPECT(CompProp) && Muestra las propiedades del Inspector
Visual dBASE proporciona la variable de memoria del sistema _app que puede utilizar
para acceder al objeto de aplicación. Mediante este objeto, puede definir varias
propiedades de Visual dBASE. Teclee esta línea en la ventana de comandos:
? _app.FrameWin.Text && Muestra el título de la ventana de la aplicación
Ahora pruebe esto:
_app.FrameWin.Text = _app.FrameWin.Text+" personalizada"
Acaba de personalizar Visual dBASE con un título.
Ahora que ha comenzado a trabajar con los objetos, continúe leyendo para aprender
sobre cómo se implantan en Visual dBASE.
Pantalón .
Elem Pantalón
MiMatriz[1] MiMatriz[2] MiMatriz[3]
Elem Talla 12
12 Pantalón 12 10095
1 2 3 Precio 10095
Talla MiObj
10095 CalCoste MiProc
Precio
MiMatriz
Todas las variables de memoria contenidas en un objeto son propiedades del objeto.
Algunas propiedades se convierten en métodos cuando le anexe código.
Nombre Juan
Talla 12
Precio 195
MiObj MiProc OtroProc
CalCoste MiProc
Un método Un procedimiento no
asociado al objeto
Las variables de un objeto (denominadas miembros del objeto) pueden ser del mismo
tipo de datos que las variables normales. En el ejemplo anterior, la propiedad Nombre
es del tipo carácter. Talla y Precio son propiedades numéricas. El tipo de CalCoste es
puntero de función; no contiene ningún valor como tal, sino que hace referencia a una
subrutina.
Contenedores de objetos
Los objetos pueden contener otros objetos. Las fichas son el ejemplo más común de esta
característica. El objeto de ficha es el objeto contenedor, o padre. Los campos de entrada,
botones y otros objetos del interface de usuario son los objetos hijos contenidos en las
fichas.
El código siguiente crea un objeto de ficha (MiFicha), un objeto de texto (Text1) y un
objeto de campo de entrada (Entrada1):
DEFINE FORM MiFicha PROPERTY Top 5, Left 3
DEFINE TEXT Text1 OF MiFicha PROPERTY Top 2, Left 2, Text "Nombre", Width 17
DEFINE ENTRYFIELD Entrada1 OF MiFicha PROPERTY Top 2, Left 11, Value "Juan"
OPEN FORM MiFicha
Text1.Top 2
Top 5 Text1.Left 2
Left 3 Text1.Value Nombre
Text1 Text1
MiFicha Hijo
Entrada1 Entrada1
Entry1
Padre
Entrada1.Top 2
Entrada1.Left 11
Entrada.Value Juan
Hijo
Top y Left son propiedades numéricas de MiFicha. Text1 y Entrada1 son del tipo objeto,
es decir, hacen referencia a otro objeto.
? MiFicha && variable de tipo "Objeto"
? MiFicha.Text1 && también variable de tipo "Objeto"
? MiFicha.Entrada1 && también variable de tipo "Objeto"
La relación padre-hijo entre objetos tiene implicaciones importantes para la forma en
que se trabaja con los objetos. Cuando se libera un objeto padre, también se liberan
todos sus objetos hijos. El código siguiente muestra que, cuando se libera MiFicha,
también se liberan Text1 y Entrada1
RELEASE OBJECT MiFicha && La ficha desaparece
? MiFicha && La variable existe, pero no hace referencia a ningún objeto
? MiFicha.Text1 && variable indefinida
? MiFicha.Entrada1 && variable indefinida
Todos los objetos que cree se basan en una clase. MiObj en la Figura 9.4 y en la Figura 9.5
se basa en la clase Object, y MiFicha, Text1 y Entrada1, en la Figura 9.6, se basan en las
clases Form, Text y Entryfield, respectivamente. Pero ¿qué es exactamente una clase?
La Figura 9.7 ilustra la relación entre tipos de datos y variables, y entre clases y objetos.
Figura 9.7 Una clase es a un objeto lo que un tipo de datos es a una variable de memoria
Tipo de datos Clases
Tipo de datos: Numérico Clase estándar: Form Cl. personalizada: Elems
Variables y campos Crea una ventana con CLASS Elems
numéricos: estas propiedades: This.Elem = "Bolso"
This.Tamano = 12
• Suman, restan, • Top This.Coste = 1695
multiplican o This.Cantidad = 4
• Left
dividen. Procedure CalValor
• Width Val = this.Coste*;
• Utilícelos en
expresiones sin this.Cantidad
• Height
RETURN Val
delimitadores
• Open() ENDCLASS
Capítulo
10
Uso de los objetos
Capítulo 10
En el Capítulo 9 ha aprendido qué son los objetos y las clases y por qué son tan
versátiles. Este capítulo explica cómo crear y usar los objetos, presenta los contenedores
de objetos y describe cómo trabajar con jerarquías de objetos. Concluye con tareas más
avanzadas, como crear objetos personalizados y trabajar con matrices como objetos.
Creación de objetos
Para crear una variable de memoria, basta declarar un nombre. Este ejemplo crea una
variable local denominada nPrecio:
LOCAL nPrecio
nPrecio = 195
Para crear una matriz, se declara su nombre y el número de filas y columnas que
contiene. Este ejemplo crea una matriz con 5 filas y 2 columnas, denominada MiMatriz:
DECLARE MiMatriz[5,2]
MiMatriz[1,1] = "Primer elemento"
Para crear un objeto, se especifica la clase en que se basará el objeto. La clase es una
receta o plantilla que especifica las propiedades y métodos que constituyen un objeto.
Un objeto es una copia de una clase. Por ejemplo, una ficha es una copia de la clase Form.
La clase Form especifica que los objetos de ficha tendrán propiedades Height y Width
para determinar el tamaño, y otras propiedades también.
En el lenguaje dBASE, puede crear objetos de una de las dos formas siguientes:
• Utilice DEFINE para crear un objeto según la necesidad y definir los valores iniciales
de sus propiedades en un solo comando. Esta sintaxis resultará muy sencilla para los
programadores habituados a los comandos DEFINE de dBASE DOS.
• Utilice el operador NEW en una sintaxis de asignación de variable de memoria.
El operador NEW crea un objeto pero no especifica valores para sus propiedades.
Para asignarlos, utilice otras sentencias de asignación adicionales.
Estas sintaxis alternativas son intercambiables, y es posible pasar de una a otra con
libertad, utilizando la que sea más conveniente en cada momento. Por ejemplo, en un
comando DEFINE, puede crear el objeto y definir sólo unas pocas propiedades.
DEFINE FORM MiFicha PROPERTY Top 10, Left 5
OPEN FORM MiFicha
Entonces, puede emplear la notación de punto (descrita en “Uso del operador de punto”
más adelante en este capítulo) para cambiar algunas propiedades.
MiFicha.Top = 12
MiFicha.Sizeable = .F.
A continuación, puede utilizar INSPECT() para cargar el Inspector y cambiar las
propiedades interactivamente.
Figura 10.2 Inspector
Para añadir otro objeto en la ficha, utilice DEFINE o el operador NEW. Este ejemplo
emplea el operador NEW:
MiBoton = NEW PUSHBUTTON(MiFicha)
• Form, que representa una referencia estándar a la ficha que contiene un objeto.
Visual dBASE crea automáticamente una referencia form cuando se declara una clase
de ficha o se abre una ficha. Como this, utilice form en código de control de sucesos y
en declaraciones de clase para hacer referencia genéricamente a la ficha que contiene
el objeto. El programa siguiente lo demuestra:
*** Programa DemoForm.prg
SET PROCEDURE TO PROGRAM(1) ADDITIVE
DEFINE FORM MiFicha
DEFINE PUSHBUTTON MiBoton OF MiFicha
MiFicha.Miboton.OnClick = MiOnClick
OPEN FORM MiFicha
Procedure MiOnClick
Form.text = "¡Ha pulsado mi botón!"
RETURN
This y form se describen en profundidad en el Capítulo 14.
En los ejemplos previos, un operador de acceso a miembro separa la referencia a objeto del
nombre de propiedad o método. Este operador asocia un miembro a un objeto de forma
parecida a cómo el operador de alias (->) asocia un campo a una tabla. Los operadores
de acceso a miembro son el de punto y el de índice, que se describen a continuación.
Como implica la Figura 10.3, es necesario teclear con cuidado cuando se definen
propiedades con el operador de punto. Al igual que con un nombre tradicional de
variable de memoria, si comete un error de tecleo u ortográfico en el nombre de
miembro de un objeto en una sentencia de asignación, Visual dBASE supone que desea
añadir un nuevo miembro personalizado con el nombre cambiado y no comunica
ningún error.
MiFicha = NEW FORM() && Crea una ficha
MiFicha.Left = 10 && Cambia el valor de la propiedad Left a 10
MiFicha.Lefty = 12 && Añade una nueva propiedad llamada Lefty
ƒ
Text MiFicha
Top 10
MiFicha
ƒ
ƒ
MiFicha Text ¡Mi ficha es grande!
Top 10
ƒ
MiFicha2
Hola ƒ
MiFicha Text ¡Mi ficha es grande!
Top 10
ƒ
MiFicha2
ƒ
Boton1.Top
Boton1.Left
ƒ
ƒ
ƒ
Boton1 Boton1
Boton2.Top
Boton2 Boton2
Boton2.Left
MiFicha Boton3 Boton3
ƒ
ƒ
ƒ
Tercero.Top
Tercero.Left
Tercero ƒ
Disponer de una referencia adicional al objeto hijo es útil cuando está contenido en
varios niveles de objetos, como por ejemplo una opción de menú contenida en un menú
de cascada, contenido en un menú desplegable, contenido en una barra de menús.
En lugar de especificar toda la vía de las referencias a objeto, una referencia adicional
puede simplificar el acceso a la opción de menú. (El Capítulo 16 describe cómo crear
menús para las fichas.)
Para hacer referencia a los objetos padres, también puede utilizar la propiedad Parent
del objeto hijo. Todos los objetos estándar del interface de usuario, excepto las fichas,
tienen una propiedad Parent que contiene una referencia al objeto padre. En la mayoría
de los casos, la propiedad Parent hace referencia a una ficha. La excepción es el objeto
Menu, que puede contener otros objetos Menu. Este ejemplo crea un controlador de
sucesos OnClick para MiBoton que hace referencia a una propiedad de MiFicha
mediante la propiedad Parent:
MiFicha.MiBoton.OnClick = Hola
PROCEDURE Hola
this.Parent.Text = "¡Hola!"
RETURN
Para la mayoría de objetos de ficha, this.Parent equivale a form. Lo más común es
utilizar this.Parent en los controladores de sucesos OnClick para que los objetos de
menú hagan referencia al menú principal.
Liberación de objetos
Para las variables de memoria tradicionales, el ámbito, por ejemplo local o privado,
determina la vida de la variable. Por ejemplo, la vida de una variable local está limitada
a la subrutina en que se declara. (El Capítulo 5 describe los ámbitos de las variables.)
Un objeto existe hasta que se libera, con la siguiente excepción: un objeto se libera de
forma automática cuando se liberan todas las variables de referencia que hacen
referencia a él.
El ejemplo siguiente lo demuestra:
MiObj = NEW Object() && El objeto tiene una referencia: MiObj
MiObj2 = MiObj && El objeto tiene dos referencias: MiObj y MiObj2
RELEASE MiObj && La variable MiObj se libera, pero el objeto aún existe
RELEASE MiObj2 && MiObj2 se libera, y también el objeto
Como con las variables de memoria tradicionales, puede liberar un objeto de forma
explícita en cualquier momento de una de las dos formas siguientes:
• Ejecute el método Release del objeto. Todos los objetos del interface de usuario, como
los campos de entrada y los botones, tienen un método Release estándar.
• Utilice el comando RELEASE OBJECT, que libera el objeto al que hace referencia una
variable de referencia a objeto, pero no libera la variable.
Importante Observe la diferencia entre RELEASE OBJECT en el ejemplo siguiente y RELEASE en el
ejemplo anterior:
MiObj = NEW Object() && El objeto tiene una referencia: MiObj
MiObj.Nombre = "Juan" && Se añade una propiedad
MiObj2 = MiObj && El objeto tiene dos referencias: MiObj y MiObj2
RELEASE OBJECT MiObj && El objeto a que hace referencia MiObj se libera; MiObj
&& aún existe
? MiObj && Devuelve "Object" porque no hace referencia a nada
? EMPTY(MiObj) && Devuelve .T.
? MiObj.Nombre && Se produce un error: Intento de acceder a un objeto
&& liberado
RELEASE MiObj,MiObj2 && MiObj y MiObj2 se liberan
Cuando se crean objetos del interface de usuario, como fichas, botones y campos de
entrada, Visual dBASE crea automáticamente una referencia interna además de las
creadas por el programador. Así garantiza que al menos siempre exista una referencia
para cada objeto. En consecuencia, la única forma de liberar un objeto del interface de
usuario es mediante RELEASE OBJECT o el método Release del objeto.
MiFicha = NEW FORM() && La ficha tiene dos referencias: MiFicha y una interna
DEFINE TEXT MiTexto OF MiFicha && El objeto tiene dos referencias: MiTexto y una interna
DEFINE ENTRYFIELD MiEntrada OF MiFicha
RELEASE MiFicha && La ficha todavía tiene una referencia: la referencia interna
RELEASE MiTexto && El objeto no es liberado
Cuando se libera un objeto que contiene otro objeto, como una ficha que contiene un
botón de comando, también se liberan todos sus objetos hijos.
Es posible utilizar los métodos de una matriz sea cual sea la forma en que se declaró.
DECLARE Matriz[6,10] && Declara una matriz de 6 filas y 10 columnas
Matriz.Dir() && Se rellena con un listado del directorio actual
La Tabla 10.1 resume los métodos que hay disponibles para las matrices:
Tabla 10.1 Resumen de los métodos de la clase Array
Método Descripción
Add() Añade un elemento.
Delete() Borra un elemento, columna o fila.
Dir() Rellena la matriz con el listado del directorio actual.
DirExt() Rellena la matriz con el listado del directorio actual y los atributos extendidos
(Win95).
Element() Devuelve el número de elemento de un subíndice (fila y columna) especificado.
Fields() Rellena la matriz con la estructura de la tabla actual.
Fill() Inserta un valor especificado en uno o más elementos.
Grow() Añade un elemento, columna o fila.
Insert() Inserta un valor de falso (.F.) en un elemento especificado.
Resize() Aumenta o disminuye el tamaño de la matriz.
Scan() Busca en la matriz una expresión especificada.
Sort() Ordena los elementos de una matriz unidimensional o bidimensional.
Subscript() Devuelve el subíndice (fila y columna) del elemento cuyo número se especifica.
Grow(), Size
Este ejemplo crea una matriz con el mismo número de elementos que registros hay en
CLIENTE.DBF. Después, rellena la matriz con valores de la tabla, utiliza Grow() para
añadir una segunda columna, que rellena con valores de la tabla, y muestra el resultado.
USE Cliente.DBF
ObjMat=NEW ARRAY(RECCOUNT()) && Inicializa un objeto de matriz
GO TOP
SCAN && Rellena la matriz con el campo Nombre
ObjMat[RECNO()]=Cliente->Nombre && de Cliente.DBF
ENDSCAN
Add()
Este ejemplo simplifica el anterior utilizando el método Add() para rellenar la matriz.
USE Cliente.DBF
ObjMat=NEW ARRAY()
SCAN
ObjMat.Add(Customer->Name)
ENDSCAN
FOR i = 1 TO ObjMat.Size
? ObjMat[i]
NEXT
Scan(), Subscript()
Este ejemplo muestra otra forma de rellenar una matriz a partir de una tabla. Utiliza
Scan() para buscar una cadena en la matriz y Subscript() para mostrar su posición.
USE Animales.DBF
ObjMat=NEW ARRAY(RECCOUNT(),3) && Inicializa un objeto de matriz
COPY TO ARRAY ObjMat FIELDS Nombre,Area, Peso && Llena la matriz con valores de la tabla
Cadena = "Loro"
aElemento = ObjMat.Scan(Cadena) && Busca la cadena en la matriz
aFila = ObjMat.SUBSCRIPT(aElemento,1)
aCol = ObjMat.SUBSCRIPT(aElemento,2)
? Cadena +"Encontrado en la fila " + ;
LTRIM(STR(aFila)) + ", columna " + ;
LTRIM(STR(aCol))
Suponga que desea crear una matriz que almacene los ganadores del premio Oscar a la
mejor película en la década de los 80. Con una matriz dispersa, puede utilizar el año
como posición de índice sin crear elementos no utilizados. El ejemplo siguiente crea una
matriz dispersa denominada MejorPeli, almacena las películas ganadoras del Oscar de
cada año y vincula la matriz con un cuadro de incremento de una ficha.
MejorPeli = NEW OBJECT()
MejorPeli[1980] = "Gente corriente"
MejorPeli[1981] = "Carros de fuego"
MejorPeli[1982] = "Gandhi"
MejorPeli[1983] = "La fuerza del cariño"
MejorPeli[1984] = "Amadeus"
MejorPeli[1985] = "Memorias de Africa"
MejorPeli[1986] = "Platoon"
MejorPeli[1987] = "El último emperador"
MejorPeli[1988] = "Rain Man"
MejorPeli[1989] = "Paseando a Miss Daisy"
FichaMejor = NEW FichaPeli()
FichaMejor.ReadModal()
CLASS FichaPeli OF FORM
this.MDI = .F.
this.Text = "Oscars de los Ochenta"
DEFINE TEXT Solicitud OF this ;
PROPERTY ;
top 3, ;
left 5, ;
width 20, ;
text "Elige un año"
DEFINE SPINBOX ans OF this ;
PROPERTY ;
top 3, ;
left 15, ;
rangemin 1980, ;
rangemax 1989, ;
rangerequired .T., ;
value 1980, ;
onChange {;form.Peli2.Text = MejorPeli[this.Value]}
DEFINE TEXT peli1 OF this ;
PROPERTY ;
top 7, ;
left 5, ;
width 20, ;
text "Mejor película..."
DEFINE TEXT peli2 OF this ;
PROPERTY ;
top 10, ;
left 5, ;
width 40, ;
height 2, ;
fontSize 15, ;
text MejorPeli[form.Ans.Value]
ENDCLASS
Count( )
Utilice Count( ) para determinar el número de elementos que contiene la matriz
asociativa. Para el objeto NumSerie del ejemplo anterior, NumSerie.Count( ) devuelve 4.
IsIndex( )
Utilice IsIndex( ) para determinar si la etiqueta dada es un subíndice válido de la matriz.
Tenga en cuenta que las etiquetas utilizadas para subíndices diferencian mayúsculas y
minúsculas. Los ejemplos siguientes muestran los valores devueltos para el objeto
NumSerie.
? NumSerie.IsIndex(“Verde”) && Devuelve .T., es un subíndice la matriz
? NumSerie.IsIndex(“verde”) && Devuelve .F., uso distinto de mayús/minús
? NumSerie.IsIndex(“Blanco”) && Devuelve .F., no está en la matriz
NextIndex( ), FirstIndex
Utilice NextIndex( ) para determinar la secuencia de elementos en una matriz asociativa.
Puesto que las matrices asociativas utilizan etiquetas para los subíndices, en lugar de
números, no hay ninguna ordenación inherente de los elementos de la matriz. No es de
esperar que los elementos estén en el mismo “orden” en que se crearon. Llame el
método NextIndex( ) con el mismo nombre de un subíndice de elemento existente para
determinar qué elemento es el siguiente en el orden interno de los elementos en dBASE.
Si pasa el subíndice del último elemento de la matriz, NextIndex( ) devuelve .F.,
indicando que no hay ningún elemento siguiente. El ejemplo siguiente muestra un
procedimiento de repetición por los elementos de la matriz asociativa NumSerie en
orden. Para encontrar el primer elemento, se comprueba el valor de la propiedad
FirstIndex.
PROCEDURE ImprNumSerie
LOCAL cNumSerie, nRecuento, i
Capítulo
11
Uso de las clases
Capítulo 11
Declaración de clases
Para declarar una clase, utilice el comando CLASS...ENDCLASS, del que puede ver una
descripción completa en la Referencia del lenguaje. Éste es un resumen de la sintaxis:
CLASS <nombre clase> [(<parámetros>)][OF <nombre superclase>[(<parámetros>)]][CUSTOM]
[FROM <nombrearchivo>]
[PROTECT <listaPropiedades>]
<código constructor>
<declaraciones de métodos>
ENDCLASS
El cuerpo de una declaración de clases está formado por:
• Sentencia PROTECT, que declara qué propiedades y métodos de la clase están
disponibles sólo para la clase y sus descendientes.
• Código constructor, que se ejecuta cuando se crea un objeto de esa clase. El código
constructor es lo que realmente crea los miembros del objeto. Puede contener
cualquier comando de dBASE, aunque suele consistir sólo en sentencias de
asignación de propiedades y métodos. El propósito del código constructor es crear
las propiedades del objeto y definir sus valores iniciales.
• Las declaraciones de métodos, por ejemplo procedimientos o funciones. Un método
contiene código que se ejecuta en algún momento posterior a la creación del objeto.
El propósito de estas subrutinas es realizar acciones sobre las propiedades.
Una subrutina puede servir como método para más de un objeto. El ejemplo siguiente
demuestra esto:
O = NEW Object()
O.x = 10
O.SumaUno = FuncSumaUno
? O.SumaUno() && Devuelve '11'
? O.x && Devuelve '11'
Y = NEW Object()
Y.x =30
Y.z = FuncSumaUno
? Y.z() && Devuelve '31'
FUNCTION FuncSumaUno
this.x = this.x + 1
RETURN this.x
PROCEDURE DefNSS(cNSS)
IF This.NSS <> “ - - “
IF EsCorrecto()
This.NSSN= cNSS
ENDIF
ENDIF
RETURN
FUNCTION ObtnNSS
RETURN This.SSN
PROCEDURE DefSalario(nNuevoSalario)
IF ObAutorizacion()
This.Salario = nNuevoSalario
ELSE
? “Transacción no autorizada”
ENDIF
RETURN
FUNCTION ObtSalario
RETURN This.Salario
FUNCTION EsCorrecto
RETURN EjecCompFicha()
FUNCTION ObtAutorizacion
RETURN EjecFichaObtContrasena()
ENDCLASS
En la clase Empleado, las propiedades Salario y NSS y los métodos EsCorrecto( ) y
ObtAutorizacion( ) están protegidos. El usuario de un objeto de la clase Empleado
puede tener acceso y cambiar directamente las propiedades Nombre y Departamento.
Para cambiar la propiedad Salario, el usuario debe emplear el método DefSalario( ).
Si intenta ver, o cambiar, el valor de Salario directamente, aparece el error “Propiedad
no accesible”. Si abre el Inspector para el objeto Empleado, la propiedad Salario no
aparecerá en la lista de propiedades.
Cuando ejecuta el método DefSalario( ), éste llama el método DefAutorizacion( ), que el
usuario no puede llamar directamente porque está protegido. DefAutorizacion( ) no
aparecerá en la lista de métodos en el Inspector.
Para que el usuario vea el valor actual de Salaioy, debe llamar a DefSalario( ).
ObtSalario( ) y DefSalario( ) son parte del interface de la clase; constituyen el medio por
el que un usuario interactúa con la clase. Salario y ObtAutorizacion( ) son parte de la
implementación; son valores y código internos a los que el usuario de la clase no
necesita tener acceso directamente para utilizarla.
La misma situación se produce para la propiedad NSS, que sólo puede leerse y
modificarse a través de los métodos no protegidos ObtNSS( ) y DefNSS( ). DefNSS( )
llama al método protegido EsCorrecto( ), al que no puede llamar el usuario.
Respecto al diseñador de la clase, el uso de propiedades y métodos protegidos le
permite garantizar la integridad de la clase protegiéndola de modificaciones no
deseadas en las propieades. El diseñador tiene libertad para cambiar cambiar cualquier
parte de la implementación sin miedo a romper el código escrito por los usuarios de la
clase, siempre que el interface permanezca igual. Por ejemplo, en la clase Empleado
anterior, DefSalario( ) llama actualmente el método protegido ObtAutorizacion( ).
DefSalario( ) podría cambiarse para llamar otro método o no llamar ninguno. Dado que
DefAutorizacion( ) está protegido, los usuarios no tendrán llamadas directas a él en su
código. Por tanto, no se verán afectados si DefAutorizacion( ) cambia, o desaparece por
completo, siempre que DefSalario( ) continúe dando el mismo resultado.
Clase: Base
Propiedad A
Método A
En esta figura:
• Base es una superclase de Derivada1 y Derivada2.
• Derivada1 y Derivada2 son subclases de Base.
• Derivada1 es una superclase de Derivada3.
No confunda las clases heredadas con los objetos contenidos. (El Capítulo 10 describe los
contenedores de objetos.) Cuando un objeto contiene a otro, existe una copia de cada
objeto hijo asociado a su objeto padre. El objeto hijo es una parte del padre. Por otra parte,
cuando se deriva una subclase de una superclase, la primera sólo comparte las
características de la segunda. La subclase es un tipo de su superclase.
De forma parecida, cuando se declara una subclase basada en una clase estándar, es
necesario declarar un parámetro para que la clase reciba la referencia a la ficha.
No importa qué nombre se da al parámetro.
El ejemplo siguiente declara una subclase en función de la clase estándar Pushbutton.
La clase MiBoton sirve como clase por defecto de los botones (de comando) y contiene
los parámetros iniciales de todos los botones derivados de esta clase. A continuación,
BotonSonido (un botón que produce un sonido) se deriva de MiBoton.
CLASS MiBoton(ficha) OF PUSHBUTTON(ficha) && Declara los parámetros de la ficha
this.text = "Mi botón" && Asigna las propiedades que tendrán
this.FontName = "Arial" && todos los botones
this.FontBold = .T.
this.FontWidth = 6
this.SetWidth = {;this.width = LEN(this.text)+10}
ENDCLASS
CLASS BotonSonido(ficha) OF MiBoton(ficha) && Declara los parámetros de la ficha
this.text = "Suena" && Sobrescribe la propiedad Text
this.Onclick = {;? CHR(7)} && Asigna un bloque de código a OnClik
this.SetWidth() && Llama al método heredado
ENDCLASS
Al igual que this y form, class y super sólo son efectivos dentro de un contexto que
indique cuál es la clase actual. Es posible utilizar class o super:
• Dentro de una declaración de clase, donde la clase actual es la que se está declarando.
La clase siguiente se generó en el Diseñador de fichas. El suceso OnClick del botón de
comando tiene asigando el procedimiento BOTON1_ONCLICK de la clase actual.
CLASS Sonido OF FORM
this.EscExit = .T.
this.Text = "Ficha dBASE"
this.Width = 65.25
this.Top = 8.08
this.Left = 25.00
this.Height = 34.25
DEFINE PUSHBUTTON BOTON1 OF this;
PROPERTY;
OnClick class::BOTON1_ONCLICK,; && Asigna BOTON1_ONCLICK de la clase actual
text "BOTON1",;
Width 21.00,;
Top 12.00,;
Left 12.00,;
Height 4.00
PROCEDURE BOTON1_OnClick
? chr(7)
ENDCLASS
• Dentro de las declaraciones de un método, donde la clase actual es aquélla a partir de
la cual se creó el objeto que contiene el método.
El ejemplo siguiente modifica el ejemplo anterior de BotonSonido. El procedimiento
OnClick de la clase SuenaMueve hace referencia a ProcSonido de la clase
BotonSonido mediante super:
CLASS BotonSonido(ficha) OF MiBoton(ficha)
this.text = "Suena"
this.Onclick = CLASS::ProcSonido
this.SetWidth()
PROCEDURE ProcSonido
? CHR(7)
RETURN
ENDCLASS
Por medio del operador de resolución de ámbito, es posible llamar un método desde
una clase, aunque no se haya creado ninguna copia de esa clase. En primer lugar, como
cualquier procedimiento o función, la declaración de una clase debe residir en el archivo
de programa actual o cargarse como archivo de procedimiento con SET PROCEDURE.
A continuación, llame el método especificando el nombre de clase con el operador de
resolución de ámbito antes del nombre del método. En realidad, un método incluido
dentro de una clase toma el nombre de clase como parte de su propio nombre.
Éste es un ejemplo simple:
? Miclase::DiHola() && Devuelve "¡Hola!"
CLASS Miclase
FUNCTION DiHola
? "¡Hola!"
RETURN .T.
ENDCLASS
El ejemplo siguiente demuestra una razón más práctica para llamar un método desde
una clase. Suponga que escribe una aplicación que crea muchas copias de una ficha
concreta. La aplicación necesita saber cuántas fichas se han creado y debe poder crear
una referencia a cualquiera de ellas.
En la declaración de clase siguiente, VariasFichas, el método CuantasFichas devuelve el
número de fichas creadas a partir de la clase. El método ReferFicha devuelve una
referencia a una ficha especificada. Puesto que no se sabe cuántas fichas existen ni si hay
una siquiera, es posible activar estos métodos directamente desde la clase.
? VariasFichas::CuantasFichas() && Devuelve el número de fichas creadas
PrimFicha = VariasFichas::ReferFicha(1) && Devuelve una referencia a la primera
&& ficha creada
* La siguiente línea devuelve una referencia a la última ficha creada
UltFicha = VariasFichas::ReferFicha(VariasFichas::CuantasFichas())
CLASS VariasFichas OF FORM
this.OnOpen = CLASS::FICHA_ONOPEN
PROCEDURE Ficha_OnOpen
PUBLIC XMatriz && En XMatriz se guardará una referencia de
&& cada ficha creada
IF EMPTY(XMatriz)
XMatriz = NEW Array(0)
ENDIF
this.Indice = XMatriz.Add(this)
this.Texto = STR(this.Indice)
RETURN
PROCEDURE CuantasFichas
IF .NOT. EMPTY(XMatriz)
RETURN XMatriz.Size
ELSE
RETURN 0
ENDIF
RETURN
PROCEDURE ReferFicha(i)
IF .NOT. EMPTY(XMatriz)
RETURN XMatriz[i]
ELSE
RETURN .F.
ENDIF
RETURN
ENDCLASS
Ahora, suponga que desea que un botón, además de emitir el sonido, se mueva cuando
se hace clic en él. La subclase siguiente, derivada de BotonSonido, hereda su
funcionalidad de sonido y la modifica.
CLASS SuenaMueve(Ficha, Ext_Sup, Ext_Izq) OF BotonSonido(Ficha, Ext_Sup, Ext_Izq)
this.text = "Suena y se mueve" && Texto por defecto para el botón
this.SetWidth() && Llama al método heredado para establecer la anchura
PROCEDURE OnClick && Declara una versión modificada del método OnClick
BotonSonido::OnClick() && Llama al método OnClick de BotonSonido
this.left = this.left+1 && Se añade movimiento al botón
RETURN
ENDCLASS
La subclase siguiente declara un botón sonoro que crece cuando se hace clic en él.
La idea es la misma que para SuenaMueve, pero la modificación se trata de otra forma.
En primer lugar, se anula OnClick con un bloque de código, no con un procedimiento.
Después, se llama el método OnClick sonoro mediante super en lugar de con el nombre
de la clase.
CLASS SuenaCrece(Ficha, Ext_Sup, Ext_Izq) OF BotonSonido(Ficha, Ext_Sup, Ext_Izq)
this.text = "Suena y crece"
this.SetWidth()
this.OnClick = {;Super::OnClick();this.Width = This.Width + 1}
ENDCLASS
Capítulo
• Proyectos en que hay más de un programador. Debido a que las subrutinas (métodos) y
variables (propiedades) están “ocultas” dentro de los objetos, es menos probable que
el trabajo de un programador interfiera con el de otro. De esta forma es más fácil
compartir código entre programadores.
• Proyectos que se modifican a menudo. El mantenimiento y actualización del código
orientado a objetos es más fácil. Una vez que una clase está escrita y depurada, puede
modificar su funcionalidad con facilidad derivando una subclase sin tocar el código
original.
Fundamentos procedurales
Los programadores proceden de una gran variedad de orígenes y sus enfoques de la
programación varían ampliamente. Sin embargo, el principio de diseño común que
todos los programadores siguen al fin y al cabo es la modularidad. Es decir, es posible
escribir un programa de 300 líneas que se ejecute secuencialmente de principio a fin,
pero es más fácil dividir las tareas del programa en módulos. Así, el programa de 300
líneas se convierte en un programa de 30 líneas más manejable que ejecuta varias
subrutinas.
Y para dividir una tarea en subrutinas, la mayoría de programadores adoptan un
planteamiento en dos fases:
1 Comienzan con la tarea más general y la dividen en componentes más pequeños.
Es la descomposición de arriba a abajo del problema.
2 Categorizan los componentes y los agrupan en una estructura jerárquica. Es el
ensamblaje de abajo a arriba de los componentes.
Mediante el diseño orientado a objetos, los programadores realizan los mismos pasos
con otro enfoque. Un programador procedural divide un problema en procedimientos y
los ensambla en una aplicación. Un programador orientado a objetos divide un
problema en clases y las ensambla en jerarquías de clases para formar una aplicación.
Algunas de las razones para este diferente planteamiento se explican en las dos
secciones siguientes.
Art Guantes
Talla 12
Precio 9995
MiObj CalcVal MiProc Procedimiento
Clase: Base
Propiedad A
Método A
Si necesita adaptar una clase para un uso ligeramente diferente, no edite la declaración
de la clase. En su lugar, derive una subclase y sustituya sólo las propiedades o métodos
que desee cambiar. Los objetos creados a partir de la subclase pueden usarse de la
misma forma que los creados a partir de la superclase. Sólo varía el comportamiento.
El polimorfismo implica dar a un objeto de una jerarquía de clases la capacidad de aplicar
una acción que es común a todos los objetos de la jerarquía, de la forma que sea más
apropiada para ese objeto. El polimorfismo (literalmente, “con varias formas”) significa
que los objetos de una jerarquía pueden compartir la misma subrutina por su nombre,
pero la subrutina puede tomar una “forma” distinta dentro de cada objeto.
El comando SKIP de dBASE ilustra las ventajas del polimorfismo. SKIP funciona de
forma distinta dependiendo del estado del área de trabajo actual. Si no hay ningún
índice activo, SKIP va al siguiente número de registro. Si el área de trabajo está
indexada, SKIP avanza al siguiente registro del índice. Si hay definido un filtro, SKIP
pasa al siguiente registro que cumpla la condición del filtro. No es necesario indicar a
SKIP cuál es el área de trabajo; basta teclear SKIP, y el comando sabrá lo que hacer.
Fases de diseño
Ahora que conoce algunos de los conceptos que subyacen en la orientación a objetos, se
tratará cómo diseñar una aplicación. Cualquier proyecto de software, sea cual sea el
método de diseño, es un proceso de analizar una situación, dividirla en componentes,
organizarlos e implantarlos. En el diseño orientado a objetos, los componentes que se
utilizan para construir la aplicación son clases.
Las siguientes son las fases generales en el diseño de una aplicación orientada a objetos:
1 Identificación de las clases.
Es la fase de descomposición de arriba a abajo conocida por los programadores
procedurales. Analice los requisitos del proyecto —los datos que debe controlar, las
tareas que debe realizar, la salida que debe producir— y construya una lista de clases
que modele estos requisitos. En este sentido, una clase es cualquier entidad física o
conceptual que tenga un propósito bien definido.
Los candidatos a clases más habituales son:
• Grupos de información, como clientes, pedidos o inventarios.
• Interfaces con los datos (normalmente fichas) para tareas como añadir, editar o
mostrar datos. Muchas de las clases que identifique se basarán en una ficha.
• Tareas especiales, como resumir, compilar o buscar datos.
2 Identificación de las tareas y datos que están asociados a las clases.
Para cada clase, elabore una lista de los datos que utiliza la tabla y las tareas que
realiza con ellos; por ejemplo, qué datos mostrarán las fichas o si el usuario deberá
añadir o editar elementos.
Un ejemplo
El supuesto de esta sección ejemplifica la codificación de una aplicación orientada a
objetos.
Va a escribir un programa para un pequeño negocio de pedidos por correo.
Necesita controlar información sobre los empleados (tanto a tiempo parcial como a
jornada completa) y calcular su remuneración cada semana. También es necesario
mantener una lista de direcciones de los clientes que realizan un pedido y de los
posibles clientes que aún no han pedido.
1 Identifique las clases.
Las principales clases de información son:
• Empleados a jornada completa
• Empleados a tiempo parcial
• Clientes
• Posibles clientes
2 Identifique las tareas y datos que están asociados a las clases.
En cada clase, necesita un interface para la edición y visualización básicas. Para los
empleados, necesita calcular su retribución cada semana.
La Tabla 12.1 resume los datos y las tareas que hay asociados a cada clase:
Tabla 12.1 Datos y tareas para las clases de ejemplo
Clase Datos Tareas
Empleados a jornada Nombre y dirección Visualizar y editar datos
completa Beneficios Calcular la paga semanal.
Salario
Empleados a tiempo Nombre y dirección Visualizar y editar datos.
parcial Pago por hora Calcular la paga semanal.
Clientes Nombre y dirección Visualizar y editar datos.
Número de pedidos
Posibles clientes Nombre y dirección Visualizar y editar datos.
Tipo de negocio
Nombre y dirección
LOCAL F,P,C,R
F = NEW JORNADACOMPLETA ()
F.OPEN()
P = NEW TIEMPOPARCIAL ()
P.OPEN()
C = NEW CLIENTE ()
C.OPEN()
R = NEW POSCLIENTE ()
R.OPEN()
PROCEDURE PB_CALCPAGO_OnClick
form.TF_PAGO.TEXT = STR(VAL(form.EF_PRIMA.VALUE)/26)
RETURN
ENDCLASS
Parte
III
Fichas
Parte III
Esta parte presenta los planteamientos que pueden adoptarse al construir aplicaciones
con fichas y trata la creación de fichas en cuanto a su relación con la programación.
Para ayuda sobre el uso del Diseñador de fichas, consulte la Guía del usuario.
Si sólo desea escribir controladores de sucesos para una ficha:
1 Lea el Capítulo 2 para una introducción para inexpertos sobre los programas
controlados por sucesos.
2 Consulte el Capítulo 14, “Escritura de controladores de sucesos,” para ver
instrucciones y ejemplos.
Para aprender sobre la creación de aplicaciones con fichas:
1 Lea el Capítulo 13, “Creación de aplicaciones con fichas.”
2 Busque en los Capítulos 14 y 15 detalles sobre el control de sucesos y el uso de
controles personalizados.
Lea el Capítulo 16, “Uso del código generado”, para comprender cómo trabajar con las
Utilidades de dos vías: el Diseñador de fichas y el Diseñador de menús.
Esta sección contiene los capítulos siguientes:
• Capítulo 13, “Creación de aplicaciones con fichas”
• Capítulo 14, “Escritura de controladores de sucesos”
• Capítulo 15, “Creación de controles y fichas personalizados”
• Capítulo 16, “Uso del código generado”
Capítulo
Figura 13.1 Ejemplo de controladores de sucesos para una ficha de entrada de datos y un cuadro de diálogo
Editar clientes
Buscar cliente
Nombre
Nombre
Dirección Asigne código al suceso
Valid de estos campos de
Ciudad entrada para comprobar Aceptar Cancelar
que no se dejan vacíos.
Provincia CP
La ficha EditCli de la Figura 13.1 es una ficha no modal. El usuario puede introducir
información dentro de esta ficha o cambiar el foco a otra. Cuando el usuario pulse el
botón Buscar, la aplicación debe saber el nombre qué buscar antes de continuar.
Es por lo que BuscaCli es una ficha modal; el usuario debe salir de la ficha BuscaCli
antes de hacer ninguna otra cosa. Muchas fichas modales son cuadros de diálogo que
obtienen información necesaria antes de volver a una ficha no modal.
Una propiedad relacionada con las fichas es MDI. Una ficha MDI tiene características
específicas que la hacen compatible con el interface MDI (de múltiples documentos) de
Windows. MDI es una característica de Windows que le permite abrir varias ventanas
dentro de la ventana de aplicación. Casi todas las aplicaciones Windows utilizan MDI
para gestionar varios documentos o varias vistas de un mismo documento dentro de la
ventana principal de la aplicación. Si desea que una ficha aparezca como ventana MDI,
defina la propiedad MDI como verdadero.
La lista siguiente enumera algunas de las características de las ventanas MDI:
• Al igual que las ventanas de aplicación, es posible cambiar su posición y tamaño. Si
MDI es .T., no se tienen en cuenta las propiedades Moveable y Sizeable.
• Son ventanas hijas de la ventana de aplicación y se listan en el menú Ventana, aun
cuando estén activas.
• Tienen un cuadro del menú Control, botones de maximización y minimización y una
barra de título que contiene el nombre de la ventana. Si MDI es .T., no se tienen en
cuenta las propiedades SysMenu, Maximize y Minimize.
• Cuando están activas, sus menús sustituyen a los de la barra de menús principal.
(Cuando la propiedad MDI es falso (.F.), los menús se muestran en la barra de menús
de la ficha.)
• Para cerrar la ficha, puede pulsar Ctrl+F4; para cerrar la ventana de aplicación, pulse
Alt+F4.
Importante Una ficha MDI no puede ser modal. Antes de abrir una ficha modal, defina como falso
(.F.) la propiedad MDI de la ficha.
DEFINE FORM MiModal FROM 10,10 TO 15,30 PROPERTY; DEFINE FORM MiNoModal FROM 10,10 TO 15,30
MDI .F.
DEFINE TEXT DiHola OF MiModal PROPERTY; DEFINE TEXT DiHola OF MiNoModal PROPERTY;
Top 1,; Top 1,;
Left 7,; Left 7,;
Text "¡Hola!" Text "¡Hola!"
DEFINE PUSHBUTTON DiAdios OF MiModal PROPERTY; DEFINE PUSHBUTTON DiAdios OF MiNoModal PROPERTY;
Top 3,; Top 3,;
Left 5,; Left 5,;
Text "Adiós",; Text "Adiós",;
OnClick {;form.CLOSE()} OnClick {;form.CLOSE()}
MiModal.ReadModal() MiNoModal.Open()
? CHR(7)+CHR(7)+CHR(7) && suena tres veces ? CHR(7)+CHR(7)+CHR(7) && suena tres veces
Variable pública en una ficha no modal Propiedad personalizada en una ficha no modal
PUBLIC DisparoFinal DEFINE FORM MiNoModal FROM 10,10 TO 15,30 PROPERTY;
DisparoFinal = "Adiós, mundo cruel" MDI .T.;
CUSTOM DisparoFinal "Adiós, mundo cruel"
DEFINE FORM MiNoModal FROM 10,10 TO 15,30 PROPERTY;
MDI .T. DEFINE TEXT DiHola OF MiNoModal PROPERTY;
Top 1,;
DEFINE TEXT DiHola OF MiNoModal PROPERTY; Left 7,;
Top 1,; Text "¡Hola!"
Left 7,; DEFINE PUSHBUTTON DiAdios OF MiNoModal PROPERTY;
Text "¡Hola!" Top 3,;
DEFINE PUSHBUTTON Adios OF MiNoModal PROPERTY; Left 5,;
Top 3,; Text "Adiós",;
Left 5,; OnClick ProcCerrar,;
Text "Adiós",; Width 8
OnClick ProcCerrar,;
Width 8 MiNoModal.Open()
Estrategias de programación
Como ya se ha mencionado en este capítulo, la mayoría de fichas de una aplicación
controlada por sucesos son no modales, permitiendo así que el usuario cambie el foco a
otras fichas, o incluso acceda a la ventana de comandos o al Selector. Aunque esta
libertad de movimientos es beneficiosa para el usuario, requiere un diseño esmerado
por parte del programador, que debe garantizar que la aplicación pueda coexistir con
otras utilidades.
Por esta razón, quizá no desee escribir una aplicación totalmente controlada por
sucesos. Las secciones siguientes describen tres enfoques que puede seguir.
Puede adoptar un solo planteamiento o una combinación de los mismos.
Interface modal
Abra todas las fichas como modales, empleando el método ReadModal() de la ficha o la
función READMODAL(). En un interface de usuario modal:
• Cada ficha retiene el foco en exclusiva, forzando que el usuario salga de la ficha antes de
continuar. Aunque es más restrictivo para el usuario, este enfoque es más sencillo
para los programadores, porque no tienen que tener en cuenta tantas acciones
posibles que el usuario puede realizar.
• El interface de Visual dBASE es inaccesible mientras se ejecuta la aplicación. Esto impide
que el usuario interfiera con las tablas empleadas en la aplicación mientras ésta se
ejecuta.
• La ejecución del programa se detiene cuando se muestra cada ficha, facilitando la gestión de
los ámbitos de las variables y de la disponibilidad de los procedimientos.
En cierto sentido, un interface modal también está controlado por sucesos (es posible
asignar controladores de sucesos a las fichas y los controles), aunque mantiene el control
sobre la secuencia de acciones, como una aplicación controlada por menús.
El código siguiente crea las fichas que se muestran en la Figura 13.1.
DEFINE FORM EDITCLI FROM 12.5,24.5 TO 31.5,70.38;
PROPERTY;
EscExit .T.,;
View "EDITCLI.QBE",;
Text "Editar clientes",;
Minimize .F.,;
Maximize .F.,;
MDI .F. && Es necesario para crear una ficha modal
DEFINE TEXT TEXTO1 OF EditCli;
PROPERTY;
ColorNormal "N/W",;
Text "&Nombre",;
Width 10.00,;
Top 1.00,;
Left 2.00,;
Height 1.00
Interface no modal
Abra la mayoría de fichas como no modales, mediante el método Open de la ficha o el
comando OPEN FORM. Utilice las fichas modales con moderación para obtener
información necesaria del usuario. Este enfoque sirve mejor al usuario y proporciona
estas ventajas:
• El usuario puede ejecutar más de un programa simultáneamente. En una aplicación grande,
por ejemplo, el usuario puede activar la ficha de entrada de pedidos, rellenar la
mitad, imprimir una relación de inventario y volver para terminar el pedido.
Esto reproduce el flujo de trabajo en el mundo real.
• El usuario puede acceder al interface de Visual dBASE, incluidos la ventana de comandos
y el Selector, lo cual es muy útil para escribir programas de utilidad que
proporcionen funciones especiales de búsqueda o visualización que complementen,
sin sustituir, el interface de Visual dBASE. Sin embargo, es posible desactivar el
interface de Visual dBASE mediante SHELL( ).
• La ejecución del programa continúa hasta su conclusión y no se detiene cuando se muestran
las fichas. El resto del programa se ejecuta mediante controladores de sucesos que
responden a las acciones del usuario.
Un interface no modal está completamente controlado por sucesos. Una vez que se
muestra la ficha inicial, el usuario es quien controla la secuencia de acciones.
El código siguiente crea las fichas que se muestran en la Figura 13.1.
* EditCli.prg
*
SET PROCEDURE TO PROGRAM(1) ADDITIVE
DEFINE FORM EDITCLI FROM 12.5,24.5 TO 31.5,70.38;
PROPERTY;
EscExit .T.,;
View "EDITCLI.QBE",;
Text "Ficha dBASE",;
Minimize .F.,;
Maximize .F.
DEFINE TEXT TEXTO2 OF EditCli;
PROPERTY;
ColorNormal "N/W",;
Text "&Nombre",;
Width 10.00,;
Top 1.00,;
Left 2.00,;
Height 1.00
*** El resto de textos y entradas siguen las mismas reglas que los anteriores. Se han
*** omitido del listado para ahorrar espacio.
ENDCLASS
Capítulo
Escritura de controladores
Capítulo 14
14
de sucesos
Cuando se programa con fichas, no se escribe código que se ejecute de forma secuencial.
Por el contrario, se escriben controladores de sucesos que se anexan a la ficha y/o a sus
controles y que se ejecutan cuando se producen los sucesos correspondientes.
Este capítulo explica cómo escribir controladores de sucesos, detalla la secuencia de su
ejecución y proporciona ejemplos de control de sucesos.
Para una introducción general a los programas controlados por sucesos, consulte el
Capítulo 2.
Los dos ejemplos de código anteriores realizan las mismas tareas, pero el de la izquierda
sólo funciona cuando se asigna a un botón denominado MiBoton de una ficha
denominada CompruSuc. El código de la derecha funciona con cualquier botón de
cualquier ficha.
Importante Las referencias this y form están disponibles sólo para los procedimientos vinculados
directamente a las propiedades de sucesos, no para los siguientes procedimientos que se
llamen. Si un procedimiento de control de sucesos llama a otro, y el segundo
procedimiento usa this o form, es necesario pasarle this o form como parámetro(s) al
segundo procedimiento.
El ejemplo siguiente modifica el ejemplo de la derecha de la Figura 14.1, pasando form a
un segundo procedimiento.
PROCEDURE AlertClick
form.Text = "!Ha pulsado mi botón!" && Cambia el título de la ventana
this.Text = "¡Hmphf!" && Cambia el texto del botón
DO Devuelve WITH form
RETURN
PROCEDURE Devuelve(RefForm)
RefForm.ColorNormal = "r/w*"
SLEEP 2
RefForm.ColorNormal = "r/w"
RETURN
3 Seleccione el suceso OnOpen del botón y haga clic en el botón Utilidades. Aparece el
editor de procedimientos.
La línea, this.Contar = 0, inicializa una propiedad personalizada del botón. Puesto que
el controlador de sucesos OnOpen está vinculado al botón, this hace referencia al objeto
de botón. Cuando el usuario abre la ficha, PUSHBUTTON_OnOpen se ejecuta y crea la
propiedad Contar del botón.
5 Cierre la ventana del editor de procedimientos.
Acaba de crear un controlador de sucesos vinculado al suceso OnOpen del botón.
Ahora, cree un controlador para el suceso OnClick.
6 Seleccione el suceso OnClick del botón en el Inspector y haga clic en el botón
Utilidades. Aparece un procedimiento vacío en el editor de procedimientos.
.T. o .F.
¿Al menos un .F.
When de control La ficha no se
evalúa como .T.? abre.
.T.
Si abre una ficha sin que haya otras fichas abiertas previamente:
1 Se ejecutan los controladores de sucesos When de todos los controles de la ficha.
Si hay al menos uno que se evalúe como .T., continúe en el paso 2. De lo contrario, la
ficha no se abre.
2 Se ejecuta el controlador de sucesos OnOpen de la ficha. La ventana se abre y recibe el
foco.
3 Se ejecuta el controlador de sucesos OnOpen de todos los controles de la ficha.
La ficha no se
cierra.
Ejecución de procedimientos
El controlador de sucesos más común es uno que realiza una acción en respuesta a un
clic del ratón. Estos controladores se vinculan con los sucesos OnClick de botones u
opciones de menú. Los controladores de sucesos OnClick pueden ser de cualquier tipo,
aunque muchos realizan acciones simples como cerrar la ficha actual o abrir otra.
El siguiente controlador de sucesos OnClick puede anexarse a un botón Aceptar o a una
opción de menú Archivo|Salir:
PROCEDURE CierraFicha
form.Close()
form.Release()
RETURN
Los sucesos OnClick se gestionan en las fichas:
• Asignando subrutinas directamente a la propiedad OnClick de botones u opciones
de menú. Es el método más recomendable en la mayoría de fichas.
• Gestionándolos para toda la ficha con ON SELECTION o con el sucesos OnSelection.
Este método podría ser preferible para los programadores familiarizados con las
técnicas de menús de dBASE DOS o para los acostumbrados a las técnicas de
programación de Windows.
Si se hace clic en un botón o se elige una opción de menú, se valida una ficha. Cuando el
usuario valida una ficha, ocurre lo siguiente:
• Si la ficha contiene uno o más botones, y el seleccionado (o el botón por defecto si no
se seleccionó ninguno) tiene un controlador de sucesos OnClick, se ejecuta éste.
• Se ejecuta el controlador de sucesos OnSelection de la ficha o la subrutina ON
SELECTION (lo que se haya especificado).
El valor de la propiedad Id del botón seleccionado (o por defecto), o de la opción de
menú elegida, se pasa al controlador de sucesos OnSelection o al procedimiento ON
SELECTION.
El ejemplo siguiente muestra una declaración de clase de una ficha que contiene cuatro
campos de entrada y un botón. El usuario pulsa Intro en un campo para marcarlo y
desactivarlo. El clic en el botón de comando desmarca todos los campos de entrada.
El controlador de sucesos OnSelection utiliza el parámetro Id para determinar qué
campo desactivar.
CLASS MarcaCampos OF FORM
this.OnSelection = CLASS::FICHA_ONSELECTION
this.Text = "Mire como funciona OnSelection"
this.Width = 55.38
this.Top = 6.19
this.Left = 30.75
this.Height = 16.00
this.Minimize = .F.
this.Maximize = .F.
Validación de datos
La validación de los datos introducidos por el usuario es una tarea importante en las
fichas de entrada de datos. Las tres propiedades siguientes se complementan para
realizar la validación de datos en los objetos de campo de entrada, cuadro de
incremento, cuadro combinado y Browse:
• Valid se ejecuta cuando el usuario realiza un cambio en el valor del control e intenta
salir de él (por ejemplo, pulsando Tab). El controlador de sucesos Valid debe evaluar
el nuevo valor y devolver .T. si es válido o .F. si no lo es. El valor devuelto .F. impide
que el usuario pueda salir del control.
• ValidRequired determina si el controlador de sucesos Valid se ejecuta cada vez que el
foco sale del control (incluso cuando contiene un valor por defecto) o sólo cuando el
usuario efectúa cambios.
• ValidErrorMsg especifica un mensaje que se muestra en la barra de estado cuando el
controlador de sucesos Valid devuelve un valor de .F.
El siguiente es un ejemplo del uso de estas propiedades para validar datos.
Si solicita al usuario que introduzca una hora, es lógico que desee asegurarse de que sea
una hora válida. El siguiente controlador de sucesos de la propiedad Valid valida la
hora introducida por el usuario.
DEFINE ENTRYFIELD Tiempo OF FichaTiempo; && Entrada para la hora
PROPERTY;
Left 15,;
Width 5,;
Picture "99:99",;
Valid ValHora,; && Asigna un controlador de sucesos
ValidRequired .T.,; && Se quiere validar
ValidErrorMsg "Hora no válida",; && Asigna un mensaje de error
this.Left = 2.00
this.Height = 15.00
DEFINE TEXT TEXTO1 OF THIS;
PROPERTY;
ColorNormal "N/W",;
Text "Forma de pago",;
Width len(this.text),;
Top 2.00,;
Left 4.00,;
Height 2.00
DEFINE COMBOBOX CUADROELEM1 OF THIS;
PROPERTY;
Width 16.00,;
Top 3,;
Left 4.00,;
Height 6.50,;
Style 1,;
DataSource "ARRAY FormaPago",; && Enlaza el cuadro combinado con la matriz
Value FormaPago[1],; && Inicializa Value con el primer elemento
OnChange class::CambiaCuadElem && Asigna un controlador de sucesos
DEFINE TEXT TEXTO2 OF THIS;
PROPERTY;
ColorNormal "N/W",;
Text " ",;
Width len(this.text)+15,;
Top 2.00,;
Left 22.00,;
Height 2.00
DEFINE ENTRYFIELD ENTRADA1 OF THIS;
PROPERTY;
Width 17.00,;
Top 3.00,;
Left 20.00,;
Height 2.00,;
Value 0,;
Border .T.,;
When {form.Texto2.Text <> " "} && Accesible solo si el pago no es en efectivo
DEFINE TEXT TEXTO3 OF THIS;
PROPERTY;
ColorNormal "N/W",;
Text "Cantidad pagada",;
Width len(this.text)+5,;
Top 6.00,;
Left 20.00,;
Height 2.00
DEFINE ENTRYFIELD ENTRADA2 OF THIS;
PROPERTY;
Width 17.00,;
Top 7.00,;
Left 20.00,;
Height 2.00,;
Value 0,;
Border .T.,;
Picture "999999.99"
Refresh( )
En ocasiones, si una ficha utiliza datos que pueden cambiar una fuente situada fuera de
la ficha (por ejemplo, otra ficha), quizá sea necesario forzar que la ficha actualice sus
vínculos de datos para asegurar que se muestran los datos más actuales. Para lograrlo,
utilice el método Refresh( ) de la ficha. El ejemplo siguiente muestra cómo puede
emplearse Refresh( ) en el controlador de sucesos OnGotFocus para que los datos se
actualicen siempre que la ficha reciba el foco.
PUBLIC f
USE ANIMALES
f = NEW fForm()
f.open()
.T. .T.
form.E1.Valid form.E2.When form.E1.OnLostFocus form.E2.OnGotFocus
.F. .F.
PROCEDURE MueveMaria(nLeft,nTop)
this.Corderito.left=this.left+this.width +1
this.Corderito.top=this.top
RETURN
OnSize
Este ejemplo se ha tomado de CLOCK.PRG, del directorio EJEMPLOS, y muestra la
hora en una ventana. Cuando el usuario cambia el tamaño de la ventana del reloj, el
procedimiento ReSizeText redimensiona el texto que muestra la hora.
PROCEDURE CambiaTamText
local t && Crea una referencia al nuevo objeto
t = form.timeText
t.width = form.width && Adapta el tamaño del objeto texto
t.height = form.height && al de la ventana de la ficha
t.fontsize=(form.width+form.height)/2*1.5 && Redimensiona la fuente
RETURN
dBASE pasa tres parámetros a los sucesos mencionados en la Tabla 14.1, y también a
OnSize y Key:
• El parámetro de marcas es un valor de un solo byte que indica si las teclas Ctrl o Alt o
un botón del ratón estaban pulsados cuando se produjo el suceso. Use las funciones
de manipulación de bits, como BITSET() o BITAND(), para interpretar el valor.
• El parámetro de columna indica la columna en que está situado el puntero del ratón.
• El parámetro de fila indica la fila en que está situado el puntero del ratón.
En el código de los controladores de sucesos, siga la sintaxis normal para recibir
parámetros, como se describe en el Capítulo 4. Para más información sobre el parámetro
de marcas, consulte en la Referencia del lenguaje la entrada correspondiente a cualquiera
de los sucesos del ratón.
Capítulo
Para instalar controles VBX, siga las mismas instrucciones que para los controles
personalizados de dBASE y seleccione el archivo .VBX. Puesto que los archivos .VBX
son un tipo especial de DLL, dBASE añade la línea en la sección [DLLs] de
DBASEWIN.INI (no en la sección [CustomClasses]). Éste es un ejemplo:
[DLLs] && Marca el comienzo de la sección de Dlls
DLL0=C:\VISUALDB\EJEMPLOS\DBTIMER.VBX && Instala el control DBTIMER
DLL1=C:\VISUALDB\EJEMPLOS\SWITCH.VBX && Instala el control SWITCH
Como alternativa a la instalación de los controles VBX en el archivo DBASEWIN.INI, puede
instalarlos de forma individual utilizando LOAD DLL. El código siguiente carga los mismos
controles VBX especificados en el anterior, excepto que lo hace en un archivo de programa
(o en la ventana de comandos), en lugar de en DBASEWIN.INI::
LOAD DLL C:\DBASEWIN\EJEMPLOS\VCR1.VBX && Instala el control VCR1
LOAD DLL C:\DBASEWIN\EJEMPLOS\DBTIMER.VBX && Instala el control DBTIMER
LOAD DLL C:\DBASEWIN\EJEMPLOS\SWITCH.VBX && Instala el control SWITCH
La Figura 15.1 muestra los controles personalizados de dBASE contenidos en
BOTONES.CC y los controles VCR1.VBX, SWITCH.VBX y DBTIMER.VBX, listados en
la paleta de controles después de instalarlos:
Figura 15.1 Solapa Personalizado de la paleta de controles
Es fácil guardar un control como personalizado desde dentro del Diseñador de fichas.
Consulte la Guía del usuario para obtener información sobre el almacenamiento de los
controles personalizados. Para convertir manualmente una sentencia DEFINE en una
declaración CLASS de un control personalizado:
1 Cambie la línea que comienza con DEFINE por una declaración CLASS como la que se
muestra en la Figura 15.2.
• La palabra clave CUSTOM al final de la línea especifica que la declaración de clase
crea un control personalizado.
Importante • Los parámetros f y n reciben una referencia a la ficha y al nombre del control,
respectivamente. Las subclases basadas en clases estándar suelen precisar sólo un
parámetro que haga referencia a la ficha. Las clases de control personalizado
necesitan un parámetro de cadena adicional que represente el nombre del control.
Como en el caso del parámetro de ficha, es posible asignar cualquier nombre al
parámetro adicional. Este ejemplo utiliza n.
2 Elimine la línea que contiene PROPERTY;.
this.RealValue = ""
PROCEDURE BISWITCH1_OnOff
form.text = "Interruptor -- Apagado"
this.caption = "Apagado"
form.colornormal = "n/w"
RETURN
PROCEDURE BISWITCH1_OnOn
form.text = "Interruptor -- Encendido"
this.caption = "Encendido"
form.colornormal = "bg/r*"
RETURN
ENDCLASS
Cuando se crea una ficha basada en una personalizada, hereda todas sus propiedades.
Observe el código de la ficha Información de producto mostrada en la Figura 15.5:
** END HEADER -- no elimine esta línea*
* Generado el 05/17/95
*
parameter bModal
local f
f = new XYZPRODFORM()
if (bModal)
f.mdi = .F. && ficha no MDI
f.ReadModal()
else
f.Open()
endif
CLASS XYZPRODFORM OF XYZTEMPL From C:\DBW55\EJEMPLOS\XYZTEMPL.CFM
this.TopMost = .F.
this.Text = "Información de producto"
this.Left = 28.666
this.Height = 21.6465
this.Width = 101
this.Top = 8.7051
Capítulo
La Figura 16.1 muestra dónde introducir el código para cada sección en el Editor de
procedimientos.
Figura 16.1 Editor de procedimientos
Elija Cabecera para
introducir la cabecera.
Seleccione General para
introducir procedimientos.
Seleccione un controlador
de sucesos para editarlo.
Procedure BOTON1_OnClick
form.Texto1.Text = "Adiós"
DO WHILE form.Height >= 1 .and. form.Width >= 1
form.Height = form.Height - 1 Los procedimientos de
form.Width = form.Width - 1 control de sucesos siguen a
form.Top = form.Top + .5 la definición del último
form.Left = form.Left + .5 control y preceden a la
DO HacerRuido sentencia ENDCLASS.
ENDDO
form.Close()
RETURN
Los procedimientos de ENDCLASS
soporte siguen a la sentencia
ENDCLASS. En el Diseñador PROCEDURE HacerRuido
de fichas, introduzca estos ? CHR(7)
procedimientos eligiendo RETURN
General en la lista Método.
Barra de menús
Menú en cascada
El código siguiente, generado por el Diseñador de menús, crea los menús que se
muestran en la Figura 16.3:
Figura 16.4 Ejemplo de un archivo .MNU generado por el Diseñador de menús
La cabecera de ** END HEADER -- no borrar esta línea*
programa contiene * Generado el 13/07/94
comentarios.
Parameter ObjFichaj
NEW MYMENU(ObjFicha,"Raiz")
CLASS MYMENU(ObjFicha,Nombre) OF MENU(ObjFicha,Nombre) El texto que defina
this.Text = "" para el rótulo de
DEFINE MENU ARCHIVO OF THIS; menú se guarda en
PROPERTY; la propiedad Text.
Text "Archivo" El Diseñador de
DEFINE MENU ABRIR OF THIS.ARCHIVO; menús utiliza este
PROPERTY; texto para hacer
Text "Abrir" referencia al objeto.
DEFINE MENU GUARDAR OF THIS.ARCHIVO;
PROPERTY;
Text "Guardar"
DEFINE MENU GUARDAR_COMO OF THIS.ARCHIVO;
PROPERTY;
Text "Guardar como..."
DEFINE MENU IMPORT OF THIS.ARCHIVO;
PROPERTY;
Text "Importar"
DEFINE MENU TEXTO OF THIS.ARCHIVO.IMPORTAR; Un comando
PROPERTY; DEFINE crea cada
El cuerpo principal
Text "Texto" opción de menú.
del .MNU consiste
en la declaración de DEFINE MENU SONIDO OF THIS.ARCHIVO.IMPORTAR; El sangrado del
PROPERTY; código muestra la
clase, que comienza
con una sentencia Text "Sonido" jerarquía de las
DEFINE MENU IMAGEN OF THIS.ARCHIVO.IMPORTAR; opciones de menú.
CLASS y termina
con ENDCLASS. PROPERTY;
Text "Imagen"
DEFINE MENU EDICION OF THIS;
PROPERTY;
Text "Edición"
DEFINE MENU CLIENTES OF THIS.EDICION;
PROPERTY;
Text "Clientes"
DEFINE MENU PEDIDOS OF THIS.EDICION;
PROPERTY;
Text "Pedidos"
DEFINE MENU ARTICULOS OF THIS.EDICION;
PROPERTY;
Text "Artículos"
DEFINE MENU AYUDA OF THIS;
PROPERTY;
Text "Ayuda"
ENDCLASS
MiMenu Barra de
menús
Opciones de
Archivo Edición Ayuda la barra
Opciones
Abrir Guardar Guardar como Cerrar Importar Clientes Pedidos Artículos desplegables
Opciones de
Texto Sonido Imagen menú en
cascada
= Objeto de menú que contiene otro objeto de menú
= Objeto de menú que inicia una acción
MiMenu
Abrir Guardar Guardar c. Cerrar Texto Sonido Imagen Clientes Pedidos Artículos
El código del menú siguiente muestra cómo utilizar las propiedades de las barras de
menús:
** END HEADER -- no elimine esta línea*
* Generado el 05/17/95
*
Parameter FormObj
NEW MENUEJEMPLO(FormObj,"Root")
CLASS MENUEJEMPLO(FormObj,Name) OF MENUBAR(FormObj,Name)
This.OnInitMenu = CLASS::CompBorrarTodo
PROCEDURE CmpBorrarTodo
IF ALIAS() == ""
This.Edicion.Borrar_todo.Enabled = .F.
ENDIF
RETURN
ENDCLASS
En el código anterior, después de definir los menús, ciertos menús de teclas se asignan a
propiedades de la barra de menús que les dan automáticamente la funcionalidad que
requieren. Por ejemplo, cuando This.Edicion.Copiar se asigna a la propiedad
EditCopyMenu de la barra de menús, el menú Copiar toma las características
siguientes:
• El menú permanece atenuado a menos que haya texto resaltado en un objeto
adecuado de la ficha, como un campo de entrada o editor.
• Cuando hay texto resaltado, se activa el menú Copiar.
• Cuando se selecciona el menú Copiar, el texto resaltado se copia en el portapapeles
de Windows.
Las otras propiedades EditxxxMenu funcionan de forma similar.
La propiedad WindowMenu sólo es útil con los menús de nivel superior de las fichas
MDI. En el menú asignado a WindowMenu, se le añadirá automáticamente un menú
por cada ventana hija abierta. Esta característica supone un medio para que el usuario
cambie de una ventana a otra en la aplicación mediante los menús.
El código del menú anterior ilustra también el uso del controlador de sucesos
OnInitMenu para ajustar el sistema de menús. En el ejemplo, ese controlador
comprueba si hay una tabla abierta en el área de trabajo actual cuando se inicializa el
menú. Si no hay ninguna tabla abierta, la opción Borrar todo del menú Edición está
desactivada.
Los menús de una ficha pueden cambiarse mientras ésta está abierta. Por ejemplo,
puede cambiar las opciones de menú que se ofrecen dependiendo del control que esté
seleccionado actualmente. A continuación se muestran controladores de sucesos para
las propiedades OnGotFocus y OnLostFocus de un objeto Browse, respectivamente.
Cuando el objeto Browse recibe el foco, se activa el menú Edición definido previamente;
cuando pierde el foco, se atenúa el menú.
PROCEDURE MenusBrowse && Se asigna a OnGotFocus del objeto Browse
form.Root.Edicion.Enabled = .T.
RETURN
PROCEDURE NoMenusBrowse && Se asigna a OnLostFocus del objeto Browse
form.Root.Edicion.Enabled = .F.
RETURN
PROCEDURE Ficha_OnOpen
SET PROCEDURE TO EJEMPLO.POP ADDITIVE
THIS.POPUPMENU = NEW EMERGEJEMPLO(THIS, "MiEmerg")
RETURN
ENDCLASS
En el código anterior, el archivo del Popup (en este caso, EJEMPLO.POP) se abre como
archivo de procedimientos para que la ficha pueda utilizarlo. Entonces, se crea un nuevo
objeto Popup, que se asigna a la propiedad PopupMenu de la ficha. Observe que una
referencia a la ficha (This) y un nombre para el objeto Popup (MiEmerg, en el ejemplo )
deben pasarse como parámetros al constructor. Como parámetro de nombre, puede
utilizar cualquiera que elija.
Plano de coordenadas
Cuando dispone visualmente las fichas en el Diseñador de fichas, no es necesario que se
preocupe de las coordenadas en que se pone cada control. Simplemente ponga los
controles donde desee y el Diseñador de fichas genera las coordenadas. Sin embargo, si
escribe el código que crea los objetos de ficha, necesita introducir las coordenadas
manualmente.
Cada ventana de ficha tiene una fuente asociada (especificada por la propiedad
ScaleFontName) que determina el tamaño del plano de coordenadas en que se sitúan los
objetos en la ficha. Si no define esa propiedad, el plano se basa en la fuente
MS Sans Serif. Esto es, la altura de las filas depende de la altura de línea de la fuente
ScaleFontName, y el ancho de las columnas depende de la anchura de carácter de esa
fuente. Aunque cada control que ponga en la ficha podría tener una fuente distinta, las
coordenadas para situar los controles (definidas por las propiedades Top, Left, Height y
Width) siempre se basan en la fuente ScaleFontName.
La Figura 16.7 muestra controles con diferentes fuentes y tamaños que se han situado en
el plano de coordenadas.
Figura 16.7 Plano de coordenadas
La propiedad Top de
este cuadro es 6.
Su propiedad Left es 3.
La propiedad Top de este
botón de comando es 16. Su
propiedad Left es 21.
Para la ubicación precisa de los controles, puede especificar unidades de carácter con
valores decimales, por ejemplo,
DEFINE PUSHBUTTON OK OF MiFicha AT 3.5, 1.5 PROPERTY TEXT "Aceptar"
Direcciones relativas
Para permitir el direccionamiento relativo, los objetos de ficha tienen métodos
NextRow() y NextCol(). NextRow() devuelve la siguiente fila disponible en el plano de
coordenadas, dado el último control dibujado; NextCol() devuelve la siguiente columna
disponible. Por ejemplo, los controles siguientes se alinearán correctamente sean cuales
sean las fuentes que especifique:
FontHeight 14
DEFINE TEXT T1 OF MiFicha AT MiFicha.NextRow()+1,2;
PROPERTY Text PROPERTY Text "First line", FontName "Times", FontHeight 24
DEFINE TEXT T1 OF MiFicha AT MiFicha.NextRow()+1,2
PROPERTY Text "Second line", FontName "Helvetica", FontHeight 14
DEFINE TEXT T1 OF MiFicha AT MiFicha.NextRow()+1,2
PROPERTY Text "Tercera línea", FontName "Arial", Height 12
DEFINE TEXT T1 OF MiFicha AT ROW(),MiFicha.NextCol()
PROPERTY Text "Otra opción de la tercera línea"
Parte
IV
Tablas
Parte IV
Capítulo
17
Uso de las tablas
Capítulo 17
Creación de tablas
En Visual dBASE, es posible crear tablas de dBASE (.DBF), Paradox (.DB) y SQL.
Para crear una tabla, defina y dé un nombre a los tipos de campo que contiene. Por cada
campo, especifique su nombre, tipo y anchura, e indique también si el campo tendrá
una etiqueta de índice. (En las tablas de Paradox, defina un índice principal.)
Las definiciones de campos constituyen colectivamente la estructura de una tabla.
Es posible crear una tabla nueva y rellenar todas las descripciones de los campos
manualmente. O bien puede copiar la estructura de una tabla existente, realizar cambios
en las descripciones de los campos y guardar la estructura con otro nombre de tabla.
Para crear una nueva tabla, utilice CREATE. Este comando activa el Diseñador de
tablas, que le permite definir interactivamente los campos dentro de una tabla.
Para más información sobre el uso del Diseñador de tablas, consulte la Guía del usuario.
Para crear una tabla a partir de la estructura de una existente, utilice COPY
STRUCTURE o CREATE...FROM junto con COPY STRUCTURE EXTENDED.
CREATE...FROM crea una tabla basada en las definiciones de campos contenidas en un
archivo de descripción de tabla. Para crear uno de estos archivos, copie la estructura de
una tabla abierta con COPY STRUCTURE EXTENDED. El ejemplo siguiente demuestra
cómo hacerlo:
USE TBLMODEL && Abre la tabla a copiar
COPY TO TBLDESC STRU EXTE && Copia su estructura
USE TBLDESC && Abre el archivo de descripción de la tabla
BROWSE && Hace cambios en la descripción de los campos
CREATE NUEVATBL FROM TBLDESC && Crea la tabla nueva
Visual dBASE también proporciona el comando CREATE...STRUCTURE EXTENDED,
que le permite crear una nueva tabla basada en la estructura de la tabla abierta
actualmente.
También pueden crearse tablas .DBF de dBASE y SQL mediante el comando
CREATE TABLE de SQL. Este comando es especialmente conveniente porque puede
especificar los campos y crear la tabla en un solo comando. Para más información,
consulte el Capítulo 9 de la Referencia del lenguaje.
Para abrir explícitamente una tabla de otro tipo, incluya la extensión con el nombre del
archivo. Para mayor claridad en el código, puede especificar la opción TYPE con el
comando USE para sustituir el valor del parámetro DBTYPE sin especificar la extensión
del archivo.
USE FACTURAS TYPE PARADOX && Abre una tabla Paradox
SET DBTYPE TO PARADOX && Hace que el formato de tabla por defecto sea Paradox
USE DEVOLUC && Abre DEVOLUC.DB
USE NOMBRES.DBF && Abre una tabla dBASE
USE ELEM TYPE DBASE && Abre una tabla dBASE
Además, algunas funciones de dBASE, como por ejemplo EOF(), FOUND() y SEEK(),
también proporcionan opciones que especifican un área de trabajo.
SELECT 1 && Selecciona el área 1 como área de trabajo actual
SEEK("MA", 3) && Busca la provincia "MA" en el área de trabajo 3
&& Es necesario que la tabla este indexada por el campo de
&& búsqueda
IF FOUND(3) && Se determina si el registro fue encontrado
ƒ
ENDIF
Cuando acceda a datos de más de una tabla, probablemente deseará abrir una tabla en
la siguiente área de trabajo disponible. La función SELECT() devuelve el número de la
siguiente área de trabajo disponible.
USE NOMBRES && Abre NOMBRES.DBF
USE CIUDADES IN SELECT() && Abre la tabla en un área de trabajo disponible
USE PROVINC IN SELECT() && Abre la tabla en un área de trabajo disponible
Utilice estos comandos y funciones para obtener información sobre las áreas de trabajo:
• LIST STATUS muestra el área de trabajo en que está abierta cada tabla e indica qué
área de trabajo es la actual.
• DBF() devuelve el nombre de la tabla abierta en un área de trabajo específica.
• WORKAREA() devuelve el número del área de trabajo actual.
Copia de tablas
Visual dBASE proporciona varias opciones para realizar copias de una tabla, incluida la
copia de datos a las tablas de una base de datos. Es posible copiar toda una tabla, sólo
ciertos registros o sólo la estructura sin registros. También es posible copiar archivos
DOS individuales especificando su extensión.
• COPY copia toda una tabla o ciertos registros y campos seleccionados. La tabla que
desee copiar debe estar abierta. COPY también proporciona una opción TYPE que le
permite copiar una tabla de un tipo a otro, dBASE o Paradox. Si copia una tabla .DBF
que contiene campos memo a otra tabla .DBF, COPY crea automáticamente un
archivo memo para la nueva tabla. Si hay un índice activo, los registros se copian a la
nueva tabla en el orden del índice; sin embargo, COPY no crea un archivo .MDX para
la nueva tabla a menos que especifique la opción WITH PRODUCTION.
• COPY...WITH PRODUCTION copia una tabla de dBASE a otra tabla de dBASE con
otro nombre y también copia sus archivos asociados de índice de producción (.MDX)
y memo (.DBT).
• COPY STRUCTURE realiza una copia vacía de una tabla sin copiar sus registros.
La tabla de que desea copiar la estructura debe estar abierta antes de ejecutar el
comando COPY STRUCTURE.
• COPY TABLE copia una tabla y sus archivos asociados que tienen el mismo nombre,
como los archivos de índice de producción (.MDX) y memo (.DBT). Utilice COPY
TABLE para duplicar una tabla con rapidez. Para las tablas de Paradox, COPY
TABLE copia toda la familia de la tabla, incluidos los índices y los archivos .VAL.
No es necesario que estén abiertas las tablas que copie.
• COPY FILE copia cualquier tipo de archivo especificado por su extensión. Si copia
una tabla, debe estar cerrada antes de ejecutar el comando COPY FILE. Este comando
no copia los archivos .DBT ni .MDX con la tabla; cópielos por separado.
COPY FILE PROG.PRG TO PROVIEJO.PRG && Copia el archivo PROG.PRG
USE NOMBRES
COPY TO PERSONAS TYPE PARADOX && Copia NOMBRES.DBF a una tabla Paradox
COPY STRUCTURE TO CLIENTES && Copia la estructura de la tabla NOMBRES.DBF
COPY TABLE NOMBRES TO AGENDA && Copia la tabla NOMBRES.DBF y todos sus
&& archivos asociados a otra tabla dBASE
Borrado de tablas
Utilice DELETE TABLE, DELETE FILE, ERASE o el comando DROP TABLE de SQL
para borrar una tabla del disco de forma permanente.
ERASE borra un archivo del disco. DELETE FILE realiza la misma función que ERASE.
Ninguno de los dos comandos borra los archivos asociados, como archivos de índice o
memo; bórrelos por separado.
DELETE TABLE y DROP TABLE borran una tabla y sus archivos asociados con el
mismo nombre, como .MDX o .DBT. Sin embargo, no borran archivos, como por
ejemplo, fichas, informes, etiquetas o archivos de programa, que se utilicen con la tabla.
En el caso de las tablas de Paradox, DELETE TABLE o DROP TABLE borran toda la
familia de la tabla, incluidos los índices y los archivos .VAL.
La tabla que desee borrar, y sus archivos asociados, debe estar cerrada antes de ejecutar
el comando ERASE, DELETE FILE, DELETE TABLES o DROP TABLE.
ERASE TEMP.DBF && Borra el archivo TEMP.DBF
DELETE FILE TEMP.DBF && Hace la misma operación
DELETE TABLE TEMP.DBF && Borra la tabla TEMP.DBF y todos sus archivos asociados
Siempre que borre una tabla, asegúrese también de actualizar las fichas, informes,
etiquetas o archivos de programa que puedan depender de la información de la tabla.
Protección de datos
La accesibilidad de los datos puede limitarse a las personas que deben trabajar con ellos.
dBASE proporciona una utilidad interna, denominada PROTECT, que le permite crear
y mantener seguridad en las aplicaciones. PROTECT aporta mayor seguridad a una
base de datos mediante:
• El impedimento de que usuarios no autorizados se conecten al sistema
• El control de los archivos y los campos a los que puede tener acceso cada usuario
• El cifrado de los datos de las tablas
PROTECT sólo funciona con tablas .DBF de dBASE. Sin embargo, Visual dBASE
también proporciona la posibilidad de la administración de Contraseñas principales de
las tablas de Paradox. Por supuesto, Visual dBASE también respeta la seguridad de los
servidores de bases de datos SQL. Para más información sobre la definición de
seguridad, consulte la Guía del usuario.
Capítulo
GO puede utilizarse para situar el puntero de registro en una tabla de Paradox o SQL;
sin embargo, no puede especificarse un valor numérico, sino que debe emplearse el
indicador asignado a un registro en particular con las funciones BOOKMARK() o
RECNO().
GO TOP && Sitúa el puntero de registro al principio de la tabla
LOCATE FOR NOMBRE = "Case"&& Sitúa el puntero el primer registro en que NOMBRE = "Case"
gBkmark = BOOKMARK() && Guarda un indicador en una variable de memoria
GO TOP && Va al principio de la tabla
GO gBkmark && Sitúa el puntero de registro en la posición indicada por
&& el valor de la variable gBkmark
Aunque es posible utilizar indicadores asignados en comandos y funciones en lugar de
un número de registro, no puede mostrarse directamente el valor de un indicador.
Sin embargo, puede crear expresiones que comparan el valor relativo de un indicador
respecto a otro, por ejemplo,
IF BkMark1 < BkMark2 && Comprueba si el primer indicador va antes que el segundo en
&& la tabla
Adición de registros
Para añadir registros en una tabla, utilice los comandos APPEND e INSERT.
Normalmente, se utiliza el comando APPEND, y se deja que dBASE añada los registros
en la tabla (después del último registro de la tabla, si ésta tiene asignados números de
registro). INSERT apenas se utiliza, ya que precisa la reorganización de la tabla o de su
índice cada vez que se añade un registro.
Adición de registros
La ejecución del comando APPEND añade un nuevo registro y muestra una ventana en
que poder editar sus datos. APPEND BLANK añade un nuevo registro y sitúa el
puntero de registro en él, pero no lo muestra. Para editar los datos, utilice EDIT si desea
editarlo interactivamente o REPLACE para añadir datos en campos especificados.
USE EMPRESA
APPEND BLANK && Añade un registro al final de la tabla EMPRESA.DBF
&& y sitúa el puntero de registro en esa posición
REPLACE EMPRESA WITH "ABC " && Actualiza los campos en el registro añadido
&& con APPEND BLANK
Visual dBASE también permite el uso de del comando INSERT FROM de SQL para
añadir registros en una tabla. Para más información, consulte el Capítulo 9 de la
Referencia del lenguaje.
Para utilizar una ficha como sistema de entrada de datos, defina la propiedad View de la
ficha con el nombre de la tabla o vista en que desea añadir datos. Asegúrese de que los
campos en que desea añadir datos están en la ficha y de que sus propiedades Datalink
están definidas con los campos correctos. Para comenzar la introducción de datos, llame
al método BeginAppend( ) de la ficha para añadir un registro vacío en la tabla.
Introduzca los datos en los campos de la ficha.
Cuando todos los datos están introducidos en la ficha (lo cual suele indicarse pulsando
un botón Aceptar), llame al método IsRecordChanged( ) para comprobar la
introducción de los datos. Si IsRecordChanged( ) devuelve .T., llame a SaveRecord( )
para guardar los datos en el registro vacío. Si no se han introducido datos nuevos, o si
no deberían guardarse los cambios (es decir, se pulsó el botón Cancelar), llame al
método AbandonRecord( ) para cancelar la operación de adición y borrar el registro
vacío de la tabla. El código siguiente ilustra estas operaciones.
LOCAL F
F = NEW FICHADEPAR()
F.OPEN()
RETURN
CLASS FICHADEPAROF FORM
this.Text = "Nombre departamento"
this.Left = 43
this.Top = 6
this.ColorNormal = "/BTNFACE"
this.View = "DEPARTAM.DBF" && La ficha utiliza la tabla DEPT.DBF
this.Height = 5
this.Width = 35
* Añade un registro para los nuevos datos cuando se abre la ficha
this.OnOpen = {;this.BeginAppend()}
this.OnClose = CLASS::Proc_OnClose && realiza alguna limpieza al cerrar la ficha
this.ButtonPushed = .F.&& Indica si el botón se pulsó para salir
DEFINE TEXT TEXTO1 OF THIS;
PROPERTY;
Text "&Departamento",;
Left 7,;
Top 0.4688,;
ColorNormal "BtnText/BtnFace",;
PageNo 1,;
Border .F.,;
Height 0.7656,;
Width 11.666
DEFINE ENTRYFIELD CAMPOENT1 OF THIS;
PROPERTY;
DataLink "DEPARTAM->DEPARTAMENTO",; && el campo señala al campo DEPARTAMENTO de
DEPARTAM
Left 7,;
ColorHighLight "WindowText/Window",;
Top 1.4102,;
ColorNormal "WindowText/Window",;
PageNo 1,;
Border .T.,;
Height 1.001,;
Width 20.666
* Procedimiento Form.OnClose
PROCEDURE Proc_OnClose
* si el usuario no salió de la ficha pulsando el botón Aceptar o Cancelar
* es decir, el usuario pulsó Escape
IF .NOT. this.ButtonPushed
this.AbandonRecord() && abandona la operación de añadir y borra el registro vacío
ENDIF
RETURN
ENDCLASS
Inserción de registros
Los comandos INSERT e INSERT BLANK funcionan de forma similar a APPEND y
APPEND BLANK, excepto que los dos comandos INSERT insertan el nuevo registro
inmediatamente después del actual.
USE EMPRESA
INSERT BLANK && Inserta un registro después del actual
REPLACE EMPRESA WITH "Herramientas Acme" && Actualiza el registro insertado
INSERT también dispone de una opción BEFORE para insertar un nuevo registro antes
de la posición actual del puntero de registro.
Es posible añadir registros en las tablas de Paradox y SQL; sin embargo, dado que estas
tablas no tienen números de registro, el comportamiento de los comandos APPEND e
INSERT varía en algunas situaciones. Para más información sobre la adición (inserción)
de registros, consulte el Capítulo 23.
Capítulo
Ordenación de registros
A los nuevos usuarios de los programas de base de datos, la ordenación suele parecerles
una forma natural de organizar los datos, porque las bases de datos impresas y estáticas
que son habituales, como diccionarios, guías telefónicas y libros de referencia, están en
orden alfabético. Las tablas, sin embargo, tienen índices lógicos para ordenar y buscar
datos de forma dinámica, por lo que carece de importancia el orden físico de los
registros en una tabla. Por tanto, no es aconsejable el uso habitual del comando SORT.
Puede hacer un uso limitado del comando SORT para crear una nueva tabla para la
distribución de datos, en especial cuando está seguro de que los datos no van a cambiar
mucho durante algún tiempo. Un ejemplo podría ser un catálogo de artículos de
temporada, cuando sabe que no borrará ni añadirá elementos durante unos meses.
Para más información sobre el comando SORT, consulte la Referencia del lenguaje.
Concatenación de tablas
El comando JOIN une tablas para crear nuevas tablas que tienen sus campos dispuestos
en un orden especial. Puede utilizar JOIN para hacer lo siguiente:
• Crear una tabla temporal para un informe mediante SORT y JOIN, que extraiga un
subconjunto de datos organizados de una forma especial en una nueva tabla.
• Incorporar una tabla de referencia normalizada en la tabla principal, especialmente
cuando aquélla contiene datos estáticos.
• Situar campos muy relacionados uno junto a otro en una tabla para facilitar su
consulta y mejorar la velocidad del índice.
Nota El comando JOIN no debería utilizarse de forma rutinaria para crear nuevas tablas, ya
que puede hacerlas muy grandes, posiblemente con campos duplicados.
El Diseñador de consultas también puede utilizarse para crear nuevas tablas mediante
la combinación de campos de diferentes tablas. Para ello, guarde la vista resultante
seleccionando Consulta|Copiar resultado en nueva tabla. Seleccione los campos que
desea combinar con cuidado para evitar la duplicación de datos. Para conocer los
principios del diseño de tablas, consulte el Capítulo 1 de la Guía del usuario.
Por ejemplo, para guardar dos archivos .NDX como etiquetas en el archivo de
producción .MDX de CLIENTES.DBF, puede utilizar la sintaxis siguiente:
USE CLIENTES EXCLUSIVE INDEX PREFIJO.NDX, EMPRESA.NDX && Abre los archivos necesarios
Los siguientes son algunos ejemplos del uso de las funciones de índice:
USE CLIENTES EXCLUSIVE
INDEX ON NUM_CLI TAG NUM_CLI
INDEX ON EMPRESA TAG EMPRESA
? MDX() && Devuelve Clientes.mdx
? TAGCOUNT() && Devuelve 2
? TAGNO() && Devuelve 2
? ORDER() && Devuelve EMPRESA
SET ORDER TO OTRO_IND && Cambia el índice maestro
? ORDER() && Devuelve OTRO_IND
? TAG() && Devuelve OTRO_IND
Técnicas de indexación
Las tablas de dBASE contienen datos que suelen cambiar de forma habitual. En muchas
aplicaciones de base de datos, las tablas se actualizan desde programas que utilizan
comandos de dBASE, como BLANK, REPLACE, REPLACE FROM ARRAY o UPDATE.
Uso de REINDEX
En muchas aplicaciones, hay demasiados datos como para poder actualizarlos de forma
manual. Por contra, es posible que muchos registros se actualizasen varias veces al día
en una aplicación. Por ejemplo, los datos introducidos manualmente en las tablas por
personal de ventas o escáneres de punto de venta se utilizan con comandos como
BLANK, UPDATE, APPEND o REPLACE para actualizar tablas más grandes.
Todos estos comandos tienen REINDEX como palabra clave opcional. Utilícela con ellos
para lograr un mejor rendimiento cuando sustituya varios registros. Esta opción impide
que dBASE actualice los índices hasta que se hayan modificado todos los registros. Sin la
opción REINDEX, si sustituye un campo clave del índice maestro, dBASE podría mover
el puntero de registro si la posición de un registro cambia en el archivo de índice por
una actualización. Si se mueve el puntero, el ámbito de la sustitución global no puede
mantenerse y se producirán resultados imprevisibles.
Puede utilizar dos o más alias cuando haya varias tablas en la cadena de relación.
Si define SKIP para que incluya las áreas de trabajo en que están abiertas las tablas
secundarias, se procesan todos los registros de las tablas secundarias que tengan un
registro correspondiente en la tabla principal.
Cuando hay una lista de tablas secundarias, dBASE inicia el proceso desde la última
tabla de la lista.
No es necesario que incluya todas las tablas secundarias en un comando SET SKIP TO.
Incluya sólo las que tengan una relación uno con muchos con la tabla principal.
Por ejemplo, la tabla Elemento podría contener varios registros para cada cliente que
haya hecho más de una compra. Puede utilizar los comandos SET SKIP y SET FILTER
para procesar los artículos o elementos de cada pedido introducido para cada cliente.
Por ejemplo:
CLOSE DATABASES
SET EXACT ON
SELECT 1
USE PEDIDOS.DBF
SELECT 2
USE CLIENTE.DBF ORDER TAG Num_Cli
SELECT 3
USE ELEMENTO.DBF ORDER TAG Num_ped
SELECT 1
SET RELATION TO Num_Cli INTO CLIENTE, Num_Ped INTO ELEMENTO
SET SKIP TO CLIENTE
SET FILTER TO FOUND(2) .AND. FOUND(3) && Establece condiciones de filtro en tablas
&& secundarias
SELECT 3
SET FILTER TO Num_Ped = PEDIDOS->Num_Ped && Establece condición de filtro en la tabla
&& secundaria
SELECT 1
GO TOP
Capítulo
Búsqueda de registros
dBASE proporciona comandos y funciones para realizar búsquedas indexadas y
devolver valores. También pueden efectuarse búsquedas sin índices mediante el
comando LOCATE o la función LOOKUP(). En el caso de la función LOOKUP(), las
búsquedas indexadas son la única forma de obtener su funcionalidad mejorada.
El hecho de que EOF() es verdadero cuando SET NEAR está desactivado es útil para
determinar los resultados de las búsquedas. Sin embargo, podría haber búsquedas en
que EOF() puede ser verdadero con SET NEAR ON. Por ejemplo, si el último registro
del archivo es una “B” y se busca “C” el puntero de registro se sitúa en el registro que
sigue a la coincidencia más próxima y también en EOF().
1. MIN() y MAX() con CALCULATE devuelven el valor menor o mayor que hay en el campo
mencionado. Por sí solas, estas funciones devuelven el menor o mayor de dos valores.
Selección de campos
Utilice SET FIELDS TO <lista campos> para limitar los campos a los que son relevantes
para los datos que desea ver o para añadir campos de otras áreas de trabajo.
Mediante SET FIELDS ON y SET FIELDS OFF, puede conmutar entre la lista
personalizada de campos que cree y el valor por defecto de dBASE (todos los campos).
Cuando diseña una consulta en el Diseñador de consultas, éste también genera un
comando SET FIELDS TO con los campos incluidos en la consulta.
SET FIELDS TO sin opciones elimina la restricción de la lista de campos y vuelve a
mostrar todos los campos.
Capítulo
Bloqueo de datos
Cuando más de un usuario o programa acceden a la misma tabla, pueden surgir
conflictos si intentan actualizar la misma información. dBASE gestiona estos conflictos
potenciales permitiendo que sólo un usuario o programa en cada momento realicen
operaciones que actualicen datos. Mientras un usuario actualiza un dato, esta tabla o
registro en uso está bloqueado y, aunque otros usuarios o programas pueden ver los
datos, no pueden actualizar ni bloquear la misma tabla o registro hasta que termine el
primer usuario.
dBASE proporciona dos tipos diferentes de operaciones de bloqueo: automático y
explícito. Con el bloqueo automático, dBASE bloquea automáticamente la tabla o registro
que se está actualizando. Con el explícito, puede bloquear toda una tabla o sólo los
registros específicos que desee actualizar.
Bloqueo automático
En dBASE, los registros de una tabla se bloquean de forma automática cuando utiliza
BROWSE o EDIT y pulsa cualquier tecla (o realiza una operación con el ratón) que
modifique un registro, excepto las utilizadas para desplazarse por la tabla o hacer una
selección de menú. (También es posible bloquear un registro eligiendo Tabla|Bloquear
registro seleccionado o pulsando Ctrl+L cuando se encuentre en un registro no
bloqueado.) dBASE intenta bloquear el registro que se está actualizando, y los registros
relacionados de otras tablas.
Visual dBASE utiliza los mismos tipos de bloqueo para las tablas de Paradox que los que
aplica a las de dBASE, es decir, intenta bloquear un registro, realiza la actualización y
libera el bloqueo. Sin embargo, al acceder a tablas de SQL, dBASE guarda primero sus
ediciones para un registro en particular y entonces comprueba si hay algún conflicto con
el registro guardado en el servidor de bases de datos en que se accede a la tabla SQL.
Si no hay ningún conflicto, actualiza el registro en el servidor de la base de datos.
(Para conocer el comportamiento específico de los bloqueos en su entorno, consulte la
documentación de SQL Link de Borland correspondiente a su servidor de base de
datos.)
Si logra el bloqueo de un registro o tabla, puede proceder a editar los datos. Si no,
Visual dBASE devuelve un mensaje indicando que el registro (o tabla) está en uso por
otro usuario. Si ha convertido la tabla empleando el comando CONVERT (consulte
“Obtención de información adicional sobre el bloqueo de registros”), Visual dBASE
también muestra el nombre del usuario que ha aplicado el bloqueo a esta tabla o
registro. En ambos casos, Visual dBASE continúa intentando obtener un bloqueo hasta
que lo logra o hasta que el usuario elige Cancelar.
Si obtiene un bloqueo en un registro, pero los datos han cambiado desde la última vez
que se mostraron, Visual dBASE actualiza los datos y devuelve el mensaje
Registro modificado por otro usuario. Después de elegir Aceptar, puede editar los
datos en el registro actualizado.
Cuando se ejecuta un comando que modifica toda la tabla, Visual dBASE intenta
bloquear la tabla de forma automática. La Tabla 21.1 enumera los comandos que
provocan un bloqueo automático (si no se ha aplicado ya un bloqueo explícito) y
muestra si bloquean toda la tabla o sólo los registros afectados. Si especifica un número
de registro como <ámbito> de DELETE, RECALL o REPLACE, se aplica un bloqueo
automático al registro, no a la tabla.
Tabla 21.1 Comandos que provocan un bloqueo automático
Comando Tipo de bloqueo
APPEND Registro
APPEND FROM Tabla
AVERAGE Tabla
BLANK Registro
BLANK <ámbito> Tabla
BROWSE1 Registro
CALCULATE Tabla
CHANGE1 Registro
COPY Tabla
COPY STRUCTURE Tabla
COUNT Tabla
DELETE Registro
DELETE <ámbito> Tabla
EDIT1 Registro
INDEX Tabla
JOIN Tabla
LABEL FORM Tabla
RECALL Registro
RECALL <ámbito> Tabla
REPLACE Registro
REPLACE <ámbito> Tabla
REPORT FORM Tabla
SORT Tabla
SUM Tabla
TOTAL Tabla
UPDATE Tabla
Después de realizar la actualización y pasar a otro registro, Visual dBASE libera la tabla
o registro de forma automática para que otros usuarios o programas puedan
actualizarlos. También puede liberar manualmente el bloqueo eligiendo
Tabla |Desbloquear registro seleccionado o pulsando Ctrl+L cuando se encuentre en un
registro bloqueado.
También puede utilizar el comando UNLOCK para liberar los bloqueos de registros y
tablas en todas las áreas de trabajo o sólo en las especificadas. (Consulte “Bloqueo
explícito de tablas y registros” más adelante en este capítulo.)
PEDIDOS.DBF ELEMENTO.DBF
Por ejemplo, si edita los campos de un registro del pedido que tiene el número 00041,
Visual dBASE bloquea ese registro en la tabla Pedidos y el registro actual en la tabla
Elemento. Entonces, cuando termine sus modificaciones y salga del registro,
Visual dBASE libera los bloqueos de ambas tablas.
El valor por defecto es que el bloqueo esté activado; para desactivar el bloqueo
automático para estos comandos, utilice SET LOCK OFF antes de ejecutar el comando.
Advertencia Si se desactiva el bloqueo automático, la integridad de los datos no está garantizada.
SET LOCK OFF afecta a algunos de estos comandos sólo al leer los datos de una tabla,
no al escribirlos. Al escribir en una tabla, COPY, COPY STRUCTURE, INDEX, JOIN,
SORT y TOTAL abren la tabla de destino automáticamente en modo exclusivo.
Nota El comando CONVERT crea una copia de seguridad de la tabla original con la extensión
.CVT antes de añadir el nuevo campo _dbaselock. El tiempo y espacio necesarios para
crear la tabla convertida variará dependiendo del tamaño de la tabla.
Utilice LKSYS() para determinar la fecha y hora en que el registro se modificó por última
vez y, suponiendo que el ancho del campo sea mayor de 8 caracteres, el identificador del
último usuario que bloqueó el registro. CHANGE() devuelve .T. si se ha actualizado el
registro de la tabla desde la última vez que mostró los datos, y .F. si los datos no han
cambiado.
Cuando un registro ha cambiado, utilice REFRESH para actualizar los datos guardados
en la tabla. También puede utilizar SET REFRESH para especificar un intervalo de
tiempo para la actualización automática de la pantalla con los datos contenidos
actualmente en una tabla, por ejemplo:
USE CLIENTE && Abre la tabla CLIENTE.DBF
SET REFRESH TO 1000 && Especifica un intervalo de tiempo para la actualización
&& automática de la pantalla
IF CHANGE() && Comprueba que el registro actual ha sido actualizado
REFRESH && Si es así, actualiza
ELSE
REPLACE... && Si los datos no han cambiado, actualiza el valor del
&& registro
ENDIF
FLOCK() y RLOCK()
Utilice las funciones FLOCK() y RLOCK() para determinar si una tabla o registro está
bloqueado por otro usuario o programa y, si no lo está, para bloquearlo. Utilice
FLOCK() para bloquear toda una tabla y RLOCK() o LOCK() para bloquear el registro
actual y todos los registros (de tablas relacionadas) que dependan del registro actual.
Si la tabla o registro que desea bloquear no está bloqueado ya por otro usuario, FLOCK()
y RLOCK() bloquean la tabla o registro y devuelven .T. De lo contrario, si la tabla o
registro ya está bloqueado, o la operación de bloqueo falla por otra razón, devuelven .F.
Junto con estas dos funciones, SET REPROCESS le permite especificar el número de
veces que desea intentar aplicar un bloqueo si no lo logra la primera vez.
Utilice SET REPROCESS para definir tres tipos distintos de valores:
• Si está definido con un valor de –1, Visual dBASE continúa reintentando el bloqueo o
el intento de abrir una tabla (con el comando USE) hasta que otro usuario que tiene
actualmente un bloqueo sobre una tabla o registro libera el bloqueo. No se muestran
mensajes ni los usuarios pueden detener el proceso de reintento, por lo que podría
producirse una condición de punto muerto.
• Si está definido con un valor de 0, Visual dBASE intenta indefinidamente obtener un
bloqueo, pero aparece un cuadro de diálogo para que el usuario pueda pulsar Esc
para detener el intento de obtener el bloqueo.
• Si está definido con un entero positivo, Visual dBASE intenta lograr el bloqueo el
número especificado de veces antes de detenerse.
El ejemplo siguiente muestra cómo puede utilizar el bloqueo explícito junto con
SET REPROCESS en una aplicación:
SET REPROCESS TO 100 && Asigna 100 al contador de reintentos
IF RLOCK()
<realizar la actualización>
ƒ
ENDIF
En este ejemplo, Visual dBASE realiza 100 intentos para lograr un bloqueo antes de salir
del bloque IF...ENDIF. SET REPROCESS también puede utilizarse con rutinas
ON ERROR en un programa de aplicación. Si define una rutina ON ERROR, ésta no se
inicia hasta que termina el bucle de SET REPROCESS. Tenga en cuenta también que si
especifica un valor de –1 con SET REPROCESS, la rutina ON ERROR nunca se ejecuta.
Creación de sesiones
Los parámetros y operaciones de una sesión se registran en función de las selecciones
vigentes cuando se crea o utiliza. La opción Sesiones del cuadro de diálogo
Propiedades |Escritorio le permite elegir si se utilizan sesiones al abrir tablas o
consultas mediante el Selector o el menú Archivo|Abrir. Los informes y etiquetas
siempre operan en su propia sesión.
Dentro de un programa, puede incluir el comando CREATE SESSION (normalmente al
principio del programa) para iniciar una nueva sesión. (Para más información sobre
CREATE SESSION y para una lista de los comandos, funciones y parámetros del
entorno controlados por las sesiones, consulte la Referencia del lenguaje.) Cuando cree
una sesión, todos los SET tienen sus valores iniciales (tomados de DBASEWIN.INI).
Aunque las tablas de otras sesiones activas permanecen abiertas, no hay tablas abiertas
en la nueva sesión y el área de trabajo actual es la 1.
CREATE SESSION && Comienza una nueva sesión
USE CLIENTE && Abre una tabla
BROWSE && Abre una ventana BROWSE
CREATE SESSION && Crea una segunda sesión
USE CLIENTE && Abre la tabla CLIENTE.DBF de nuevo
SKIP 1 && El desplazamiento en la segunda sesión no afecta
&& al puntero de registro de la primera
Si utiliza el Diseñador de fichas, necesita añadir el comando CREATE SESSION en el
código generado de una ficha si desea que funcione en su propia sesión.
Nota La ventana de comandos mantiene su propia sesión, por lo que las operaciones
realizadas en ella son independientes de la nuevas sesiones que cree, por ejemplo,
cuando abre un objeto como una consulta o una tabla usando el Selector.
Selección de sesiones
No hay ningún comando específico del lenguaje para seleccionar una sesión. Una sesión
se selecciona cuando se crea o cuando una ventana asociada a una sesión se convierte en
la ventana activa. Una sesión asociada a una ficha se selecciona siempre que se ejecuta
un método o controlador de sucesos para la ficha. Al seleccionar otra sesión abierta, se
restauran todos los parámetros del entorno definidos cuando se creó la sesión.
Capítulo
Creación de transacciones
Visual dBASE dispone de un grupo de funciones, BEGINTRANS(), COMMIT() y
ROLLBACK(), que proporcionan el proceso de transacciones para la actualización de
tablas de dBASE, Paradox y SQL. Dependiendo de si una transacción se completa
satisfactoriamente, es posible o aceptar los cambios, o recuperar o restaurar las tablas a
su estado original.
BEGINTRANS() inicia una transacción. La función devuelve .T. si logra iniciarla. Todos
los bloqueos de registros y tablas se mantienen hasta terminar la transacción.
COMMIT() termina una transacción, haciendo que los cambios realizados en las tablas e
índices sean permanentes después de ejecutar COMMIT(). Esta función también libera
todos los bloqueos de registro y tabla y devuelve .T. si la transacción se acepta.
ROLLBACK() también termina una transacción, pero restaura todos los cambios
realizados en las tablas e índices abiertos antes de liberar todos los bloqueos de registro
y tabla. La función devuelve .T. si la transacción se logra recuperar.
ON ERROR ROLLBACK() && Deshace los cambios si se produce un error
USE EMPLEADO
IF BEGINTRANS() && Intenta comenzar la transacción.
REPLACE ALL Salario WITH Salario * 1.1 && Un cambio reversible con ROLLBACK()
IF .NOT. COMMIT() && Intenta escribir los cambios en el disco
* No se puede escribir. Incluya opciones para que
* el usuario pueda reintentar o cancelar
ƒ
ENDIF
ENDIF
Tabla 22.2 Comandos y funciones no permitidos en las transacciones de Visual dBASE (continuación)
Comandos y funciones
CLOSE INDEX PACK
CLOSE TABLES ZAP
CONVERT
PROCEDURE VER_EDITAR
IF form.ModoEdicion
form.Aceptar()
form.ModoEdicion = .F.
form.text = "Cliente -- Modo Ver"
this.text = "&Editar"
this.statusmessage = "En modo Ver. Pulse el botón Editar para editar los datos"
ELSE
BEGINTRANS()
form.ModoEdicion = .T.
this.text = "&Ver"
this.statusmessage = "En modo Edición. Pulse el botón Ver para volver al modo Ver"
ENDIF
Este procedimiento proporciona código que cambia la ficha del modo de visualización
al de edición de datos, y viceversa. En la rama ELSE, en que la ficha se cambia para
permitir que el usuario edite los datos, Visual dBASE inicia una transacción con la
función BEGINTRANS().
La rama IF contiene código para cambiar la ficha de permitir ediciones a sólo visualizar.
En primer lugar, llama la función Aceptar() para averiguar si el usuario ha modificado
los datos.
FUNCTION Aceptar
IF form.ModoEdicion .AND. form.CambiosHechos
IF MessDlg("Confirmación", "¿Efectuar cambios?"...) = 6
COMMIT()
ELSE
ROLLBACK()
ENDIF
ELSE
ROLLBACK()
ENDIF
form.CambiosHechos = .F.
RETURN .T.
Si se han producido modificaciones, la ficha muestra un cuadro de diálogo que le
pregunta si desea aceptar, recuperar o cancelar los cambios realizados en los datos.
El cuadro de diálogo también aparece si sale de Visual dBASE mientras la transacción
está activa.
Visual dBASE incluye otras dos formas de evaluar los cambios asociados a una
transacción. Por ejemplo, puede utilizar la propiedad OnChange con elementos de
datos, como campos de entrada, cuadros de lista y cuadros combinados, y determinar si
se han realizado modificaciones en un campo.
DEFINE ENTRYFIELD ENTRNUMCLI OF THIS;
PROPERTY;
ƒ
DataLink "Num_cli", ;
OnChange CLASS::CAMBIOSHECHOS, ;
ƒ
Puede definir un método OnNavigate para determinar si un usuario ha salido de un
registro en particular y ha realizado modificaciones en el registro. Como se ha
mencionado antes, probablemente también deseará comprobar, al cerrar la ficha, si se
han efectuado cambios en una tabla.
CLASS CLIENTES OF FORM;
this.OnOpen=CLASS::FICHA_ABIERTA
this.OnClose=CLASS::FICHA_CERRADA
this.OnNavigate CLASS::CAMBIOSHECHOS
ƒ
También puede proporcionar proceso de transacciones en una ficha cuando utiliza los
comandos APPEND o REPLACE, en lugar de emplear objetos (como campos de
entrada) o métodos (como OnChange u OnNavigate), para añadir o actualizar un solo
registro o realizar operaciones por lotes que actualizan varios registros de una tabla.
1
Se trata comoread committed
2 Sólo lectura
Notas La versión anterior de dBASE tomaba el nivel de aislamiento 1 como nivel por defecto,
mientras que Visual dBASE toma el nivel 0.
Si el servidor los permite, los comandos SET TRANSACTION, COMMIT y ROLLBACK
de SQL interactiva pueden utilizarse en lugar de las funciones de dBASE.
Capítulo
Inserción de registros
Al añadir registros en las tablas de dBASE, puede hacerlo al final de la tabla (con
APPEND) o insertarlos en la posición del registro actual (con INSERT). Con tablas de
Paradox y SQL, sólo es posible añadir registros. En las de Paradox, INSERT con un
índice activo se comporta igual que APPEND con una tabla de dBASE. El registro se
“inserta” en el índice, pero se añade al final de la tabla.
En las tablas SQL, los índices no afectan a la forma en que se añaden los registros en las
tablas. Cuando inserta registros en una tabla SQL, el servidor de bases de datos al que
accede determina dónde y cómo se guardan los nuevos registros.
Borrado de registros
El borrado de registros individuales en una tabla de dBASE es un proceso de dos pasos.
En primer lugar, marca el registro para borrado con DELETE y lo elimina de la tabla con
PACK. (Debe abrir la tabla para uso exclusivo antes de ejecutar el comando.)
El comando RECALL desmarca los registros borrados, invirtiendo el efecto de DELETE.
Ni las tablas SQL ni las de Paradox mantienen una marca “borrado”, como tienen las de
dBASE. En consecuencia, el borrado se produce en un solo paso en esas tablas.
Cuando borra un registro con DELETE, se elimina permanentemente de la tabla, sin ser
posible recuperarlo.
En las tablas de Paradox y SQL:
• DELETE borra permanentemente un registro de una tabla y mueve el puntero al
siguiente registro. (En las tablas SQL, el puntero de registro pasa al siguiente registro
recuperado del servidor de bases de datos.)
• DELETED() siempre devuelve .F.
• RECALL y PACK devuelven errores.
• SET DELETED no tiene ningún efecto.
Mediante el comando ZAP, puede borrar todos los registros de las tablas de dBASE,
Paradox y SQL.
Validación de datos
En las tablas de Paradox y SQL, puede especificar controles de validación para cada
campo, que son normas que rigen los valores que puede introducir el usuario en el
campo. Por ejemplo, un control de validación puede especificar un valor mínimo,
máximo o por defecto para un campo.
Los controles de validación de Paradox y SQL son similares a las cláusulas de validación
que se especifican para los objetos de introducción del usuario (como los campos de
entrada) mediante la propiedad Valid, excepto que se asocian directamente a los
campos de una tabla.
Visual dBASE aplica los controles de validación existentes a las tablas de Paradox y SQL.
Cuando se editan datos en un campo de una tabla de Paradox o SQL que tiene un
control de validación, Visual dBASE evalúa la condición de validación y devuelve un
error si no se cumple. Sin embargo, no es posible crear ni modificar un control de
validación. Para ello, emplee Paradox o la utilidad adecuada disponible en el servidor
de bases de datos que contiene la tabla. Busque en la documentación de Paradox o del
servidor de bases de datos información sobre los tipos específicos de control de
validación que se proporcionan y cómo crearlos.
Los controles de validación de Paradox se almacenan en un archivo que tiene el mismo
nombre que la tabla y la extensión .VAL. Visual dBASE abre el archivo .VAL de forma
automática, si existe, al abrir una tabla de Paradox.
El ejemplo siguiente demuestra cómo podría definir una transacción para datos
guardados en un servidor de bases de datos:
ON ERROR DO ProcError && Indica una rutina de proceso de errores
OPEN DATABASE Conta && Abre una base de datos
USE :Conta:MITABLA && Abre una tabla de la base de datos
IF BEGINTRANS("Conta", 0) && Comienza una transacción de servidor
REPLACE ALL SALARIO WITH SALARIO * Inflacion && Intenta actualizar todos los registros
IF .NOT. COMMIT("Conta") && Acepta los cambios si no ocurre
&& ningún error
* Error al escribir
ƒ && Incorpora opciones para el caso en
&& que la transacción falle
ENDIF
ENDIF
ƒ
PROCEDURE ProcError && Define un procedimiento para
&& controlar los errores
IF .NOT. ROLLBACK("Conta") && Intenta deshacer los cambios
* Fallo al intentar deshacer los cambios
IF DBERROR() <> 0 && Comprueba si el error es del servidor
* Procesar error BDE
ƒ
IF SQLERROR() <> 0 && Comprueba si el error es del servidor SQL
* Procesar error SQL
ENDIF
ENDIF
ENDIF
RETURN
Los programas de dBASE suelen utilizar APPEND BLANK y REPLACE para añadir un
registro vacío en una tabla y rellenar los campos. Para evitar la creación de claves vacías
duplicadas en las tablas de Paradox o SQL, utilice APPEND AUTOMEM, que añade un
nuevo registro y simultáneamente rellena los campos con valores tomados de variables
automem creadas con anterioridad. Para más información sobre el uso de estos
comandos, consulte la Referencia del lenguaje.
Diferencias en seguridad
Visual dBASE permite el cifrado de tablas de dBASE mediante el sistema de seguridad
Protect. Protect también proporciona la seguridad por contraseña a niveles de
aplicación, de tabla y de campo. Con la excepción de la seguridad por contraseña de
aplicación, el sistema Protect se aplica sólo a las tablas de dBASE. Para más información
sobre el sistema de seguridad Protect de Visual dBASE, consulte la Guía del usuario.
Las tablas de Paradox incorporan un soporte de seguridad por contraseña.
Visual dBASE admite esta capacidad y requiere que se proporcione la contraseña
principal de una tabla de Paradox para poder tener acceso a los datos.
Las tablas SQL utilizan el sistema de seguridad del servidor de bases de datos.
Los nombres y las contraseñas de conexión necesarios deben proporcionarse al trabajar
con datos de un servidor SQL.
Tabla 23.1 Resumen de cómo gestiona Visual dBASE las tablas de Paradox y SQL (continuación)
En tablas de
Paradox y SQL Esto afecta a Por tanto, Visual dBASE
Archivos Todos los índices USE Abre automáticamente todos los índices
de índice asociados se abren al asociados (para Paradox, sea cual sea la
abrir la tabla y etiqueta “mantenida” de Paradox) y los
permanecen mantiene abiertos hasta que se cierra la tabla.
abiertos hasta que
se cierra la tabla.
Haga referencia a los SET ORDER TO Especifica el índice maestro de la misma forma
nombres del índice, USE...ORDER TAG que SET INDEX TO hace para una tabla de
no a los archivos de <nombre etiqueta> dBASE. Es necesario usar el nombre de índice
índice. como etiqueta; es decir, no es posible utilizar
SET ORDER TO <número índice>.
Opción PRIMARY de Proporciona la opción PRIMARY para hacer
INDEX referencia a los índices principales de las tablas
de Paradox. Haga referencia a los índices
secundarios por su nombre de índice.
SET INDEX TO Devuelve un error en cada caso. La referencia
Opciones INDEX y OF de USE a todos los índices de tablas de Paradox y SQL
se hace como etiquetas.
SET ORDER TO <número índice>
COPY TAG
COPY INDEXES
Opción OF de DELETE TAG
Claves de Las claves pueden INDEX Devuelve un error cuando una clave es una
índice ser un solo campo o Creación de etiquetas con expresión. Para índices compuestos, utilice
una lista de campos una coma para separar los nombres de los
(denominada clave CREATE campos.
compuesta). No se MODIFY STRUCTURE
permiten SEEK, SET KEY TO Acepta las listas de clave compuesta.
expresiones. FIND, SEEK(), LOOKUP(), No permite las listas de clave compuesta.
KEYMATCH() Utilice SEEK y SET KEY TO para buscar por
índices de clave compuesta.
No se permiten las Opciones FOR y DESCENDING Devuelve un error para las tablas que no
claves condicionales de INDEX permiten las claves condicionales o
y descendentes en descendentes.
las tablas de FOR(), DESCENDING() Devuelve una cadena vacía para FOR();
Paradox. (Los DESCENDING() devuelve .F. para las tablas
índices que no permiten los índices descendentes.
descendentes sí
suelen permitirse en
las tablas SQL.)
Los índices Opción UNIQUE de INDEX Devuelve un error para tablas de Paradox.
principales Para las tablas SQL, creará un índice exclusivo;
imponen los valores de clave exclusivos se imponen
automáticamente automáticamente.
los valores de clave UNIQUE() Devuelve siempre .T. para los índices
exclusivos. Los principales y .F. para los secundarios.
secundarios no
pueden imponer los SET UNIQUE No tiene ningún efecto.
valores de clave APPEND, EDIT, BROWSE Muestra una advertencia (APPEND, EDIT,
exclusivos. (Para las BROWSE) o un error (APPEND BLANK,
tablas SQL, los APPEND BLANK, REPLACE
REPLACE) y no añade registros si provocan
índices exclusivos un valor de clave duplicado. Esto incluye
imponen valores de registros vacíos; las tablas no pueden tener
clave exclusivos.) más de un registro vacío si hay un índice
principal o exclusivo.
Capítulo
24
Uso de SQL
Capítulo 24
Visual dBASE permite el uso de comandos de dBASE o SQL con tablas de servidores de
dBASE, Paradox o SQL. La sintaxis de SQL utilizada dentro de un programa dBASE se
denomina SQL incrustado. Cuando se utiliza SQL con tablas de dBASE o Paradox, se
denomina SQL local. Cuando se emplea con tablas de servidor, se denomina SQL
interactiva (los comandos de SQL se pasan de dBASE al servidor de base de datos, donde
realmente se ejecutan). Visual dBASE también permite la declaración y llamada de
procedimientos almacenados en servidores de base de datos.
Para obtener información sobre cómo trabajar con tablas de SQL, consulte el Capítulo
Capítulo 23. Para obtener una descripción detallada de la función SQLEXEC( ) y las
sentencias de SQL que puede utilizar en SQL local, consulte la Referencia del lenguaje.
Nota Para que pueda acceder a un servidor remoto de SQL es preciso que adquiera e instale
SQL Link de Borland y configure un alias de servidor remoto mediante el Database
Engine de Borland. Para más información, consulte la Guía del usuario de SQL Link.
Definición de SQL
SQL es un descendiente de SEQUEL (Structured English QUEry Language), que IBM
diseñó hace más de veinte años. SQL se creó como lenguaje para construir sistemas de
gestión de bases de datos relacionales (RDBMS) en cualquier plataforma de hardware. El
primer RDBMS comercial que utilizó SQL apareció en 1981, y SQL es ahora el lenguaje
estándar para consultas de red entre diferentes plataformas de hardware y software.
SQL es en realidad un sublenguaje diseñado para incrustarse en un lenguaje de
programación de aplicaciones. Es tan flexible que pueden emplearse como lenguaje de
definición de datos (DDL) y como lenguaje de manipulación de datos (DML).
Con frecuencia, una sola sentencia SQL (comando) puede sustituir a varios comandos de
definición, manipulación de datos e indexación de Visual dBASE.
Nota Hay muchas fuentes externas para obtener información adicional sobre SQL y RDBMS.
Un ejemplo es An Introduction to Database Systems de C.J. Date (Addison-Wesley,
Reading, Massachusetts, 1983).
Terminología SQL
La tabla siguiente muestra los términos usados en dBASE y en SQL para describir
aspectos de las bases de datos relacionales.
Tabla 24.1 Terminología básica de SQL
SQL Visual dBASE Definición
Base de datos Base de datos Conjunto de información relacionada que se ha organizado para
un fin específico.
En dBASE, una base de datos reúne un conjunto de una o más
tablas que contienen y clasifican información, además de
archivos relacionados como índices y archivos memo.
En SQL, una base de datos agrupa un solo archivo grande que
alberga todos los datos de la base, y un catálogo del sistema que
contiene información descriptiva de la base de datos (a veces se
denomina diccionario de datos).
Tabla Tabla Estructura de filas (registros) y columnas (campos) que contiene
información.
Una base de datos SQL muestra datos en formato de tabla, igual
que un archivo de base de datos dBASE. Aunque no contiene
archivos de tabla individuales, designa ciertos datos como tablas,
y le permite darles un nombre, como si fueran tablas físicamente
aparte al estilo de dBASE.
Fila Registro Grupo de columnas (campos) de una tabla que contienen
(dirección horizontal) información relacionada acerca de un solo registro.
En dBASE (y otras bases de datos para PC), los registros están
numerados y tienen un orden explícito.
En las bases de datos SQL, no se numeran ni ordenan las filas.
Sin embargo, pueden agruparse, ordenarse y mostrarse como si
estuvieran numeradas (consulte “Uso de la sentencia SELECT de
SQL” en la página 355).
Columna Campo Categoría de información (columna) de una tabla que se incluye
(dirección vertical) para todos los registros de la tabla.
Vista Vista Una vista es un subconjunto de las filas y columnas de una o más
tablas. En ocasiones, se denomina tabla virtual porque en
realidad no contiene datos, sino que proporciona una ventana a
través de la cual pueden verse los datos de las tablas subyacentes
o de base en que se ha definido la vista. Una vista actualizable es
similar a una vista normal, excepto en que puede utilizarla para
actualizar e insertar datos en las tablas de base de la vista.
Transacciones en SQL
Los servidores de bases de datos SQL gestionan las peticiones en unidades de trabajo
lógicas a las que se denomina transacciones. Una transacción es un grupo de operaciones
relacionadas que deben realizarse todas satisfactoriamente antes de que el RDBMS
finalice los cambios en la base de datos. El proceso de transacciones en los servidores de
bases de datos garantiza que las peticiones de proceso sean adecuadas al estado actual
de los datos.
En SQL, es posible terminar todas las transacciones explícitamente mediante una
sentencia que acepte o descarte los cambios. Una vez confirmado que no se han
producido errores durante la transacción, es posible terminarla con una sentencia
COMMIT. Entonces, la base de datos cambia para reflejar las operaciones que se acaban
de realizar. Si se produce un error, pueden abandonarse los cambios con una sentencia
ROLLBACK.
1. TOM L: This table reference needs to be soft coded. And there are a lot of hard-coded table references in
this section.
2. TOM L: Please make this a cross reference
Variables de memoria
Las variables de memoria de dBASE pueden utilizarse dentro de los comandos de SQL.
Incluya un signo de dos puntos (“:”) antes de los nombres de las variables de memoria,
como en el ejemplo siguiente:
x = "Roberto"
SELECT * FROM clientes WHERE nombre = :x
Requisitos previos
Para cualquier operación de ESQL que accede a datos a través de un servidor de SQL,
asegúrese de:
• Abrir explícitamente la base de datos de destino. La conexión de base de datos SQL
Link supone que el destino de cualquier transacción SQL es la base de datos de SQL
especificada en el alias BDE. Si el objeto de la transacción ESQL es una base de datos
local de dBASE o Paradox, utilice OPEN DATABASE para abrirla explícitamente.
Nota • Si los comandos tendrán acceso a tablas de una sola base de datos abierta, puede
indicarla con SET DATABASE. Sin embargo, si los comandos harán referencia a
tablas de más de una base de datos, no utilice SET DATABASE; por el contrario,
cualifique los nombres de todas las tablas incluyendo el nombre de su base de datos
mediante el formato :NOMBREBASEDATOS:NOMBRETABLA (o :NOMBREALIAS:NOMBRETABLA). Si no
lo hace así, dBASE supone que todas las tablas mencionadas son del tipo especificado
en el alias de conexión de base de datos de SQL Link.
Sintaxis de SELECT
La sintaxis del comando SELECT, que se muestra a continuación, incluye diversas
cláusulas. Con la excepción de SELECT y FROM, la mayoría de las cláusulas son
opcionales. Cuando utilice más de una en un comando SELECT, combínelas en el orden
mostrado en la sintaxis.
SELECT <cláusula>
[INTO <cláusula>]
FROM <cláusula>
[WHERE <cláusula>]
[GROUP BY <cláusula>]
[HAVING <cláusula>]
[UNION subconsulta]...
[ORDER BY <cláusula>/FOR UPDATE OF <cláusula>]
[SAVE TO <cláusula>];
Consultas simples
La forma más simple del comando SELECT incluye sólo las cláusulas SELECT y FROM.
Por ejemplo:
SELECT Compania, Nombre, Apellido
FROM Client;
La cláusula SELECT especifica los nombres de las columnas que deben aparecer en el
resultado, y su orden. La cláusula FROM identifica la tabla que contiene las columnas.
NUM_PIEZA DESCRIPC
001001 ESTACION T., OFICINA ELECTRON.
001002 CONJUNTO MOBILIARIO OFICINA
001005 CONJUNTO MOBILIARIO EJECUTIVO
001007 SOPORTE MADERA SIMPLE
ƒ ƒ
001033 SILLA REPOSABRAZOS
001038 LAMPARA MOVIL
Cláusula WHERE
Para consultar filas específicas, incluya una condición de búsqueda en una cláusula
WHERE.
Para mostrar todos los artículos del inventario de Barcelona, introduzca:
SELECT Num_Pieza, Descripc, Localidad, Disponible
FROM Inventar
WHERE Localidad = "BARCELONA";
La condición de búsqueda de WHERE (Localidad = "BARCELONA") compara el valor
de Localidad en cada fila con el valor "BARCELONA". Si la condición de búsqueda es
verdadera para una fila, ésta se incluye en la tabla resultante.
No es necesario que la tabla resultante incluya la columna utilizada al especificar la
condición WHERE. Por ejemplo:
SELECT Num_Pieza, Descripc, Disponible
FROM Inventar
WHERE Localidad = "BARCELONA";
El resultado incluye las mismas filas, pero omite la columna Localidad.
Los valores que se comparan deben ser de tipos de datos compatibles. Un valor
(o constante) de carácter debe compararse con otro de carácter, un valor numérico con
otro numérico, y así sucesivamente. Los tipos de datos SMALLINT, INTEGER,
DECIMAL, NUMERIC y FLOAT son compatibles entre sí.
Los valores del tipo carácter deben encerrarse entre comillas o entre corchetes ([]).
Además, se comparan usando su representación ASCII. Así, abc en minúsculas no es
igual que ABC en mayúsculas.
Una columna de tipo lógico puede especificarse en una cláusula WHERE con o sin un
operador de comparación. Por ejemplo, las consultas siguientes son equivalentes:
SELECT * FROM Pedidos WHERE ENVIADO = .T.;
SELECT * FROM Pedidos WHERE Enviado;
Las funciones de dBASE pueden utilizarse para convertir los valores de las condiciones
de búsqueda para su comparación. Por ejemplo, utilice la función UPPER( ) para
convertir los valores de una columna de tipo carácter y la función CTOD( ) para
convertir una cadena de fecha para su comparación con valores de columnas de fecha.
Combinación de condiciones
Es posible combinar condiciones de búsqueda en una cláusula WHERE mediante los
operadores lógicos de SQL. Introduzca:
SELECT Num_Pieza, Descripc, Disponible, Localidad
FROM Inventar
WHERE Localidad = "SEVILLA" AND Disponible < 20;
Cuando se especifica más de una condición WHERE, cada una se evalúa como
verdadero o falso para cada fila. Entonces, el operador lógico combina las filas paras las
que las condiciones de búsqueda se evalúen como verdaderas, y produce un resultado.
La prioridad de los operadores lógicos determina el orden en que se evalúan las
condiciones WHERE. Si utiliza el mismo operador lógico para combinar condiciones,
éstas se evalúan de izquierda a derecha.
Es posible utilizar paréntesis para determinar el orden en que se evalúan las condiciones
de búsqueda. Por ejemplo, suponga que cambia el comando anterior para mostrar los
artículos inventariados en Sevilla o Madrid, excluyendo los que cuestan menos de
$1,000 y con reservas escasas. Para ello, introduzca:
SELECT Num_Pieza, Descripc, Localidad, Disponible, Coste_unit
FROM Inventar
WHERE Localidad = "SEVILLA" OR Localidad = "MADRID"
AND Disponible < 20 AND Coste_unit < 1000;
Es posible utilizar todos estos operadores con valores numéricos. Sin embargo, sólo los
de suma y resta pueden utilizarse con cadenas de caracteres, para la concatenación.
Para columnas de tipo carácter, MIN( ) y MAX( ) devuelven los valores ASCII más bajos
(A a Z) y más altos (a a z), respectivamente. Los valores se comparan de izquierda a
derecha.
Nota Las funciones agregadas pueden emplearse sólo en expresiones que direccionen valores
de las columnas. No es posible realizar una operación agregada sobre un valor
constante, una variable de memoria o los valores de una columna de datos lógicos.
COUNT1
12
El símbolo de asterisco (*) especifica que COUNT( ) opere sobre los valores de todas las
columnas de la tabla.
Los encabezados de la tabla resultante de las funciones agregadas utilizan el nombre de
la función más un número que indica su posición de izquierda a derecha en la cláusula
SELECT. Por ejemplo, para utilizar la función SUM( ) para calcular la nómina mensual
total de los vendedores, introduzca:
SELECT SUM(Salario)
FROM Vender;
SUM1
63410
Para averiguar los sueldos más alto, más bajo y medio de los vendedores, introduzca:
SELECT MAX(Salario), MIN(Salario), AVG(Salario)
FROM Vender;
Es posible utilizar una función agregada con la palabra clave DISTINCT para operar
sólo sobre valores de columna exclusivos. Por tanto, para contar el número de ciudades
en que hay clientes, introduzca:
SELECT COUNT(DISTINCT Ciudad)
FROM Client;
COUNT1
15
COUNT1
5
El comando SELECT recupera las filas cuya columna Provincia contenga "M". Entonces,
la función COUNT( ) cuenta el número de filas recuperadas.
Para mostrar artículos de inventario por orden ascendente de la primera letra de sus
descripciones, introduzca:
SELECT Num_Pieza, Descripc, Localidad, Disponible
FROM Inventar
ORDER BY Descripc ASC;
Consejo Para acelerar la recuperación de los datos, cree índices por las columnas que utilice a
menudo para ordenar el resultado.
En una cláusula ORDER BY, puede hacer referencia a una columna por su posición en la
sentencia SELECT. Por ejemplo, para presentar los artículos por orden ascendente
(orden por defecto) de localidad y por orden descendente de número de artículos en
existencias, introduzca:
SELECT Num_Pieza, Descripc, Localidad, Disponible
FROM Inventar
ORDER BY 3, 4 DESC;
Agrupamiento de filas
Las cláusulas GROUP BY y HAVING permiten organizar las filas en grupos sobre los
que realizar operaciones de agregación. Mediante GROUP BY y HAVING, es posible
cambiar el ámbito de una operación agregada de todos los valores de una columna a
sólo los contenidos en el grupo.
Cláusula GROUP BY
La cláusula GROUP BY agrupa un resultado por valores comunes a una o más
columnas. Cada grupo se resume como una sola fila en la tabla de resultado, cuyos
encabezados identifican grupos (G_) o valores añadidos para cada grupo.
Cada columna especificada en la cláusula SELECT debe incluirse también en la cláusula
GROUP BY a menos que se utilice en una operación agregada. Lo contrario también es
cierto. Además, no es posible especificar una columna calculada en una cláusula
GROUP BY.
El ancho total de las columnas especificadas en una cláusula GROUP BY puede tener un
máximo de 100 bytes.
Por ejemplo, para obtener las existencias totales de cada artículo inventariado en todas
las localidades, introduzca:
SELECT Num_Pieza, Descripc, SUM(Disponible)
FROM Inventar
GROUP BY Num_Pieza, Descripc;
G_LOCALIDAD COUNT1
BARCELONA 3
SEVILLA 5
MADRID 4
Utilice una cláusula ORDER BY con una GROUP BY para ordenar un resultado de
forma diferente a lo indicado por el orden por defecto de GROUP BY. Por ejemplo, para
presentar los artículos por cantidad en existencias, en lugar de por número de artículo,
introduzca:
SELECT Num_Pieza, Descripc, SUM(Disponible)
FROM Inventar
GROUP BY Num_Pieza, Descripc
ORDER BY 3;
Cláusula HAVING
La cláusula HAVING sirve para identificar los grupos que aparecen en el resultado de
GROUP BY. HAVING cualifica el resultado de un grupo de la misma forma que
WHERE cualifica un resultado ordinario —especificando una condición que cada grupo
debe satisfacer—. La condición suele incluir la operación agregada que se especifica en
la cláusula SELECT.
Para mostrar los artículos que cuesten más de 50.000 pts. y cuyas existencias sean
superiores a 10 unidades, introduzca:
SELECT Descripc, Num_Pieza, SUM(Disponible), Coste_unit
FROM Inventar
WHERE Coste_unit > 500
GROUP BY Descripc, Num_Pieza, Coste_unit
HAVING SUM (Disponible) > 10;
Cláusula UNION
La cláusula UNION sirve para combinar consultas. UNION combina las tablas de
resultado de dos o más comandos SELECT y elimina las filas duplicadas.
Para mostrar las localidades de ventas que también disponen de existencias, introduzca:
SELECT Localidad
FROM Vender
UNION
SELECT Localidad
FROM Inventar;
LOCALIDAD
BARCELONA
SEVILLA
MADRID
Las reglas siguientes rigen las cláusulas SELECT utilizadas para especificar una unión:
• Cada cláusula SELECT debe tener el mismo número de columnas, y los tipos de
datos de las columnas correspondientes deben coincidir. Sin embargo, no es
necesario que sean iguales los nombres de las columnas correspondientes.
• Los anchos de las columnas de carácter correspondientes deben coincidir.
• Las columnas numéricas correspondientes deben ser del mismo tipo de datos (fijo o
de coma flotante), contener el mismo número de dígitos y, si son decimales, tener el
mismo número de dígitos decimales.
• Las cláusulas SELECT no pueden contener una columna con un tipo de datos
LOGICAL, ni una función o variable de memoria de dBASE.
El resultado de UNION se ordena por los valores de todas las columnas especificadas en
cada cláusula SELECT. Si desea que el resultado se ordene por los valores de una
columna distinta, utilice ORDER BY como última cláusula del comando SELECT.
Utilice un número que indique la posición de izquierda a derecha de la columna
ORDER BY, por ejemplo, ORDER BY 2. Para mostrar los nombres de todas las ciudades
en que haya personal, inventario o clientes, introduzca:
SELECT Ciudad
FROM Client
UNION
SELECT Localidad
FROM Vender
UNION
SELECT Localidad
FROM Inventar;
CIUDAD
Alcorcón
BARCELONA
Badajoz
Barcelona
Cáceres
El Ronquillo
Leganés
MADRID
Madrid
Mairena
SEVILLA
Sevilla
Tomares
Torrejón
Torrente
Ultrera
Valencia
Zaragoza
Hay duplicados aparentes en este resultado (por ejemplo, BARCELONA y Barcelona),
lo cual refleja que hay valores de Ciudad (introducidos con mayúscula inicial y
minúsculas) y de Localidad (introducidos en mayúsculas) no tienen la misma
representación ASCII.
Requisitos previos
Antes de poder ejecutar un procedimiento, debe tener un prototipo declarado mediante
EXTERN.
Al igual que con EXTERN, para disponer de un argumento que el procedimiento pueda
cambiar, debe especificar tipos especiales de argumentos en el prototipo:
• CPTR especifica un argumento que se utilizar para entrada y para salida.
• CPTROUT especifica un argumento que es sólo para salida.
Los procedimientos almacenados están disponibles sólo mientras la base de datos está
abierta. Cualquier comando u operación que la cierre (como CLOSE DATABASE y
CLEAR ALL) también impide la ejecución de procedimientos almacenados.
Sintaxis de declaración
EXTERN SQL [<tipo devuelto>] <nombre procedimiento> ( [<lista argumentos>])
[<nombre basedatos>] [ FROM <nombre pa> ]
<nombre procedimiento> es el nombre del procedimiento almacenado que se ejecuta en
dBASE.
<nombre pa> es el nombre real del procedimiento almacenado. Este parámetro es
necesario si el nombre del procedimiento debe cualificarse con un nombre de usuario,
nombres de paquete o direcciones de servidor remoto, debido a que el nombre del
procedimiento almacenado duplica el nombre de una función interna de dBASE.
<nombre basedatos> es el nombre de la base de datos en que reside el procedimiento
almacenado si es diferente de la configuración actual de SET DATABASE TO.
<lista argumentos> enumera los tipos de datos de los argumentos. Utilice CPTR o
CPTROUT para especificar un argumento cuyo valor modifica el procedimiento
almacenado.
<tipo devuelto> especifica el valor devuelto por las funciones almacenadas. Por ejemplo,
si la función almacenada devuelve un entero, el tipo devuelto sería CINT. (En general,
los procedimientos almacenados no devuelven un valor. Por defecto, el <tipo devuelto>
es CVOID.
Una vez declarado, el procedimiento puede ejecutarse por sí solo o igual que cualquier
otra función de dBASE.
Utilice SQLERROR( ) para determinar si se ejecuta con éxito la función/procedimiento
almacenado.
Sintaxis de ejecución
<nombre procedimiento> ( <lista argumentos> )
Ejemplos
El ejemplo siguiente ejecuta el procedimiento almacenado en servidor CalcMediana( ), que
toma el nombre de un cliente como argumento y almacena un valor numérico como segundo
argumento:
mediana = 0
CalcMediana( "Roberto", mediana )
IF SQLERROR() != 0
? "Error del servidor:", SQLMESSAGE()
ELSE
? "Mediana=",mediana
ENDIF
median = CalcMediana("Roberto")
IF SQLERROR() != 0
? "Error del servidor:", SQLMESSAGE()
ELSE
? "Mediana=",mediana
ENDIF
Limitaciones
• El soporte de los procedimientos almacenados depende por completo de la versión y
configuración del servidor de SQL. Por ejemplo, InterBase 4.0 permite los
procedimientos almacenados, pero InterBase 3.3 no; Oracle7 también los permite,
pero sólo si se activa la opción procedimental. Para más información, consulte al
administrador de bases de datos.
• Si el servidor permite los procedimientos sobrecargados, se declara automáticamente
un único procedimiento. (Oracle7 permite funciones o procedimientos
sobrecargados.)
• Si el servidor no proporciona acceso a las definiciones de procedimientos
almacenados, no permite el uso de AUTOEXTERN. Por ejemplo, Oracle7,
InterBase 4.0 y los controladores ODBC permiten AUTOEXTERN, pero Sybase no.
Parte
V
Entorno Windows
Parte V
Esta parte trata los temas relacionados con la programación para el entorno Windows.
Contiene los capítulos siguientes:
• Capítulo 25, “Impresión”
• Capítulo 26, “Uso de las DLL y del API de Windows”
• Capítulo 27, “Expansión de dBASE mediante DDE/OLE”
Capítulo
25 Impresión
Capítulo 25
Acerca de la impresión
Visual dBASE añade las capacidades de impresión del entorno Windows a las
capacidades de impresión que existían en versiones anteriores de dBASE. Visual dBASE
permite el uso de las variables de memoria del sistema para el control de la salida impresa.
Estas variables controlan todos los aspectos de la impresión, desde la selección del
controlador de impresora a la especificación de márgenes, interlineado y fuentes.
Dirección de la salida
dBASE ofrece elementos del lenguaje y utilidades de menús asociadas que determinan
qué impresora recibe la salida. La forma en que se dirige la salida depende de si envía
salida direccionable o direccionada.
La impresión en Windows está orientada a documentos; es decir, Windows considera cada
operación de impresión como la apertura y cierre de un documento, al que
normalmente se denomina documento de impresión. Debe estar abierto antes de poder
generar la salida y debe cerrarse antes de que la salida pueda enviarse a la impresora.
PROCEDURE SaltoPag
EJECT
* dBASE incrementará _pageno automáticamente
?? DATE() AT 1, "Página:" AT 67, _pageno PICTURE "999" AT 73 && Imprime la cabecera
&& de página
?
?
RETURN
Los valores que especifique son aditivos; por ejemplo, la distancia total desde el borde
izquierdo del papel hasta el primer carácter de un párrafo es el valor de _ploffset más el
número de columnas especificadas con _indent y _lmargin.
Estilos de texto
La opción STYLE de dBASE ofrece cinco estilos de texto, que se muestran en la Tabla
6.3. Estos estilos están disponibles para todas las fuentes instaladas en Windows.
• B especifica el estilo negrita.
• I especifica el estilo cursiva.
• U especifica el estilo subrayado.
• R especifica el estilo superíndice (elevado).
• L especifica el estilo subíndice (descendido).
Para utilizar un estilo de texto, especifique su letra en la opción STYLE. También es
posible combinar los estilos de texto:
Tabla 25.2 Ejemplos de los estilos de texto
Comando Resultado
? "Esta es una frase en negrita" STYLE "B" Esta es una frase en negrita
? "Esta es una frase inclinada "STYLE "I" Esta es una frase inclinada
? "Fuente Times New Roman subrayada" STYLE "1U" Fuente Times New Roman subrayada
? "Fuente Arial, tamaño 10 puntos y cursiva"; Fuente Arial, tamaño 10 puntos y
STYLE "2I" cursiva
Capítulo
LibFunc() LibFunc()
vínculo
Compilación y
Compilación
Compilación
LibFunc() LibFunc() LibFunc()
Los archivos DLL pueden tener cualquier extensión, como .DLL, .DRV, .FON o .EXE,
aunque la mayoría tienen la extensión .DLL. Los ocho primeros caracteres de cualquier
DLL cargado en memoria por una aplicación deben ser exclusivos, sea cual sea su
extensión. Es decir, si ha cargado SCRIPT.FON, no podrá cargar después SCRIPT.DLL.
El comando que intente cargar SCRIPT.DLL (ya sea EXTERN o LOAD DLL) no podrá
hacerlo ni comunicará ningún error.
Palabra clave que Nombre que Palabras clave que Nombre del archivo Nombre de la
representa el tipo de asigne a la representan los tipos de DLL que contiene la función en la DLL
datos del valor función datos de los parámetros función
devuelto por la función de la función
La Tabla 26.1 muestra las palabras clave de EXTERN para cada tipo de datos:
Tabla 26.1 Palabras clave de EXTERN para parámetros y valores devueltos
Palabra Tipo de Tipo de datos Tipo de
clave datos dBASE Tipo de datos C Pascal datos ASM
Parámetros CDOUBLE Numérico long double (80 bits) Double N/D
o valores CHANDLE Numérico Handles, como Handles, como dw
devueltos HANDLE, HWND, HWND, HFont,
HFONT, HDC HDC
CINT Numérico int Integer dw (16 bits)
CLOGICAL Lógico short Int Integer dw (16 bits)
CLONG Numérico long int (32 bits) Long Int dd (32 bits)
CSTRING Carácter char far * PChar dw (16 bits)
(terminado en cero)
CVOID N/D void Procedure N/D
CWORD Numérico short int (16 bits) WORD dw (16 bits)
Sólo CPTR N/D void * Pointer dd (32 bits)
parámetros
Las funciones del API de Windows devuelven, en ocasiones, dos valores en un solo
entero: uno en la palabra inferior y otro en la superior. Mediante las funciones de bits,
puede extraer y manipular estos valores. La Figura 26.2 ilustra la división en bits del
número 36783, un entero sin signo de 16 bits:
Figura 26.2 Numeración de los bits
Valores de
los bits 1 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1
Números de bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Capítulo
Acerca de DDE
El Intercambio dinámico de datos le permite intercambiar instrucciones e información
entre Visual dBASE y otra aplicación Windows mediante un canal denominado vínculo
DDE. Esta comunicación de dos vías funciona de forma parecida a una conexión
telegráfica, con dBASE en un extremo y otra aplicación Windows en el otro.
Cada aplicación del vínculo juega un papel diferente, dependiendo de la dirección en
que fluyen las instrucciones por la conexión. Una aplicación de un vínculo DDE es el
cliente, y la otra es el servidor. El cliente solicita datos al servidor, envía datos al servidor o
envía comandos para que los ejecute el servidor. El servidor juega un papel más pasivo;
es invocado por el cliente, y recibe datos, produce datos o realiza tareas según las
instrucciones del cliente. dBASE puede ser cliente, servidor o ambos al mismo tiempo;
es decir, puede invocar y dar instrucciones a otra aplicación, o ser invocado y recibirlas
de otra aplicación.
dBASE proporciona dos clases DDE, DDELink y DDETopic. Los objetos DDELink se
crean cuando dBASE es cliente y los DDETopic se crean con dBASE como servidor.
ContCar es una variable numérica que se incrementa una vez por cada fila sucesiva.
La función CHR( ) convierte este número a su equivalente de letra ASCII. El
programa inicializó ContCar con el comando siguiente:
ContCar = ASC("D")
Esto inicializa ContCar como 68; cuando se pasa a la función CHR( ), ésta devuelve
“D”, que es la letra de la primera columna.
• Número de fila: Quattro Pro utiliza números para identificar las filas de celdas.
Cada número de fila se guarda en ContFila, que se convierte al tipo carácter y se
eliminan los espacios iniciales con la siguiente llamada de función:
LTRIM(STR(ContFila))
El programa concatena estos tres elementos en la variable NombreCelda. El comando
siguiente utiliza NombreCelda como primer argumento del método Poke( ) para apuntar
a la celda e insertar el valor. El primer valor de NombreCelda es “A:D1”, que se traduce
como “Página A, Columna D, Fila 1”. El siguiente valor de NombreCelda es “A:E1”, es
decir “Página A, Columna E, Fila 1”. El proceso continúa hasta que todos los campos del
primer registro se escriben en sus celdas respectivas.
El bucle interior termina y la fila (controlada por la variable ContFila) se incrementa en 1.
ContCar se vuelve a definir como 68, y el registro siguiente se transfiere a las celdas de la
fila 2. La celda que recibirá el primer campo del segundo registro es A:D2.
El proceso continúa hasta que el último registro se escribe en la hoja de cálculo.
Este código de programa comienza una sesión en Quattro Pro, abre un archivo de hoja
de cálculo denominado MIHOJA.WB1 y establece un vínculo DDE entre la sesión de
Quattro Pro y la sesión actual de dBASE. El programa utiliza el método Execute( ) para
hacer lo siguiente:
1 Crea un nuevo archivo de texto denominado DATOS.TXT (comando {OPEN} de
Quattro Pro).
2 Envía el contenido de las celdas A1, A2 y A3 a DATOS.TXT (con el comando
{WRITELN} de Quattro Pro).
3 Cierre DATOS.TXT (con el comando {CLOSE} de Quattro Pro).
La aplicación cliente utiliza este nombre (en lugar de “DBASEWIN”) para ejecutar una
solicitud Initiate. Por ejemplo, para crear un vínculo DDE con la sesión
SERVIDOREXISTEN (en lugar de con otra sesión), Quattro Pro podría ejecutar la
siguiente solicitud {INITIATE}:
{INITIATE "SERVIDOREXISTEN", "MiTema", CHANNEL}
Para crear un vínculo DDE con la otra sesión (cuya propiedad DdeServiceName aún
contiene el valor por defecto “DBASEWIN”), Quattro Pro podría ejecutar la siguiente
solicitud {INITIATE}:
{INITIATE "DBASEWIN", "MiTema", CHANNEL}
Acerca de OLE
Vínculo e incrustación de objetos (OLE) es una tecnología de Microsoft que no sólo
permite que las aplicaciones intercambien datos, sino también que compartan código
según ciertas normas específicas. Por ejemplo, observe el archivo IMAGENES.WFM en
el directorio de ejemplos de Visual dBASE. Cuando se ejecuta IMAGENES.WFM,
muestra imágenes gráficas de mapa de bits. El campo de imagen de la tabla es un campo
OLE que está "vinculado" con la aplicación Paintbrush de Windows. Cuando se hace clic
en la imagen gráfica, se ejecuta Paintbrush desde dentro de Visual dBASE para permitir
la edición de la imagen (consulte la Figura 27.1).
Observe cómo el título y los menús de Paintbrush reflejan su vínculo con la ficha de
Visual dBASE.
Figura 27.1 Paintbrush iniciado desde dentro de dBASE mediante OLE.
Los objetos OLEAutoClient no tienen que residir dentro de las fichas. También pueden
utilizarse dentro de los programas de dBASE y desde la ventana de comandos.
Las propiedades, sucesos y métodos de un objeto OLEAutoClient se determinan por la
aplicación servidor. Las aplicaciones OLE2 varían considerablemente en su
implementación, por lo que debería consultar la documentación de las aplicaciones
servidor para conocer detalles específicos. El programa siguiente demuestra cómo crear
un gráfico y situarlo en una ficha usando Excel.
* abre objetos
unaHoja = NEW OLEAutoClient("Excel.Sheet")
unaHoja.Application.Visible = .T.
USE animales
* crea rejilla
celda = unaHoja.Cells( 2, 1 )
celda.Value = "Tamaño"
celda = unaHoja.Cells( 3, 1 )
celda.value = "Peso"
SCAN
celda = unaHoja.celdas( 1, RECNO() + 1)
celda.value = animales->nombre
celda = unaHoja.celdas( 2, RECNO() + 1)
celda.value = animales->tamano
celda = unaHoja.celdas( 3, RECNO() + 1)
celda.value = animales->peso
ENDSCAN
* crea gráfico
unGrafico = unaHoja.ChartObjects.Add(100, 100, 200, 200)
series = unGrafico.chart.SeriesCollection
series.Add("Hoja1!R1C1:R2C7",.T.)
series.Add("Hoja1!R3C1:R3C7",.T.)
* copia gráfico a dBASE
unGrafico.Copy()
unaHoja.application.quit()
* crea tabla temporal que contendrá el gráfico
temp1DBF = FUNIQUE()
CREATE (temp1DBF) STRUCTURE EXTENDED
APPEND BLANK
REPLACE field_name WITH "OLE", field_type WITH "G"
temp2DBF = FUNIQUE()
CREATE (temp2DBF) FROM (temp1DBF)
CLOSE TABLES
DELETE TABLE (temp1DBF)
* crea ficha con control OLE
USE (temp2DBF) NOSAVE
APPEND BLANK
f1 = new form()
ole = new ole(f1)
ole.width = f1.width
ole.height = f1.height
ole.datalink = "OLE"
f1.OnOpen = { ; KEYBOARD "{Ctrl+V}" CLEAR }
f1.OnClose = { ; CLOSE TABLES }
f1.open()
* fin de ejemplo de Excel
Parte
VI
Apéndices
ParteVI
Apéndice
Ejecución de aplicaciones
ApéndiceA
A
de dBASE para DOS
Visual dBASE es compatible con dBASE III PLUS, dBASE IV y dBASE 5.0 para DOS, y la
mayoría de aplicaciones escritas para dBASE DOS se ejecutan con pocos o ningún
cambio en el código fuente. Para comenzar, simplemente ejecute la aplicación y observe
cómo funciona.
Nota En este apéndice, dBASE III PLUS, dBASE IV y dBASE 5.0 para DOS se mencionan
como dBASE DOS cuando lo que se trata se aplica a todos ellos.
Debido a las diferencias inherentes entre el entorno basado en caracteres de DOS y el
entorno gráfico de Windows, las aplicaciones complejas pueden precisar algunos
cambios para que se ejecuten correctamente. Además, algunos comandos y funciones de
dBASE DOS no son adecuados para el entorno Windows y tienen unos equivalentes
nuevos.
Este apéndice proporciona consejos generales para ejecutar aplicaciones dBASE DOS.
Cuando esté preparado para mejorar la aplicación con las características de Visual
dBASE, consulte el Apéndice B.
Pasos básicos
A continuación se resumen los pasos que debe seguir para ejecutar las aplicaciones de
dBASE DOS. Cada paso se explica en profundidad en las secciones siguientes.
1 Tipos de archivos permitidos. Copie los archivos DOS necesarios en un directorio que
esté en la vía de acceso o añada el directorio en que se hallan los archivos en la vía de
acceso actual de Visual dBASE.
2 Entorno de configuración de Windows. Si es necesario, cambie los valores por defecto
definidos en el entorno DOS a las definiciones correspondientes de Windows.
Asegúrese de que la aplicación no precisa el uso de ciertas pulsaciones que tienen un
significado diferente en el entorno Windows.
3 Mejoras en el lenguaje. Algunos de los comandos permitidos funcionan en Visual
dBASE de forma distinta a como lo hacen en dBASE DOS. Podrían tener valores por
defecto distintos, valores máximo y mínimo diferentes o nuevas opciones. Revise esta
sección para comprobar si algunos de estos cambios afectan a sus aplicaciones.
4 Diferencias en los códigos de error. Muchos códigos de error en Visual dBASE son los
mismos que en dBASE IV y dBASE 5.0 para DOS, aunque algunos han cambiado. Si
una aplicación utiliza comandos ON ERROR, lea esta sección para averiguar si debe
actualizar algún código de error en la aplicación.
Copie los archivos que necesite a un directorio que esté incluido en la vía de acceso de
Visual dBASE o añada su posición actual en la vía de acceso.
DBASEWIN.INI
Algunas aplicaciones de dBASE DOS dependen de definiciones específicas guardadas
en el archivo de configuración CONFIG.DB, pero Visual dBASE no lo lee, sino que
utiliza un archivo .INI, DBASEWIN.INI, para la configuración. Los archivos .INI son
archivos de texto que las aplicaciones Windows emplean para almacenar las
definiciones de configuración. El propio Windows utiliza WIN.INI y SYSTEM.INI (entre
otros) para configurar su entorno.
Algunas definiciones de CONFIG.DB tienen equivalentes en DBASEWIN.INI. Otras se
toman de Windows y no son necesarias en DBASEWIN.INI. Si una aplicación depende
de los parámetros de CONFIG.DB, debe ajustar el código o añadir definiciones
equivalentes en el archivo DBASEWIN.INI. El Apéndice C de la Guía del usuario describe
todos los parámetros de DBASEWIN.INI.
La Figura A.1 muestra cómo corresponden estos comandos SET a los parámetros de la
opción Internacional.
Figura A.1 Comandos que anulan los parámetros de la opción Internacional del Panel de control
Mejoras en el lenguaje
Algunos comandos de dBASE DOS son innecesarios en el entorno Windows y se han
suprimido. Otros se han sustituido por nuevos comandos o funciones. El Apéndice A de
la Referencia del lenguaje enumera todos los comandos de dBASE III+/IV que Visual
dBASE ya no utiliza.
Los comandos para los que no hay soporte en Visual dBASE no producen errores
durante la compilación ni durante la ejecución, ni tienen efecto alguno en el programa.
Visual dBASE simplemente no los tiene en cuenta.
Aunque una aplicación se ejecute bajo Visual dBASE sin cambios, debería repasar la lista
de comandos no permitidos de la Referencia del lenguaje. Si hay una parte concreta de la
aplicación que dependa de uno de estos comandos, deberá modificar el código
ligeramente para que refleje el nuevo entorno en que se ejecuta la aplicación.
Por ejemplo, si la aplicación utiliza bases de datos SQL, habrá utilizado los comandos
BEGIN TRANSACTION y END TRANSACTION para controlar cuándo se escriben los
cambios en un registro. Puesto que Visual dBASE está diseñado para programación
controlada por sucesos, estos comandos se han sustituido por funciones denominadas
BEGINTRANS(), COMMIT() y ROLLBACK(). Los comandos antiguos no devuelven un
error, pero no tienen el mismo efecto que tenían en dBASE IV o dBASE 5.0 para DOS.
Apéndice
El Generador de componentes
El Generador de componentes es una utilidad que traduce el código generado por las
utilidades de diseño de dBASE IV al formato utilizado por las de Visual dBASE.
Aunque estos archivos se ejecutan tal cual, si los procesa con el Generador de
componentes, podrá mejorarlos con los controles estándar en Windows, como botones
y cuadros de lista.
Mediante el Generador de componentes, puede convertir con facilidad los archivos de
formato, informe y etiqueta de dBASE IV al entorno Windows. Después de ejecutar el
Generador de componentes, cargue el código generado en las utilidades de diseño de
Visual dBASE como el Diseñador de fichas y el Diseñador de menús.
El Generador de componentes es un programa de Visual dBASE instalado en el
subdirectorio UTIL. Ejecútelo con el archivo de programa CB.PRO. Para instrucciones
sobre el uso del Generador de componentes, consulte su ayuda en línea.
Estrategias de mejora
Los bloques en que se basan las aplicaciones de Visual dBASE son las fichas, que son
ventanas que contienen objetos con los que interactúa el usuario. Su principal labor en la
mejora de una aplicación es crear las fichas que constituyen el interface de usuario.
Para detalles sobre la creación de fichas con el Diseñador de fichas, consulte la Guía del
usuario. Para una explicación del código utilizado por el Diseñador de fichas, consulte
los Capítulos 13 a 16 de este manual.
Los pasos que siga dependen principalmente del tipo de interface de usuario que desee
desarrollar. Como se describe en el Capítulo 13, hay tres planteamientos básicos:
• Un interface modal es como el de una aplicación de dBASE III PLUS o dBASE IV.
El usuario interactúa con una ficha cada vez, y cada ficha tiene el control exclusivo
del escritorio. Es muy fácil mejorar una aplicación en un interface modal.
• Un interface no modal está completamente controlado por sucesos. El usuario puede
interactuar con más de una ficha, o ejecutar más de un programa, simultáneamente.
La conversión de su aplicación a un interface no modal podría precisar alguna
reestructuración del código para hacerla completamente controlada por sucesos.
• Un interface no modal orientado a objetos también está controlado por sucesos. La
conversión de su aplicación a un interface orientado a objetos implica la traducción
del código a una serie de declaraciones de clase, que son muy reutilizables.
El Diseñador de fichas emplea este planteamiento, generando una declaración de
clase para cada ficha que cree.
Este apéndice trata las cuestiones que afrontará al convertir una aplicación a un interface
modal que utiliza fichas. Comienza mostrando una aplicación simple primero en
dBASE IV y luego mejorada en Visual dBASE. A continuación, describe las diferencias
principales entre las dos versiones. Para mejorar aún más la aplicación y reprogramarla
para un interface no modal u orientado a objetos, consulte la comparación de los tres
planteamientos en el Capítulo 13.
FUNCTION BuscaNombre
IF LEN(TRIM(cNombre) > 0
SEEK UPPER(TRIM(cNombre))
IF .NOT. FOUND()
? CHR(7)
@ 0, 11 SAY "Nombre no encontrado. Inténtelo de nuevo"
ELSE
DO EDITA
ENDIF
BuscaMas = .T.
ELSE
BuscaMas = .F.
ENDIF
RETURN BuscaMas
PROCEDURE EDITA
ACTIVATE WINDOW EDITCLI
@ 2, 2 SAY "Nombre"
@ 2, 14 GET CLIENTE->NOMBRE;
COLOR ,N/GB
@ 4, 2 SAY "Calle"
@ 4, 14 GET CLIENTE->CALLE;
COLOR ,N/GB
@ 6, 2 SAY "Ciudad"
@ 6, 14 GET CLIENTE->CIUDAD
COLOR ,N/GB
@ 8, 2 SAY "Provincia"
@ 8, 14 GET CLIENTE->PROVINCIA;
COLOR ,N/GB
@ 10,2 SAY "C. Postal"
@ 10,14 GET CLIENTE->COD_POST;
PICTURE "!!!!!!!!!!";
COLOR ,N/GB
@ 12,2 SAY "Teléfono"
@ 12,14 GET CLIENTE->TELEFONO;
PICTURE "999-999-9999";
COLOR ,N/GB
READ
DEACTIVATE WINDOW EDITCLI
RETURN
BuscaCli.ReadModal()
PROCEDURE PulsadoOK
IF .NOT. EMPTY(form.Entrada1.Value)
SEEK(UPPER(TRIM(form.Entrada1.Value)))
IF .NOT. FOUND()
? CHR(7)
form.StatusMessage = "Nombre no encontrado. Inténtelo otra vez"
form.Entrada1.SetFocus()
ELSE
form.StatusMessage = ""
form.Entrada1.Value = SPACE(nLongNombre)
CLOSE FORM BuscaCli
ENDIF
ELSE
form.StatusMessage = ""
CLOSE FORM BuscaCli
ENDIF
RETURN
Inicialización
La mayoría de programas de dBASE comienzan con comandos que inicializan variables
públicas y configuran el entorno. Las aplicaciones de Visual dBASE utilizan pocas
variables globales, y muchas definiciones globales se especifican mediante propiedades
de objetos o simplemente no son operativas.
La aplicación de dBASE IV comienza con varios comandos SET y la declaración de una
variable pública. La aplicación de Visual dBASE comienza con directivas de
preprocesador y un solo comando SET.
Figura B.3 Comparación del código de inicialización
• En dBASE IV, SET TALK OFF desactiva la salida de comandos y CLEAR borra la
pantalla. En Visual dBASE, la salida de comandos sólo aparece en el panel de
resultados de la ventana de comandos. Puesto que las fichas aparecen en el escritorio,
estos comandos no son necesarios.
• En la aplicación de dBASE IV, SET SCOREBOARD OFF y SET STATUS OFF
desactivan la visualización de la información de estado, que aparece en el área
direccionable de la pantalla y puede entrar en conflicto con la salida en pantalla.
En Visual dBASE, esta información aparece en la línea de estado, área no
direccionable del entorno. Puesto que no puede haber conflicto con la salida en
pantalla, estos comandos no son operativos.
• En las aplicaciones Windows, la tecla Intro suele aceptar fichas, de forma similar a
Ctrl+W en dBASE III PLUS o Ctrl+Fin en dBASE IV. El nuevo comando de Visual
dBASE, SET CUAENTER OFF, hace que la tecla Intro se comporte como en
dBASE DOS, moviendo el foco al siguiente control disponible.
En general, debería dejar SET CUAENTER con su valor por defecto ON; sin
embargo, para facilitar la transición a las pulsaciones de Windows, puede definirlo
como OFF al principio de los programas convertidos. Para ver una lista de las
pulsaciones empleadas en Visual dBASE, consulte el Apéndice B de la Guía del
usuario.
• La aplicación de dBASE IV inicializa nLongNombre como variable pública. En Visual
dBASE, las constantes globales suelen definirse mediante #define, una directiva del
preprocesador. Para más información sobre estas directivas, consulte el Capítulo 7.
Creación de la ventana
En ocasiones, las aplicaciones de dBASE IV crean ventanas para mostrar datos.
En Visual dBASE, toda la interacción del usuario se produce dentro de las fichas, que
son ventanas del tipo Windows que contienen objetos del interface de usuario.
Para más información sobre la programación con diferentes tipos de ventanas de ficha,
consulte el Capítulo 13.
La aplicación de dBASE IV crea una ventana para editar clientes; la de Visual dBASE
hace lo mismo con una ficha. Ambas aplicaciones utilizan EDITCLI.QBE para
configurar el entorno de la tabla.
Figura B.4 Comparación de la creación de la ventana
• En dBASE IV, DEFINE WINDOW simplemente crea una ventana donde aparece la
salida, como los comandos @...SAY. En Visual dBASE, DEFINE FORM crea un objeto
de ficha con muchas propiedades que puede definir. Este ejemplo define las
siguientes propiedades de ficha:
• La propiedad EscExit, definida como .T., permite salir de la ficha pulsando Esc.
• La propiedad Text muestra un mensaje en la barra de título de la ventana.
• La propiedad MDI debe definirse como .F. para las ventanas no modales.
El Capítulo 13 describe las características de las ventanas MDI.
• En dBASE IV, el comando SET VIEW configura el entorno de la tabla en un archivo
.QBE. En Visual dBASE, el mismo archivo .QBE se vincula con la ficha mediante la
propiedad View de la ficha.
Variables de memoria
El uso de variables de memoria se mejora significativamente en Visual dBASE. Para la
introducción y visualización de datos, se utiliza la propiedad Value de los objetos en
lugar de crear variables de memoria globales. Si utiliza variables de memoria
tradicionales, puede gestionarlas con mayor eficacia mediante los dos nuevos ámbitos:
local y estático. El Capítulo 5 describe en detalle los ámbitos de las variables de
memoria.
Ambas aplicaciones piden al usuario un nombre que buscar.
Figura B.6 Comparación de las variables de memoria
Procedimientos y funciones
El código contenido en los procedimientos y funciones —el núcleo de la mayoría de
programas de dBASE— es muy similar en dBASE IV y en Visual dBASE. Se diferencian
principalmente en la forma en que se llaman y en cómo hacen referencia a los datos.
Dado que las aplicaciones Visual dBASE son controladas por sucesos, los
procedimientos y funciones suelen ejecutarse cuando se producen los sucesos, no
cuando un programa los llama explícitamente. Además, como se ha mencionado
anteriormente, Visual dBASE almacena muchos elementos de datos en forma de
propiedades de objetos. Las subrutinas utilizan la “notación de punto” para hacer
referencia a las propiedades.
El Capítulo 2 presenta la programación controlada por sucesos y el Capítulo 14 describe
cómo escribir controladores de sucesos. Para una introducción al trabajo con objetos y
propiedades, consulte el Capítulo 9.
Ambas aplicaciones utilizan una subrutina para buscar el nombre.
La Figura B.8 compara el código de menú de dBASE IV con uno similar de Visual
dBASE. El código de dBASE IV, extraído de la aplicación de ejemplo GESTION.PRG,
crea un menú de ventana; el código de Visual dBASE, extraído de la aplicación
GESTION.PRG mejorada, crea una jerarquía de objetos de menú.
DEFINE POPUP Principal FROM 7,27 TO 22,50 DEFINE MENU Ver OF f.Main;
PROPERTY Text "&Ver"
DEFINE BAR 1 OF Principal;
PROMPT "===== MENU PRINCIPAL =====" SKIP DEFINE MENU Empleados OF f.Main.Ver;
PROPERTY Text "&Empleados",;
DEFINE BAR 2 OF Principal ; OnClick VerEmpleados
PROMPT " Tablas:" SKIP
DEFINE MENU Clientes OF f.Main.ver;
DEFINE BAR 3 OF Principal; PROPERTY Text "&Clientes",;
PROMPT "EMPLEADOS" OnClick VerClientes
DEFINE BAR 4 OF Principal; DEFINE MENU Vendedores OF f.Main.ver;
PROMPT "CLIENTES" PROPERTY Text "&Vendedores",;
DEFINE BAR 5 OF Principal; OnClick VerVendedores
PROMPT "VENDEDORES" DEFINE MENU Inventario OF f.Main.ver;
DEFINE BAR 6 OF Principal; PROPERTY Text "&Inventario",;
PROMPT "INVENTARIO" OnClick VerInventario
DEFINE BAR 7 OF Principal; DEFINE MENU Cuentas Of f.Main.Ver;
PROMPT "PEDIDOS" PROPERTY Text "C&uentas",;
DEFINE BAR 8 OF Principal; OnClick VerCuentas
PROMPT "CUENTAS" DEFINE MENU Prefijos OF f.Main.ver;
DEFINE BAR 9 OF Principal; PROPERTY Text "&Prefijos",;
PROMP "PREFIJOS" OnClick VerPrefijos
Mejoras adicionales
El Capítulo 1 enumera las características nuevas más importantes del lenguaje en Visual
dBASE. Consulte ese capítulo para obtener ideas. Estos son algunos ejemplos de las
mejoras que quizá desee aplicar:
• Para mostrar botones con iconos personalizados para tareas comunes como Aceptar,
Cancelar o Ayuda, utilice los controles de BOTONES.CC en el subdirectorio
EJEMPLOS. El Capítulo 15 describe cómo crear y utilizar controles personalizados de
dBASE y VBX.
• Las siguientes funciones nuevas muestran cuadros de diálogo para recibir la entrada
del usuario:
• CHOOSEPRINTER() muestra un cuadro de diálogo para seleccionar una
impresora y devuelve la impresora elegida.
• GETCOLOR() muestra un cuadro de diálogo donde puede definir un color
personalizado o seleccionar un color en la paleta de colores.
• GETDIRECTORY() muestra un cuadro de diálogo donde puede seleccionar un
directorio para su uso con los comandos siguientes.
• GETEXPR() muestra el Generador de expresiones y devuelve la expresión creada.
• GETFILE() y PUTFILE() muestra cuadros de diálogo en que el usuario puede
elegir o introducir un nombre de archivo existente, o uno nuevo, respectivamente.
• GETFONT() muestra un cuadro de diálogo en que seleccionar una fuente.
Devuelve una cadena que contiene el nombre de la fuente, el tamaño en puntos,
el estilo (si elige otro que no sea Normal) y la familia.
• Si la aplicación utiliza archivos .PRS que contienen sentencias de SQL, emplee la
función SQLEXEC(). Para más información, consulte el Capítulo 23.
Apéndice
Depende
de la fuente
ANSI ANSI
Nota Cuando dBASE envía la salida a la pantalla, el juego de caracteres depende de la fuente
utilizada. Por ejemplo, las áreas siguientes de la pantalla utilizan por defecto el juego de
caracteres OEM:
• Editor de textos (incluidos los archivos memo)
• Campos de entrada
• Ventana de comandos
Por contra, las áreas siguientes de la pantalla utilizan por defecto una fuente ANSI:
• Ventana de registros de la tabla
• Rótulos en los botones
• Selector de archivos
Por ejemplo, los comandos siguientes abren un archivo de tabla y crean otro con el
LDID definido como el controlador de idioma global actual:
USE CLIENTES && LDID especifica un controlador de idioma distinto del global
COPY TO CLIENTE && El LDID de CLIENTE.DBF especifica el controlador de idioma de
&& CLIENTES.DBF.
Los comandos siguientes abren un archivo de tabla y crean un archivo de tabla
ordenada con un LDID definido como el controlador de idioma de la tabla original:
USE CLIENTES && LDID especifica un controlador de idioma distinto del
&& global
SORT ON APELLIDOS TO CLIENTE && El LDID de CLIENTE.DBF es el mismo que el de
&& CLIENTES.DBF
Por ejemplo, cuando se crea un archivo de tabla con el controlador de idioma de alemán,
se escribe un identificador LDID en el área de cabecera del archivo. Cuando se abren los
archivos en una sesión de Visual dBASE en que el controlador de idioma global es de
inglés, existe una discrepancia entre los juegos de caracteres. Si crea un índice con
INDEX ON, el orden lógico del índice obedece al controlador de idioma de la tabla:
USE VOLK && Creado con el controlador de idioma de alemán
INDEX ON NAMEN TAG DIENAMEN && Ordena los registros según el orden alfabético alemán
Por contraste, si crea un filtro con SET FILTER, la condición de filtro obedece al
controlador de idioma global:
USE VOLK
SET FILTER TO NAMEN = "KONIG" && Excluye los registros con "KÖNIG" en NAMEN
Indice
Símbolos alineación
horizontal 392
aplicaciones
orientadas a objetos,
# Vea directivas de números a la derecha 78 diseño 179-180
preprocesador números a la izquierda 78 uso compartido de datos 403
& (operador de macro) 64-65 salida impresa 388, 392 archivos
( ) (operador de llamada) 39 almacenamiento apertura en el Depurador 100
* (asterisco) en consultas cambios 279 ayuda 233
SQL 356 configuración del biblioteca 46
+ (operador de Depurador 124 borrado 275
concatenación) 72 ámbito cobertura 32
– (operador de archivos de memoria 66 impresión en 380, 382
concatenación) 72 Depurador 121 índice múltiple 297
. (operador de punto) 143 identificadores 90 índice simple 297
: (delimitador) objetos 152 memoria 66
nombres de campo 284, 337 opciones de edición 281 ámbito 66
para controladores de variables de memoria 54-59, objeto 26
idioma 453 177 procedimiento 44, 46
:: (operador de resolución de ampersand (&), operador de programa 44
macro 64-65 extensiones por defecto 26
ámbito) 169
Añadir punto de evaluación, registro de Paradox 340
@...SAY, comandos 291 texto, visualización en el
[ ] (operador de índice) 144 cuadro de diálogo 116
Añadir punto de ruptura, cuadro Depurador 125
de diálogo 109 vinculación 28
A análisis de cobertura 30-33 archivos de covertura 32
actualización finalización 31 áreas de trabajo 272
campos memo 292 inicio 30 alias 272
datos #pragma 96 campos 283
indexación 303 análisis de covertura no actual 272
transacciones 330 definido 13 AreUSure( ) 165
índices 288, 303 ancho máximo de línea en el Argumentos de parámetros,
información de bloqueos de editor de textos 25 cuadro de diálogo 113
registros 324 animación de programas aritméticos, operadores de
variables automem 291 (Depurador) 104 consultas SQL 361
actualización de datos definición de velocidad 123 ASCII, juego de caracteres 444
datos ANSI, juego de caracteres 444 associative arrays
transacciones 334 anulación defined 13
adición miembros heredados 168 asterisco (*) en consultas
características de Windows en tipos de tabla 337 SQL 356
menús 258-260 apaisado, modo (impresión) 387 AUTO 27
elementos en matrices 61 apertura automem, variables 291
puntos de evaluación archivos en el Depurador 100 liberación 291
(Depurador) 116 bases de datos 270 sustitución 291
puntos de ruptura 107, 110 varias 336 avance
registros 285 documentos OLE 294 hoja 388
agrupamiento de datos en fichas páginas 388
consultas SQL 368-369 modales/no modales 197 ayuda, provisión 233
aislamiento secuencia de sucesos 220
niveles índices 301
transacciones 334 tablas 269
ajuste vertical 392 exclusivamente 319
alias de tabla 271 sólo lectura 319
aplicación, objeto 132
Indice 455
pg_dbw.ix Page 456 Wednesday, August 30, 1995 2:32 PM
Indice 457
pg_dbw.ix Page 458 Wednesday, August 30, 1995 2:32 PM
Indice 459
pg_dbw.ix Page 460 Wednesday, August 30, 1995 2:32 PM
Indice 461
pg_dbw.ix Page 462 Wednesday, August 30, 1995 2:32 PM
N O ocultación
métodos 164
.NDX, archivos 297 objeto, archivos propiedades 164
conversión a .MDX 297 vinculación 28 ocultación de datos 57
negrita 391 objetos 158 OEM, páginas de códigos 444
NEW, operador clases 138 OLE 413-415
creación de objetos 139 creación 139-141 OLE, campos Vea campos OLE
y comando DEFINE 148 definidos por el OLE, tipos de datos 292
NextIndex( ) 157, 158 usuario 150 OnChange, controlador de
no dBASE, campos dentro de objetos 148 sucesos 228-230
conversión 336 diseño orientado a 175-191 OnClick, controlador de
no dBASE, funciones 397 ejemplo 180 sucesos 222
no dBASE, tablas 335-345, 347 en otros objetos 134
OnGotFocus, controlador de
acceso 335 explicación 133
sucesos 232
delimitación de nombres de extensión 131
interfaces orientados a OnHelp, controlador de
campo 284 sucesos 233
posición en bases de objetos y dBASE III+/
IV 428 OnInitMenu( ) 258
datos 336 OnLostFocus, controlador de
transacciones 340 jerarquía de menús 257
liberación 152 sucesos 232
no dBASE, tipos de datos 85 OnMove, controlador de
no modal, interface comparado matrices como 153
matriz sucesos 234
con dBASE III+/IV 428 OnNavigate 230
creación 153
no modales, ventanas 195 OnOpen 261
padre/hijo 134
nombre propio, formato 74 programación de fichas OnSize, controlador de
nombres orientada a 206 sucesos 235
campos propiedades operadores
delimitación 337 inspección 121 acceso a miembro 143-144
sesiones de dBASE referencia 149 concatenación (+ y –) 72
(DDE) 412 referencia consultas SQL
tablas 270 interna 152 aritméticos 361
notación de punto 143 miembros 142 comparación 358
referencia a métodos 169 múltiples 149 lógicos 359
NULL 85 notación de llamada (paréntesis) 39
número de líneas en el punto 143, 149 lógicos
Depurador 102 padre e hijo 149 .NOT. 84
números relación padre-hijo 135 macro (&) 64-65
alineación 78 variables resolución de ámbito (::) 169
asignación a fuentes tipos de datos 134 ordenación
(impresión) 390 variables de referencia 142 frente a indexación 295
en fichas 78 como parámetros 146, 151 registros 295, 296
form 143, 160 ordenación de consultas
múltiples 148 SQL 365-367
this 142, 160
y variables orientación a objetos 129
tradicionales 146 programación de fichas 206
P posición
por defecto de pantalla
programas
análisis 30-33
padres, objetos 134 (aplicaciones de dBASE animación (Depurador) 104
páginas III+/IV) 420 archivos 44
avance 388 puntero de registro 280 cabecera en las fichas 252
impresión de rangos 389 salida impresa 383 control de ejecución
páginas de códigos 444 tablas en bases de datos 336 (Depurador) 104
coincidencia 449 tabulación (impresión) 388 depuración 97-124
identificación 451 #pragma 96 detención de la ejecución 113
internas y DOS 446 análisis de cobertura 31, 32 ejecución desde el
palabras clave preprocesador Vea directivas de Depurador 112
con EXTERN 396 preprocesador ejecución y
en declaraciones de clase 169 privadas, variables de modalidad 198-199
PICTURE 78 memoria 56 restablecimiento 113
pantalla, juego de caracteres 445 procedimientos 36 visualización en ventana
Paradox, tablas Vea tablas de almacenados Pila 115
Paradox declaración 372 propiedades
parámetros declaración inspección de objetos 121
bloques de código 47 automática 373 menús de una ficha 258
clases locales 163 limitaciones 374 ocultación 164
declaraciones de clase 163 almacenados (SQL) 371-374 personalizadas 145
#define 91 archivos 44, 46 programación 129
número 41 búsqueda en el protección 164-165
pase 13, 37-42 Depurador 103 reinicialización 168
en el Depurador 113 código del Diseñador de protección
referencias form 212 fichas 252 datos 276
subclases a declaración 37 métodos 164-165
superclases 172 disponibilidad 44 propiedades 164-165
tipo de datos 40 ejemplos 37 protección de variables de
pasadas, número 111 frente a funciones 36 memoria 43
pase de parámetros 13, 37-42 pase de parámetros a 39-41 prototipos
en el Depurador 113 uno solo 45 declaración 396
referencias form 212 varios 45 para pasar parámetros 396
paso a paso en programas PROCEDURE 38 pseudofunciones 92
(Depurador) 106 proceso públicas, variables de
patrón de trabajo transacciones 330 memoria 56
objeto-acción 19 producción, archivos .MDX 297 pulsaciones
PCOUNT( ) 41 programa, archivos parámetro de marcas 235
personalización vinculación 28 reservadas (advertencia) 424
controles 237-243 programación punteros de función frente a
definición 237 carácter de continuación 25 bloques de código 49
ejemplos 241 caracteristicas de 12 punteros de registro 280
instalación 238 controlada por sucesos y determinación de la
fichas 237, 244-250 tradicional 211 posición 282
propiedades y métodos 145 controladores de punto de código 444
PICTURE, palabra clave 78 sucesos 211-236 punto, notación 143
Pila, ventana (Depurador) 115 convenciones puntos de evaluación 116
plano de coordenadas estilísticas 24-25 modificación de valores de
fichas 262 copias 130 expresiones 118
impresión 383 estrategias 200-208 puntos de ruptura 107-112
polimorfismo marcas de comentario 24 acción 111
definición 179 mayúsculas y minúsculas 25 borrado 108
ejemplo 181 modular 35 definición 107, 110
orientada a objetos 129-138 ejecución de programas
propiedades 129 hasta 112
sangrado del código 24 globales o específicos 109
visual 17 número de pasadas 111
Indice 463
pg_dbw.ix Page 464 Wednesday, August 30, 1995 2:32 PM
R relación
INTEGRITY 305
SET NEAR y búsquedas 312
SET PROCEDURE 27
rangos de valores de tablas 304 SetSalary( ) 165
inspección 120 RemoveAll( ) 157, 158 SetSSN( ) 165
ratón RemoveKey( ) 157, 158 signo # Vea directivas de
control de sucesos 235 reordenación de registros e preprocesador
técnicas 2 indicadores 338 símbolo monetario 77
RDBMS, definición 347 repetición de caracteres 75 sintaxis
recuento de registros 282 REPLACE, comando 289 #define 91
recuperación de configuración resolución de ámbito, operador errores 98
del Depurador 124 (::) 169 sistema, variables de memoria
recuperación de registros 290 restablecimiento de Vea impresión
redeclaración de métodos 168 programas 113 sólo lectura, tablas 319
redondeo de valores RESTRICTED 305 soporte
decimales 80 RETURN, puntos de ruptura en sintaxis de SQL 351-353
referencia el comando 113 tablas de Paradox y
genéricas RLOCK() 325 SQL 345-346
programación 212 ROLLBACK 349 tipos de archivos de dBASE
índices no dBASE 342 ROLLBACK( ) 11 III+/IV 421
integridad 305 SOUNDEX, indexación con 300
métodos 169
miembros de un objeto 142
S SQL 10, 347-374
comandos 349
objetos salida consultas
interna 152 código 219-221 agrupamiento de
notación de punto 143 direccionable 379 datos 368-369
padre e hijo 149 dirección 380 creación 355-371
por notación de punto 149 direccionada 379 diferencia de mayúsculas/
propiedades de objetos 149 dirección 381 minúsculas 358
Refresh( ) 231 seguimiento de programas operadores
registros 277 (Depurador) 105 aritméticos 361
adición 285 seguridad 344 operadores de
bloqueo SELECT de SQL 355-371 comparación 358
automático 321 expresiones 362 operadores lógicos 359
información de estado 323 opción DISTINCT 356, 365 ordenación 365-367
sesiones 326 varias tablas 370
opción FROM 355
borrado Paradox/SQL 339 definición 347
opción GROUP BY 368-369
búsqueda 310-312 errores 353
opción HAVING 369
control de duplicaciones 300 incrustado 354
opción ORDER BY 365, 366,
cuadro de incremento de lectura recomendada 348
367
desplazamiento 241 procedimientos
opción UNION 370
edición 279 almacenados 371-374
opción WHERE 357, 363, 365
filtrado 314 sentencias
separadores numéricos 77 COMMIT 349
en vistas 315 SEQUEL 347
huérfanos 305 ROLLBACK 349
servidor SELECT 355-371
indicadores como
aplicación de control servidores 354
números 338
(DDE) 407 sintaxis permitida 351-353
inserción 339
dBASE 409 tablas
marcado para borrado 290
DDE 403 compatibilidad de tipos
ordenación 295, 296
transacciones 330 de datos 358
recuento 282 niveles de aislamiento 334
secuencia 301 términos 348
sesiones 326-327 usos 347
sin numerar, sustitución 339
cierre 327 SQL, tablas Vea tablas SQL
sustitución de valores 289
creación 327 SQLError( ) 353
reinicialización de
integridad de datos 326 SQLExec( ) 350
propiedades 168 múltiples 318 SQLMessage( ) 353
SET CUAENTER 209 subcadenas, extracción 73
SET EXACT y búsquedas 312
Indice 465
pg_dbw.ix Page 466 Wednesday, August 30, 1995 2:32 PM
estáticas 57 W
disponibilidad 58
globales 56 WindowMenu 258
liberación 52 Windows
locales 57 adición de sus características
nombre 25 en menús 258-260
privadas 56 API 393-402
protección de valores 43 constantes 401
públicas 56 controladores de
restauración 66 impresora 378
sistema Vea impresión creación de archivos de
tipos 54 ayuda 233
tradicionales y referencia a Windows environment 9
objeto 146
uso 51
VBStream, propiedad 242
Z
VBX, controles 242 ZAP, comando 290
instalación 239
Velocidad de animación, cuadro
de diálogo 123
ventanas
dBASE IV 435
identificadores 397
MDI 196
modales/no modales 195-199
vertical, modo (impresión) 387
vinculación
archivos 28
vinculación de controladores de
sucesos 213-217
vínculo e incrustación de objetos
Vea OLE
vínculos DDE 403-413
Vea también DDE
dinámicos 408
establecimiento 405
finalización 405
Peek() y Poke() 405
Visor, ventana (Depurador) 116
Visual dBASE Compiler 28
visualización
archivos de texto en el
Depurador 125
expresiones en el
Depurador 116
flujo del programa 115
®
VERSIÓN 5.5 dBASE para Windows
Borland International, Inc., 100 Borland Way
P.O. Box 660001, Scotts Valley, CA 95067-0001
title.dwp Page ii Wednesday, August 30, 1995 1:55 PM
Borland puede tener patentes y/o aplicaciones pendientes de patente que cubren el contenido de este documento.
La posesión de este documento no concede al usuario licencia para esas patentes.
COPYRIGHT © 1984, 1994 Borland International. Todos los derechos reservados. Todos los productos de Borland
son marcas comerciales o marcas comerciales registradas de Borland International, Inc. Otras marcas y nombres
de productos son marcas comerciales o marcas comerciales registradas de sus propietarios respectivos.
pg_dbw.toc Page i Wednesday, August 30, 1995 1:56 PM
Contenido
Introducción 1 Parte I
Organización de este manual . . . . . . . . . . . . 2 Conceptos básicos de
Uso del ratón . . . . . . . . . . . . . . . . . . . . .2
Uso del teclado . . . . . . . . . . . . . . . . . . . .3
programación 15
Referencias a dBASE para DOS . . . . . . . . . .3
Capítulo 2
Capítulo 1 Principios de la programación
Introducción a la programación en dBASE 17
en dBASE 5 Codificación manual frente a programación
Extensiones orientadas a objetos . . . . . . . . . . 5 visual . . . . . . . . . . . . . . . . . . . . . . . . 17
Objetos y clases . . . . . . . . . . . . . . . . . . . .5 Razones para el uso de programas
Ámbito de las variables de memoria . . . . . . .6 controlados por sucesos . . . . . . . . . . . . . 18
Bloques de código y punteros de función. . . . .6 Funcionamiento de los programas
Fichas . . . . . . . . . . . . . . . . . . . . . . . . . . 7 controlados por sucesos . . . . . . . . . . . . . 20
Ventanas de ficha . . . . . . . . . . . . . . . . . . .7 Desarrollo de programas controlados
Objetos del interface de usuario . . . . . . . . . .7 por sucesos . . . . . . . . . . . . . . . . . . . . . 22
Controladores de sucesos . . . . . . . . . . . . . .7
Utilidades de dos vías . . . . . . . . . . . . . . . .7 Capítulo 3
Sesiones . . . . . . . . . . . . . . . . . . . . . . . .8 Creación, compilación y
Entorno Windows . . . . . . . . . . . . . . . . . . 8
Controladores de impresora Windows . . . . . .8
comprobación de programas 23
Fuentes de Windows. . . . . . . . . . . . . . . . .8 Creación de un archivo de programa . . . . . . 23
Llamadas a DLL y API de Windows . . . . . . .9 Uso de convenciones estilísticas . . . . . . . . . 24
Multimedia: gráficos y sonido . . . . . . . . . . .9 Compilación de programas . . . . . . . . . . . . 26
DDE y OLE . . . . . . . . . . . . . . . . . . . . . .9 Comparación de versiones de los
Tablas . . . . . . . . . . . . . . . . . . . . . . . . . 10 archivos fuente y objeto . . . . . . . . . . . . . 28
El Database Engine de Borland (BDE). . . . . . 10 Creación de ejecutables. . . . . . . . . . . . . . . 28
Soporte SQL . . . . . . . . . . . . . . . . . . . . . 10 Comprobación de programas . . . . . . . . . . . 29
Fichas escalables . . . . . . . . . . . . . . . . . . 10 Generación de registros aleatorios . . . . . . . . 29
Integridad referencial . . . . . . . . . . . . . . . 11 Uso del análisis de cobertura . . . . . . . . . . . 30
Seguridad . . . . . . . . . . . . . . . . . . . . . . 11 Inicio del análisis de cobertura. . . . . . . . . . 30
Proceso de transacciones controladas Finalización del análisis de cobertura. . . . . . 31
por sucesos. . . . . . . . . . . . . . . . . . . . . 11
Creación frente a actualización de los
Tipos de campo especiales: binario y OLE . . . 11 archivos de cobertura . . . . . . . . . . . . . 32
Indicadores . . . . . . . . . . . . . . . . . . . . . 12 Bloques lógicos . . . . . . . . . . . . . . . . . . 32
Expresiones de campos memo . . . . . . . . . . 12 Visualización de la información del
Programación general . . . . . . . . . . . . . . . 12 archivo de cobertura. . . . . . . . . . . . . . . 33
Preprocesador . . . . . . . . . . . . . . . . . . . . 12
Depurador . . . . . . . . . . . . . . . . . . . . . . 12
Matrices versátiles . . . . . . . . . . . . . . . . . 13
Transmisión mejorada de parámetros. . . . . . 13
Análisis de cobertura. . . . . . . . . . . . . . . . 13
Generación de datos aleatorios para
comprobación . . . . . . . . . . . . . . . . . . . 14
Amplias capacidades. . . . . . . . . . . . . . . . 14
i
pg_dbw.toc Page ii Wednesday, August 30, 1995 1:56 PM
Capítulo 4 Capítulo 6
Uso de los procedimientos y Uso de los tipos de datos 67
bloques de código 35 Acerca de los tipos de datos . . . . . . . . . . . . 67
Acerca de los procedimientos y los bloques de Formato por defecto de los datos . . . . . . . . 69
código. . . . . . . . . . . . . . . . . . . . . . . . 36 Uso de los datos de carácter . . . . . . . . . . . . 70
Procedimientos frente a funciones . . . . . . . . 36 Comparación de cadenas de caracteres. . . . . 71
Declaración de procedimientos. . . . . . . . . . 37 Comparación fonética . . . . . . . . . . . . . . 71
Declaración de parámetros . . . . . . . . . . . . 37 Concatenación de cadenas de caracteres . . . . 72
Llamada de procedimientos con parámetros. . 39 Extracción de parte de una cadena
de caracteres . . . . . . . . . . . . . . . . . . . 73
Variación del número de parámetros . . . . . . 41
Modificación o determinación del uso de
Protección de los valores de las variables de mayúsculas y minúsculas. . . . . . . . . . . . 74
memoria . . . . . . . . . . . . . . . . . . . . . . 43 Eliminación de espacios. . . . . . . . . . . . . . 75
Uso de los archivos y bibliotecas de Repetición de caracteres . . . . . . . . . . . . . 75
procedimientos . . . . . . . . . . . . . . . . . . 44 Uso de los datos numéricos . . . . . . . . . . . . 76
Almacenamiento de procedimientos en los Especificación de valores globales de
archivos de programa . . . . . . . . . . . . . . 44 visualización de los números. . . . . . . . . . 77
Archivos de programa que contienen un solo Visualización de los números en las fichas. . . 78
procedimiento . . . . . . . . . . . . . . . . . 45
Archivos de programa que contienen varios
Realización de cálculos financieros . . . . . . . 79
procedimientos . . . . . . . . . . . . . . . . . 45 Realización de cálculos trigonométricos . . . . 79
Almacenamiento de procedimientos Truncado y redondeo de números . . . . . . . 80
en archivos de procedimiento. . . . . . . . . . 46 Uso de los datos de fecha . . . . . . . . . . . . . 81
Almacenamiento de procedimientos Formato y visualización de las fechas . . . . . 82
en archivos de biblioteca. . . . . . . . . . . . . 46 Uso de los datos de hora . . . . . . . . . . . . . . 83
Uso de los punteros de función y bloques de Uso de los datos lógicos . . . . . . . . . . . . . . 84
código. . . . . . . . . . . . . . . . . . . . . . . . 47 Uso de los tipos de datos nulos . . . . . . . . . . 85
Capítulo 5 Uso de los tipos de datos que no son
de dBASE . . . . . . . . . . . . . . . . . . . . . . 85
Uso de las variables de memoria 51 Conversión entre tipos de datos . . . . . . . . . 86
Acerca de las variables de memoria . . . . . . . 52
Nombres de las variables de memoria . . . . . 53 Capítulo 7
Declaración de las variables de memoria . . . . 54 Uso de las directivas de
Explicación de los ámbitos de las variables preprocesador 87
de memoria . . . . . . . . . . . . . . . . . . . . 54
Públicas . . . . . . . . . . . . . . . . . . . . . . 56 Acerca del preproceso . . . . . . . . . . . . . . . 88
Privadas . . . . . . . . . . . . . . . . . . . . . . 56 Definición de constantes . . . . . . . . . . . . . . 89
Locales . . . . . . . . . . . . . . . . . . . . . . . 57 Uso de literales como constantes . . . . . . . . 89
Estáticas . . . . . . . . . . . . . . . . . . . . . . 57 Uso de variables de memoria
Uso de las matrices . . . . . . . . . . . . . . . . . 60 como constantes . . . . . . . . . . . . . . . . . 89
Manipulación de las matrices y los Uso de identificadores para representar
valores que contienen . . . . . . . . . . . . . . 61 constantes . . . . . . . . . . . . . . . . . . . . . 90
Expansión de las variables de tipo carácter. . . 64 Expansión de expresiones . . . . . . . . . . . . . 91
Almacenamiento de las variables Transmisión de parámetros: identificadores
de memoria en archivos . . . . . . . . . . . . . 66 frente a procedimientos . . . . . . . . . . . . . 92
Compilación condicional. . . . . . . . . . . . . . 93
Compilación condicional para diferentes
versiones de dBASE . . . . . . . . . . . . . . . 94
Inserción de archivos include . . . . . . . . . . . 95
Definición de la opción de cobertura. . . . . . . 96
ii
pg_dbw.toc Page iii Wednesday, August 30, 1995 1:56 PM
iii
pg_dbw.toc Page iv Wednesday, August 30, 1995 1:56 PM
Parte II Capítulo 12
Objetos y clases 127 Diseño orientado a objetos 175
Cuándo utilizar el diseño orientado
Capítulo 9 a objetos . . . . . . . . . . . . . . . . . . . . . . 175
Introducción a la programación Transición del diseño procedural al
orientado a objetos . . . . . . . . . . . . . . . 176
orientada a objetos 129 Fundamentos procedurales . . . . . . . . . . .176
Breve recorrido por la orientación a objetos . 129 Problemas de ámbito de las variables de
Acerca de los objetos . . . . . . . . . . . . . . . 133 memoria . . . . . . . . . . . . . . . . . . . . . .177
Contenedores de objetos. . . . . . . . . . . . . 134 Problemas para lograr la reutilización . . . . .178
Acerca de las clases . . . . . . . . . . . . . . . . 136 Fases de diseño . . . . . . . . . . . . . . . . . . 179
Resumen de la orientación a objetos . . . . . . 138 Un ejemplo . . . . . . . . . . . . . . . . . . . . . 180
Cómo aprender más . . . . . . . . . . . . . . . 191
Capítulo 10
Uso de los objetos 139 Parte III
Creación de objetos . . . . . . . . . . . . . . . . 139 Fichas 193
Referencia a los miembros de un objeto. . . . 142
Uso del operador de punto . . . . . . . . . . . 143 Capítulo 13
Uso del operador de índice . . . . . . . . . . . 144 Creación de aplicaciones
Adición de propiedades y métodos con fichas 195
personalizados. . . . . . . . . . . . . . . . . . 145
Uso de las variables de referencia a objeto . . 146 Acerca de las fichas modales y no modales. . 195
Creación de objetos dentro de otros objetos . 148 Apertura de fichas modales y no modales . . 197
Referencia a objetos principales y Modalidad y ejecución de un programa. . . . 198
derivados. . . . . . . . . . . . . . . . . . . . . 149 Estrategias de programación . . . . . . . . . . 200
Creación de objetos personalizados . . . . . . 150 Interface modal. . . . . . . . . . . . . . . . . . .200
Transmisión de referencias a objeto Interface no modal. . . . . . . . . . . . . . . . .203
como valores Interface no modal orientado a objetos . . . . .206
devueltos y parámetros . . . . . . . . . . . . 151 Definición del comportamiento de la
Liberación de objetos . . . . . . . . . . . . . . . 152 tecla Intro . . . . . . . . . . . . . . . . . . . . . 209
Uso de las matrices como objetos . . . . . . . 153 Cómo aprender más . . . . . . . . . . . . . . . 209
Creación de matrices dispersas . . . . . . . . . 155
Creación de matrices asociativas . . . . . . . . 157 Capítulo 14
Escritura de controladores
Capítulo 11 de sucesos 211
Uso de las clases 159 Acerca de los controladores de sucesos . . . . 211
Declaración de clases . . . . . . . . . . . . . . . 159 Escritura de controladores de sucesos con el
Referencias a miembros en una Diseñador de fichas . . . . . . . . . . . . . . . 213
declaración de clase. . . . . . . . . . . . . . . 160 Averiguación de cuándo tienen lugar
Asociación de métodos a una clase . . . . . . 161 los sucesos . . . . . . . . . . . . . . . . . . . . 217
Declaración de los parámetros de una clase . 163
Protección de propiedades y métodos. . . . . 164
Escritura de código de inicialización y
salida de las fichas. . . . . . . . . . . . . . . . 219
Acerca de las jerarquías de clases . . . . . . . 166 Ejecución de sucesos al abrir una ficha . . . . .220
Declaración de una clase basada en Ejecución de sucesos al cerrar una ficha . . . .221
otra clase . . . . . . . . . . . . . . . . . . . . . 167 Ejecución de procedimientos . . . . . . . . . . 222
Anulación de los miembros heredados . . . . 168
Referencia a métodos desde una clase. . . . . 169
Transmisión de parámetros a las
superclases. . . . . . . . . . . . . . . . . . . . 172
Creación de una jerarquía de clases . . . . . . 173
iv
pg_dbw.toc Page v Wednesday, August 30, 1995 1:56 PM
v
pg_dbw.toc Page vi Wednesday, August 30, 1995 1:56 PM
vi
pg_dbw.toc Page vii Wednesday, August 30, 1995 1:56 PM
Capítulo 22 Capítulo 24
Uso de las transacciones 329 Uso de SQL 347
Descripción general del proceso de una Definición de SQL. . . . . . . . . . . . . . . . . 347
transacción . . . . . . . . . . . . . . . . . . . . 330 Terminología SQL . . . . . . . . . . . . . . . . .348
Creación de transacciones . . . . . . . . . . . . 330 Acceso a datos orientado a conjuntos y
Proceso de transacciones con tablas no procedimental . . . . . . . . . . . . . . . .349
de dBASE y Paradox . . . . . . . . . . . . . . 331 Transacciones en SQL . . . . . . . . . . . . . . .349
Uso de comandos y funciones de SQL incrustado y SQLExec( ) . . . . . . . . . . 350
dBASE en las transacciones . . . . . . . . . . 331 Sintaxis de SQL permitida . . . . . . . . . . . . 351
Uso de las transacciones en las fichas . . . . . 332 Añadidos, operadores y funciones . . . . . . .352
Definición de puntos de transacción. . . . . . 332 Variables de memoria . . . . . . . . . . . . . . .353
Uso de niveles de aislamiento en las Diagnosis de errores SQL . . . . . . . . . . . . 353
transacciones de servidor . . . . . . . . . . . 334 SQL incrustado y servidores SQL . . . . . . . 354
Requisitos previos . . . . . . . . . . . . . . . . .354
Capítulo 23 Uso de la sentencia SELECT de SQL . . . . . . 355
Uso de tablas que no son Sintaxis de SELECT . . . . . . . . . . . . . . . .355
de dBASE 335 Consultas simples . . . . . . . . . . . . . . . . .355
Selección de todas las columnas . . . . . . . . .356
Diferencias en las tablas de Paradox y SQL. . 336
SELECT con DISTINCT. . . . . . . . . . . . . .356
Apertura de una base de datos . . . . . . . . . 336 Cláusula WHERE . . . . . . . . . . . . . . . . .357
Especificación del tipo de tabla . . . . . . . . . 337 Uso de los operadores de comparación . . . .358
Delimitación de los nombres de campo. . . . 337 Combinación de condiciones. . . . . . . . . . .359
Uso de indicadores para identificar Definición y uso de las expresiones . . . . . . .361
registros. . . . . . . . . . . . . . . . . . . . . . 338 Expresiones en la cláusula SELECT . . . . . .362
Inserción de registros. . . . . . . . . . . . . . . 339 Expresiones en la cláusula WHERE . . . . . .363
Borrado de registros . . . . . . . . . . . . . . . 339 Funciones agregadas en las expresiones . . .363
Expresiones agregadas en las cláusulas
Validación de datos. . . . . . . . . . . . . . . . 340 SELECT . . . . . . . . . . . . . . . . . . . . .364
Uso de las transacciones . . . . . . . . . . . . . 340 Expresiones agregadas cualificadas por
Uso de los índices . . . . . . . . . . . . . . . . . 342 una cláusula WHERE . . . . . . . . . . . . .365
Diferencias en las claves de índice . . . . . . . 343 SELECT con predicados BETWEEN,
IN y LIKE . . . . . . . . . . . . . . . . . . . .365
Diferencias en seguridad . . . . . . . . . . . . 344
Ordenación del resultado . . . . . . . . . . . .365
Ejecución de sentencias SQL . . . . . . . . . . 344 Ordenación por una sola columna . . . . .365
Resumen del soporte de tablas de Paradox Ordenación por más de una columna . . .366
y SQL . . . . . . . . . . . . . . . . . . . . . . . 345 ORDER BY con una cláusula WHERE . . .367
Agrupamiento de filas . . . . . . . . . . . . . .368
Cláusula GROUP BY . . . . . . . . . . . . .368
Cláusula HAVING . . . . . . . . . . . . . .369
Cláusula UNION . . . . . . . . . . . . . . . . .370
Uso de los procedimientos almacenados . . . 371
Requisitos previos . . . . . . . . . . . . . . . . .371
Sintaxis de declaración . . . . . . . . . . . . . .372
Sintaxis de ejecución. . . . . . . . . . . . . . . .372
Ejemplos. . . . . . . . . . . . . . . . . . . . . . .372
Declaración automática de procedimientos
almacenados . . . . . . . . . . . . . . . . . . .373
Limitaciones . . . . . . . . . . . . . . . . . . . .374
vii
pg_dbw.toc Page viii Wednesday, August 30, 1995 1:56 PM
Parte V Capítulo 26
Entorno Windows 375 Uso de las DLL y del API
de Windows 393
Capítulo 25 Acerca de las bibliotecas y los vínculos . . . . 393
Impresión 377 Uso de las DLL con dBASE . . . . . . . . . . . 395
Acerca de la impresión. . . . . . . . . . . . . . 377 Llamada de funciones DLL . . . . . . . . . . . 395
Nuevas características de impresión de Creación de prototipos y conversión de
Visual dBASE . . . . . . . . . . . . . . . . . . 378 los tipos de datos. . . . . . . . . . . . . . . . .396
Especificación de los controladores Ejemplos de llamada de funciones DLL . . . .397
de impresora. . . . . . . . . . . . . . . . . . . 378 Carga y liberación de las DLL . . . . . . . . . .399
Determinación del nombre de un Llamada de las funciones del API de
controlador de impresora . . . . . . . . . . . 379 Windows . . . . . . . . . . . . . . . . . . . . . 400
Salida direccionable y direccionada . . . . . . 379 Uso de las constantes del API
Dirección de la salida. . . . . . . . . . . . . . . 380 de Windows . . . . . . . . . . . . . . . . . . .401
Dirección de la salida direccionable . . . . . . 380 Gestión a nivel de bits de los parámetros
Dirección de la salida direccionada . . . . . . 381 y los valores devueltos . . . . . . . . . . . . .401
Averiguación del estado de la impresora . . . 382
Impresión de la salida en un archivo . . . . . 382 Capítulo 27
Posición de los caracteres de salida . . . . . . 383 Expansión de dBASE mediante
Impresión de la salida con coordenadas
absolutas . . . . . . . . . . . . . . . . . . . . . 383
DDE/OLE 403
Impresión de la salida con coordenadas Acerca de DDE . . . . . . . . . . . . . . . . . . 403
relativas . . . . . . . . . . . . . . . . . . . . . 383 Creación de aplicaciones cliente . . . . . . . . 404
Uso de coordenadas fraccionarias . . . . . . . 384 Establecimiento y terminación de un
Definición de la posición vertical y vínculo DDE . . . . . . . . . . . . . . . . . . .405
horizontal de la impresora . . . . . . . . . . 384 Intercambio de datos con el servidor . . . . . .405
Gestión de números de línea, saltos de Desplazamiento por regiones . . . . . . . . . .406
página y número de copias . . . . . . . . . . 385 Envío de comandos al servidor . . . . . . . . .407
Formato de la salida impresa . . . . . . . . . . 386 Creación de vínculos dinámicos . . . . . . . . .408
Ajuste de la longitud de la página . . . . . . . 386 Creación de aplicaciones servidor . . . . . . . 409
Especificación del modo apaisado Arranque de Visual dBASE desde una
o vertical . . . . . . . . . . . . . . . . . . . . . 387 aplicación cliente . . . . . . . . . . . . . . . . .410
Selección de las opciones de impresión Escritura de rutinas de controlador de
por parte del usuario . . . . . . . . . . . . . . 387 inicialización . . . . . . . . . . . . . . . . . . .411
Especificación de márgenes y sangrado. . . . 387 Acerca de OLE. . . . . . . . . . . . . . . . . . . 413
Especificación de la alineación horizontal . . 388 Uso de la automatización OLE. . . . . . . . . .414
Ajuste del interlineado y posiciones de
tabulación . . . . . . . . . . . . . . . . . . . . 388
Avances de hoja y paginación . . . . . . . . . 388
Avances de hoja y avances de línea . . . . . . 388
Números de página y rangos de página . . . 389
Modo de calidad y modo de borrador. . . . . 389
Especificación de las fuentes y estilos
de texto . . . . . . . . . . . . . . . . . . . . . . 389
Uso de las fuentes de Windows con
Visual dBASE . . . . . . . . . . . . . . . . . . 390
Uso de una fuente . . . . . . . . . . . . . . . . 390
Estilos de texto . . . . . . . . . . . . . . . . . . 391
Justificación de las cadenas de texto . . . . . . 392
Especificación del ancho de línea con
ajuste vertical . . . . . . . . . . . . . . . . . . 392
Especificación de la alineación horizontal
con ajuste vertical . . . . . . . . . . . . . . . . 392
viii
pg_dbw.toc Page ix Wednesday, August 30, 1995 1:56 PM
Parte VI Apéndice C
Apéndices 417 Uso de los juegos de caracteres y
controladores de idioma 443
Apéndice A Acerca de los juegos de caracteres . . . . . . . 444
Ejecución de aplicaciones Acerca de los controladores de idioma . . . . 446
de dBASE para DOS 419 Coincidencias exactas e inexactas. . . . . . . . 448
Escritorio de Visual dBASE y Uso de controladores de idioma globales . . . 449
aplicaciones DOS . . . . . . . . . . . . . . . . 420 Uso de controladores de idioma de tablas . . 450
Pasos básicos. . . . . . . . . . . . . . . . . . . . 421 Identificación del controlador de idioma
y página de códigos de una tabla . . . . . . .451
Tipos de archivos permitidos . . . . . . . . . . 421
Uso de los controladores de idioma de
Entorno de configuración de Windows . . . . 422 la tabla frente a los globales . . . . . . . . . .452
DBASEWIN.INI. . . . . . . . . . . . . . . . . . 422 Incompatibilidades de caracteres en los
Referencias a controladores de impresora . . 422 nombres de campo . . . . . . . . . . . . . . . 453
Formatos por defecto de los datos . . . . . . . 423
Conflictos con las pulsaciones de Windows . 424 Indice 455
Mejoras en el lenguaje . . . . . . . . . . . . . . 424
Evitar conflictos de funciones. . . . . . . . . . 425
Cambios específicos del lenguaje. . . . . . . . 425
Diferencias en los códigos de error. . . . . . . 425
Apéndice B
Mejora de las aplicaciones de
dBASE para DOS 427
El Generador de componentes . . . . . . . . . 428
Estrategias de mejora. . . . . . . . . . . . . . . 428
Programa de dBASE IV de ejemplo . . . . . . 429
Programa de dBASE IV de ejemplo
mejorado . . . . . . . . . . . . . . . . . . . . . 431
Explicación de las diferencias en el código . . 434
Inicialización . . . . . . . . . . . . . . . . . . . 434
Creación de la ventana. . . . . . . . . . . . . . 435
SAY/GET y objetos de datos . . . . . . . . . . 436
Variables de memoria . . . . . . . . . . . . . . 438
Procedimientos y funciones. . . . . . . . . . . 438
Transición a los menús de Visual dBASE . . . 440
Mejoras adicionales. . . . . . . . . . . . . . . . 442
ix
pg_dbw.toc Page x Wednesday, August 30, 1995 1:56 PM