Centro de Ingeniería y Desarrollo Industrial
Curso de LabWin do ws /CVI /CVI 9.0 9.0
Cé sar A rm and o Cr uz Men do za CVI-01-2010 1
Introducción
.............................................................................................................................................................4
¿Qué es LabWindows/CVI? ..................................................................................................................................4 Entorno de desarrollo ...........................................................................................................................................4 Mi primer programa .................................................................................................................................................5 Atributos importantes de un panel ......................................................................................................................6 Generando código de archivo UIR ........................................................................................................................8 Analizando el código generado ......................................................................................................................... 11 Agregando un botón para desplegar un mensaje ........................ ................................. .................. .................. .................. ................... ................... .................. .............. ..... 13 Eventos posibles para paneles y controles ............. ....................... ................... .................. .................. .................. ................... ................... .................. .................. ................. ........ 16 Práctica manejando eventos ............................................................................................................................. 17 Manejo de datos en pantalla ................................................................................................................................. 17 Leer y asignar información en un panel ............................................................................................................ 17 Práctica modificando el estado de un led ......................................................................................................... 17 Práctica de operación con dos números .......................... ................................... .................. .................. .................. ................... ................... .................. .................. ................. ........ 18 Práctica para actualizar controles usando eventos ................ ......................... .................. .................. .................. .................. ................... ................... .................. ........... .. 20 Manejo de Timers .................................................................................................................................................. 21 Timer Síncrono y Asíncrono ............................................................................................................................... 21 Consideraciones para un timer síncrono ........................................................................................................... 22 Ejercicio utilizando timer síncrono .................................................................................................................... 23 Funciones para controles de tipo Timer ............................................................................................................ 23 Ejercicio utilizando timer síncrono y control graph................. graph.......................... ................... ................... .................. .................. .................. .................. .................. ........... 24 Funcionamient Funcio namiento: o:................................. ................ ................................... ................................... ................................... ................................... .................................. ................................... ........................ ...... 24 Timer Asíncrono ................................................................................................................................................ 28 Funciones para el manejo de un Timer Asíncrono .............. ....................... .................. .................. .................. .................. ................... ................... .................. .............. ..... 28 Ejercicio utilizando un timer asíncrono ............................................................................................................. 30 Manejo de ActiveX ................................................................................................................................................. 31 ¿Cómo se registra un ActiveX en Windows? ................. .......................... .................. ................... ................... .................. .................. .................. .................. ................ ....... 31
2
Introducción
.............................................................................................................................................................4
¿Qué es LabWindows/CVI? ..................................................................................................................................4 Entorno de desarrollo ...........................................................................................................................................4 Mi primer programa .................................................................................................................................................5 Atributos importantes de un panel ......................................................................................................................6 Generando código de archivo UIR ........................................................................................................................8 Analizando el código generado ......................................................................................................................... 11 Agregando un botón para desplegar un mensaje ........................ ................................. .................. .................. .................. ................... ................... .................. .............. ..... 13 Eventos posibles para paneles y controles ............. ....................... ................... .................. .................. .................. ................... ................... .................. .................. ................. ........ 16 Práctica manejando eventos ............................................................................................................................. 17 Manejo de datos en pantalla ................................................................................................................................. 17 Leer y asignar información en un panel ............................................................................................................ 17 Práctica modificando el estado de un led ......................................................................................................... 17 Práctica de operación con dos números .......................... ................................... .................. .................. .................. ................... ................... .................. .................. ................. ........ 18 Práctica para actualizar controles usando eventos ................ ......................... .................. .................. .................. .................. ................... ................... .................. ........... .. 20 Manejo de Timers .................................................................................................................................................. 21 Timer Síncrono y Asíncrono ............................................................................................................................... 21 Consideraciones para un timer síncrono ........................................................................................................... 22 Ejercicio utilizando timer síncrono .................................................................................................................... 23 Funciones para controles de tipo Timer ............................................................................................................ 23 Ejercicio utilizando timer síncrono y control graph................. graph.......................... ................... ................... .................. .................. .................. .................. .................. ........... 24 Funcionamient Funcio namiento: o:................................. ................ ................................... ................................... ................................... ................................... .................................. ................................... ........................ ...... 24 Timer Asíncrono ................................................................................................................................................ 28 Funciones para el manejo de un Timer Asíncrono .............. ....................... .................. .................. .................. .................. ................... ................... .................. .............. ..... 28 Ejercicio utilizando un timer asíncrono ............................................................................................................. 30 Manejo de ActiveX ................................................................................................................................................. 31 ¿Cómo se registra un ActiveX en Windows? ................. .......................... .................. ................... ................... .................. .................. .................. .................. ................ ....... 31
2
¿Puedo eliminar un ActiveX registrado? ....................................................................................................... 31 Insertando y habilitando un A ctiveX en e n nuestro panel UIR ................... ............................ .................. .................. .................. .................. .................. ........... 31 ¿Qué cambios hay en nuestro proyecto? ...................................................................................................... 35 Ejercicio utilizando el ActiveX de Calendario de Windows ......................... .................................. ................... ................... .................. .................. ................. ........ 36 Ejercicio utilizando el ActiveX de Adobe Reader ................. .......................... .................. .................. .................. .................. ................... ................... .................. .............. ..... 44 Manejo de bases de datos ..................................................................................................................................... 46 Conceptos de base de datos .......................................................................................................................... 46 Structured Query Language (SQL) ................................................................................................................. 47 Ejercicios con código SQL .............................................................................................................................. 48 LabWindows/CVI Toolkit SQL ........................................................................................................................ 57 Adminstrador ODBC ...................................................................................................................................... 57 LabWindows y bases de datos ....................................................................................................................... 59 Ejercicio para leer el contenido de la tabla Frecuentan ............ ..................... .................. .................. .................. .................. ................... ................... ................. ........ 68 Ejercicio para insertar información a la tabla Frecuentan .......................... ................................... ................... ................... .................. .................. ................. ........ 71 Ejercicio para eliminar información a la tabla Frecuentan.................. ............................ ................... .................. .................. .................. .................. ................ ....... 72 72 Apuntes finales sobre SQL ................................................................................................................................. 72
3
Introducción ¿Qué es LabWindows/CVI? LabWindows/CVI es un completo ambiente de desarrollo ANSI C para la creación de aplicaciones de instrumentación virtual. LabWindows/CVI viene con librerías para adquisición, análisis y visualización, una interface simplificada de edición para usuario con arrastre y colocación de elementos y herramientas automatizadas de generación de código con las cuales se puede probar dicho código interactivamente entes de adicionarlo a un proyecto. Con LabWindows/CVI, se pueden crear interfaces localizadas de usuario, crear y trabajar con componentes ActiveX y desarrollar aplicaciones multihilos.
Entorno de desarrollo La interfaz del entorno de desarrollo, es muy similar a otros IDE como Visual Studio, Eclipse, etc.
1
3
2
1.- Panel de proyectos. En esta parte se organizan los archivos (*.c, *.h, *.uir, *.prj) que integran el o los proyectos. En este mismo espacio se pueden insertar archivos que no formen parte del proyecto, como pueden ser archivos *.txt, archivos de base de datos, etc. Este tipo de archivos no afectan el proceso de compilación o ejecución de un proyecto. 2.- Panel de librerías. En este espacio CVI coloca la descripción del contenido de las diferentes librerías que se encuentran integradas al proyecto activo.
4
3.- Espacio para usos múltiples. Se utiliza como editor de código C, editor de la interfaz gráfica, editor de paneles de funciones, visualización de contenido de variables, memoria, etc.
Mi primer programa Una vez iniciada la sesión con LabWindows/CVI, se procederá a guardar el proyecto que vamos a crear, el nombre propuesto es Ejercicio01.
Ahora crearemos un nuevo documento de tipo UIR para crear nuestro panel de interfaz de usuario.
5
Por default, LabWindows inserta un panel en blanco en el nuevo archivo UIR que acabamos de crear. Para editar las propiedades del panel, pulsaremos doble clic izquierdo sobre el panel. En el panel de propiedades, modificaremos el título de la ventana con la siguiente leyenda “Mi primer programa”.
Atributos importantes de un panel Todo panel que se crea en un archivo UIR, se identifica por un atributo denominado Constant Name. Labwindows siempre propondrá un nombre de constante para cada panel que insertemos en un archivo UIR. Se recomienda que el nombre a utilizar en este atributo, se escriba en mayúsculas y no puede contener espacios en blanco. Esto sigue las mismas reglas utilizadas en un compilador de C para la sentencia #define. En un proyecto de CVI que utilice uno o varios archivos UIR, no se puede repetir el nombre de una constante que identifique a un panel. 6
Otro parámetro importante dentro de los atributos de un panel, es el Callback Function. Como veremos más adelante al analizar el código en CVI, LabWindows trabaja en base a eventos. Lo anterior significa que desde el archivo UIR, se estará indicando qué bloques de código se deberán ejecutar en los archivos de código fuente C. El cuándo y qué bloque de código se debe ejecutar, se configurará más adelante al especificar lo que se conoce como tipo de evento. Por el momento es importante saber que a través del archivo UIR, nosotros como desarrolladores podemos conocer las acciones que esté realizando el usuario como por ejemplo dónde pulsó clic izquierdo, dónde se encuentra el cursor de su mouse posicionado, dónde ha modificado información, etc. Retomando el parámetro Callback Function, para el caso de nuestro panel que estamos configurando, deseamos poder capturar el evento que corresponda a la acción de cerrar la ventana de nuestra aplicación que estamos creando. Para lograr lo anterior, es necesario especificar un nombre de función. Esta función no existe aún, pero se creará más adelante. Sobre las reglas para especificar el nombre de una función, serán las que se tengan definidas en el estándar de programación que se esté utilizando. Por mencionar alguna, se utilizarán letras minúsculas con excepción de la primera letra del nombre de la función. La configuración final que debemos tener para nuestro ejercicio es la siguiente:
Una vez que hemos configurado nuestro primer panel, procederemos a guardar nuestro archivo UIR. El nombre propuesto es Interfaz01.
7
Generando código de archivo UIR Ahora que hemos configurado nuestro primer panel, procederemos a generar el código para su ejecución. Para ello ejecutaremos la siguiente opción del menú principal:
Como en este momento no disponemos de ningún archivo de código fuente C, el generador de código nos preguntará en dónde deseamos depositar el código que estamos por crear. Por ahora le indicaremos que deseamos hacerlo en una nueva ventana. Posteriormente nos mostrará la siguiente ventana de configuración.
8
A esta ventana le haremos algunos ajustes para obtener lo siguiente:
El primer cambio es para que el archivo destino con el código fuente, sea insertado en nuestro proyecto activo. El segundo, es indicar el nombre de una variable (veremos más adelante que será de tipo entero) que nos servirá a nivel de código, para identificar a este panel en particular. Esta variable será utilizada para acciones como el desplegar el panel u ocultarlo.
9
El último se refiere a indicar cuál función callback de las existentes en nuestro archivo UIR, servirá para poder cerrar nuestra aplicación. Como en este momento solo hemos especificado una función (Terminar), seleccionaremos la misma para finalizar la aplicación. Al aceptar estos ajustes, deberemos observar una imagen como la siguiente:
Podemos observar que en el panel de proyectos tenemos un proyecto de nombre Ejercicio01, que contiene dos carpetas, una con el archivo UIR Interfaz01.uir y una con el código fuente recién generado Interfaz01.c. En este momento nuestro proyecto ya puede ser ejecutado y ejecutará la única acción que tiene definida, cerrar la aplicación. Bastará con pulsar en el siguiente botón:
LabWindows compilará el código C existente y mostrará la siguiente pantalla:
10
Nuestra aplicación solo se limita por ahora a mostrar un panel y responder a la acción de cerrar. Las funciones de minimizar y maximizar se encuentran implícitas en todo panel creado y no requieren de una función callback para ejecutarse.
Analizando el código generado El código que hasta ahora hemos generado es el siguiente:
2 1
3
4
1. En esta parte se concentran todas las librerías de tipo .h que son necesarias para poder compilar exitosamente cada una de las funciones incluidas en el código fuente. Por lo general LabWindows nos recomendará las librerías que son necesarias incluir cuando alguna función sea desconocida. Entre estos archivos podemos ver que existe uno con el mismo nombre de nuestro archivo UIR. Esto se debe a que todo archivo UIR que generemos, siempre se encontrará acompañado por su respectivo archivo .h 11
2. Después de la sección de los archivos de cabecera, se colocará la definición de las variables globales a utilizar en el programa. ¿Recuerdas el nombre de variable que modificamos aquí?
Esta variable fue declarada en esta sección.
3. Como todo programa en C, siempre debe existir una función main. Normalmente en esta función, se destina para ejecutar una función llamada LoadPanel. La finalidad de esta función es el cargar en memoria el panel o los paneles que hemos creado en nuestro archivo UIR. Esta función recibe tres parámetros: - El primero por el momento lo usaremos con el valor de cero - El segundo es el nombre del archivo UIR en donde se encuentra el panel que deseamos cargar en memoria - El tercero corresponde a la constante que identifica a nuestro panel. Esta función retorna un valor de tipo entero, que no es otra cosa más que la referencia del panel que se ha cargado en memoria. Esta referencia sería el valor que utilizaremos en todo nuestro código para ejecutar acciones sobre un panel. Importante: El valor que retorna la función LoadPanel, no es el mismo que se encuentra asociado a la constante del panel. Son valores distintos.
4. En esta sección encontramos nuestra función callback que definimos desde nuestro archivo UIR. LabWindows por default genera una función callback en donde inserta una estructura de control tipo switch. La finalidad de una estructura switch es el poder manejar diferentes eventos que se puedan generar desde el panel o control al que se encuentra asociada la función callback.
12
Se puede observar que en cada case de la estructura switch se encuentran unas constantes (asumimos esto porque se encuentran escritas en mayúsculas), que sirven para identificar los eventos que podemos capturar con esta función callback desde el panel que la contiene.
El caso que nos interesa analizar por este momento, es que corresponde al EVENT_CLOSE. Este evento se asocia a la acción de pulsar clic izquierdo sobre la X de la ventana, indicando que se desea cerrar la ventana. Una vez que estamos listos para capturar el evento que nos interesa, solo resta escribir al interior del case, las acciones que deseamos sean ejecutadas cuando se cumpla esa condición. Para el ejercicio actual, LabWindows ha escrito la función QuitUserInterface que significa se debe detener toda captura de eventos para salir de nuestro programa. La función QuitUserInterface cancela a la función RunUserInterface que se ejecutó en la función main.
Agregando un botón para desplegar un mensaje Vamos a modificar nuestro proyecto para adicionar un botón que nos permita desplegar un mensaje en pantalla mediante la función MessagePopup.
13
Ajustaremos las propiedades del botón para que tenga el siguiente aspecto:
A este botón se asociaremos una función callback que se llamará: DespliegaMensaje. Para crear la función asociada a este botón, pulsaremos clic derecho sobre el botón como se muestra a continuación:
El código de esta función ha sido generado en el archivo de código fuente que tenemos en nuestro proyecto. Cuanto tengamos varios archivos .c, LabWindows nos preguntará en cuál de ellos deseamos depositar el código a generar. Ahora nuestro editor de código se muestra como sigue:
14
En nuestra nueva función, complementaremos con código en el caso para el evento EVENT_COMMIT. Insertaremos la siguiente línea de código: MessagePopup(“Mensaje de prueba”,” Hola mundo”);
Volvemos a ejecutar nuestra aplicación y al pulsar clic izquierdo sobre el botón “Mostrar mensaje”, deberemos observar algo como lo siguiente:
15
Eventos posibles para paneles y controles Los eventos que podemos configurar para los paneles son los siguientes:
Para los controles los eventos disponibles son:
16
Práctica manejando eventos Modifique la función callback DespliegaMensaje para que despliegue el mensaje ante un clic derecho y para un doble clic izquiero.
Manejo de datos en pantalla Leer y asignar información en un panel LabWindows proporciona dos funciones para el proceso de lectura y asignación de datos a controles: - GetCtrlVal - SetCtrlVal Ambas funciones requieren tres parámetros: - Referencia del panel donde se encuentra el control a leer o asignar el dato - Constante que identifica al control. Así como un panel se encuentra identificado por un nombre de constante, un control se identifica de igual manera con el nombre de una constante. Para efecto de utilizarse en esta función, el identificador del control se compone por el nombre de la constante del panel más el nombre de la constante del control separados por un guion bajo (_). Por ejemplo, para el ejercicio actual, nuestra constante de panel es VENTANA01 y si la constante del control fuera BOTON01, el identificador que espera la función GetCtrlVal o SetCtrlVal es VENTANA01_BOTON01. - El tercer parámetro es según la función: o GetCtrlVal. La dirección de memoria donde se va a depositar el dato a leer. o SetCtrlVal. El valor o la variable que contiene el dato a ser asignado al control en pantalla.
Práctica modificando el estado de un led Vamos a agregar a nuestro proyecto un control de tipo led que responda al evento de doble clic izquierdo para encender y apagar el mismo. Inserte en el panel un led (redondo o cuadrado), defina el nombre de la constante como LED y asigne una función callback de nombre CambiaEstado. Genere el código de la función en el archivo de código fuente del proyecto activo. En la estructura switch de la función creada, modifique el evento EVENT_COMMIT para que la función responda a la acción de doble clic izquierdo. Agregue las líneas de código faltantes hasta quedar como se indica a continuación:
17
Ejecuta la aplicación y valida su funcionamiento pulsando doble clic sobre el control led.
Práctica de operación con dos números Modifique el proyecto actual para lograr una interfaz de usuario como la siguiente:
Dados dos números (primera y segunda cantidad), al pulsar clic sobre el botón Multiplicar, se colocará el resultado del producto en el control etiquetado como Resultado.
18
El código fuente de la solución es:
19
Práctica para actualizar controles usando eventos Inserte en el panel de proyecto actual dos nuevos controles numéricos como se muestra en la siguiente imagen:
El funcionamiento de este ejercicio consiste en capturar a través del control etiquetado como “Perilla de nivel”, las variaciones que se hacen con el mouse en su valor y reflejarlo simultáneamente (sin soltar el mouse) en el control etiquetado como “Depósito”.
20
Manejo de Timers Timer Síncrono y Asíncrono LabWindows ofrece dos tipos de controles que ayudan en el proceso de ejecución automática de funciones mediante la programación de eventos en base a tiempo. El primero de ellos es el Timer Síncrono, mismo que se pude insertar desde el editor de UIR como un control. Este tipo de control tiene las mismas propiedades generales que hemos visto hasta ahora, es decir, se identifica con un Constant Name y se le asocia un nombre de función callback, misma que se ejecutará automáticamente a intervalos de tiempo predefinidos. Un parámetro específico para este tipo de control, es el que permite la configuración del intervalo de tiempo de ejecución. Otro parámetro que resulta de gran utilidad al momento de trabajar con este tipo de control, es el de habilitación. Este parámetro si se encuentra activo indicará que desde el momento en que nuestro proyecto es ejecutado, el timer comenzará a ejecutar la función asociada una vez transcurrido el intervalo de tiempo especificado. En caso contrario, si se encuentra deshabilitado será tarea del programador mediante instrucción de código, habilitar el timer cuando lo considere apropiado. Una de las principales ventajas de este tipo de timer es su sencillez en el proceso de implementación, ya que se sigue el mismo proceso que hasta ahora hemos visto para insertar un control y generar su función callback asociada desde el editor UIR.
21
La estructura de la función callback que nos genera un timer de este tipo es la siguiente:
Podemos observar que la única diferencia es el tipo de evento que nos maneja la estructura de control switch, ahora se trata de un EVENT_TIMER_TICK.
Consideraciones para un timer síncrono Mencionábamos al inicio del curso que LabWindows trabaja en base a eventos y que su manejador es la función que se ejecuta al inicio en el main de nuestros programas llamada RunUserInterface. Este manejador organiza los eventos que se reciben en una fila, mismos que se van atendiendo en el orden de llegada. Este modo de administración puede generar que un timer que se haya configurado a un intervalo de tiempo por ejemplo de 5ms, no sea determinístico. ¿Por qué?. Porque al que al tratarse de un evento que se atiende junto con el resto de los posibles eventos que se generan en la interface de usuario (movimiento mouse, clics, modificaciones de datos, etc) más los que administra Windows por su propia cuenta, existan fluctuaciones entre el tiempo que realmente ha transcurrido entre cada evento del timer. Así mismo, al querer manejar procesos con este tipo de timer a tiempos muy cortos de ejecución (milisegundos), genera que nuestro procesador se sature y se destine un alto porcentaje de tiempo de procesador a ello. Se recomienda utilizar este tipo de control para procesos que no son críticos. Un aspecto a cuidar también es la relación del intervalo de tiempo de ejecución del timer contra el tiempo que se tardará en ejecutar las líneas de código que se incluyen en la función callback. 22
Cuando se inserta un timer en un panel dentro del editor UIR, observaremos un icono como este No debemos preocuparnos mucho por su ubicación en nuestro panel que se esté diseñando, ya que en tiempo de ejecución el icono no es visible para el usuario. Un último dato importante sobre este tipo de timer síncrono es la resolución de tiempo,
Ejercicio utilizando timer síncrono Comenzaremos diseñando una aplicación que en pantalla incremente el valor de un control en uno de forma automática cada segundo a partir de que se ejecuta la aplicación.
Funciones para controles de tipo Timer En la mayoría de las aplicaciones a desarrollar, necesitaremos tomar el control del timer para indicarle en qué momento iniciar o parar. Para ello LabWindows nos ofrece las siguientes funciones: - SuspendTimerCallbacks (); - ResumeTimerCallbacks (); Estas funciones afectan a TODOS los timers que tengamos corriendo en nuestra aplicación. Existe una tercera función que se llama SetCtrlAttribute. Esta función no es exclusiva para el control de tipo Timer, al contrario, aplica para todos los controles que depositamos en un panel. ¿Qué nos permite hacer?. Prácticamente modificar todo lo que deseemos de un control. Todos los atributos que modificamos de un control desde el panel en el editor de UIR, con esta función lo podemos hacer desde código. En el siguiente ejercicio la pondremos en práctica.
23
Ejercicio utilizando timer síncrono y control graph Diseñaremos una interfaz de usuario como la siguiente:
Funcionamiento: Cuando se pulse clic sobre el botón “ Iniciar gráfica”, gráfica”, utilizando el valor de intervalo de tiempo configurado y el número de datos a generar, se estará construyendo con números aleatorios, un vector con la cantidad de números especificada en la pantalla. Este vector de datos se estará dibujando en la gráfica cada t segundos, según se haya igualmente configurado en la pantalla.
La gráfica estará de forma continua hasta que se pulse en el botón “ Pausar gráfica” gráfica” o se cierre la aplicación. En caso de pausar el proceso, se reanudará con “Iniciar “ Iniciar Gráfica”. Gráfica”. Finalmente, mientras la aplicación se encuentra graficando datos automáticamente, podremos variar el tiempo de graficado y la cantidad de datos, simplemente modificando los valores de los controles respectivos. 24
Nuestro panel lo configuraremos como sigue:
Constant Name Callback Function Label
INTERVALO CambiarIntervalo CambiarInterval o Intervalo de tiempo (segundos)
Constant Name Callback Function Label
DATOS CambiaCantidadDatos Cantidad de datos a generar:
Constant Name Callback Function Label
COMMANDBUTTON Graficar Iniciar gráfica
Constant Name Callback Function Label
COMMANDBUTTON_2 Pausar Pausar gráfica
Constant Name Callback Function Label Enable
TIMER GraficarVector 0.500 No
Constant Name Callback Function Points per Screen Scroll Mode
MIGRAFICA 10000 Continuos 25
Panel Constant Name Callback Function Panel Title
PANEL Salir Utilizando gráficas
timer
síncrono
y
Una vez que se tenga configurado nuestro UIR, generamos todo el código para comenzar a complementarlo. Para poner en marcha nuestra aplicación, se requiere pulsar sobre el botón “ Iniciar gráfica”, por lo que este botón deberá establecer las condiciones iniciales de nuestra aplicación. - Leer y configurar el intervalo de tiempo que se ha configurado en la pantalla - Leer el número de datos que se deben de generar - Poner en marcha el timer
Se recomienda que las variables donde se almacene el intervalo de tiempo y la cantidad de datos, sean globales, ya que serán utilizadas por varias funciones de nuestra aplicación. ¿Cómo configurar el timer?. Utilizamos la función SetCtrlAttribute en donde sus parámetros son: - Variable con la referencia del panel - Identificador del control que queremos modificar, en este caso el del timer - El tipo de atributo que queremos modificar: o ATTR_INTERVAL: Para modificar el intervalo de tiempo (tipo doble) o ATTR_ENABLE: Para habilitar el timer (tipo entero) - El valor del parámetro con el tipo de dato que según aplique Ahora, programaremos la función del botón “Pausar gráfica”, en el paso anterior vimos como se pone en marcha el timer, ¿cómo podríamos indicar que no esté habilitado?. Listo!! Ya tenemos nuestra función para pausar nuestro proceso de graficado. Ahora hagamos que nuestra aplicación responda a las modificaciones del tiempo y cantidad de datos mientras se grafica. Se generaron dos funciones callback asociadas a los controles que tiene esta información, por lo que en cada función solamente habrá que incluir el código para que actualicen sus variables respectivas. Finalmente programemos las acciones del timer. Ahí debemos construir un arreglo de datos dobles y llenarlo con datos aleatorios. Podemos utilizar la función Random(). Posteriormente hay que dibujarlo en pantalla con la instrucción PlotStripChart(). Hemos terminado.
26
27
Timer Asíncrono El segundo tipo de timer que nos permite implementar LabWindows, es el denominado asíncrono. Una de las principales características de este control, es que la llamada de su función callback se ejecuta en su propio hilo. Esto es, la administración de los eventos generados por un timer asíncrono no corre a cargo de la función RunUserInterface. Esta característica hace que este tipo de timers sean ideales para tareas de adquisición de datos, en donde se requiere un mayor nivel de determinismo en su tiempo de ejecución. La cantidad de timers asíncronos que se pueden crear en un sistema basado en Windows es de 16, en sistemas de tiempo real la cantidad es de 128 y en sistemas Linux hasta 256. En cuanto a la resolución mínima de tiempo que se puede implementar en un timer asíncrono, a diferencia de la limitante de 1ms para el timer síncrono, en este caso se puede alcanzar una resolución de hasta 1us. Para conocer la resolución mínima soportada por el sistema operativo donde se va a ejecutar, la función GetAsyncTimerResolution proporciona este dato. Al utilizar este tipo de timers, se debe tener especial cuidado con las variables que sean comunes entre timers. Esto es, ya que al tratarse de ejecuciones en hilos separados, el contenido de las variables no se encuentra protegido y un mal manejo podría generar inconsistencias en el contenido de las variables. Finalmente, este timer se encuentra definido dentro de la librería “ asynctmr.h ”.
Funciones para el manejo de un Timer Asíncrono Debido a que este tipo de control no es definido desde el editor UIR, es necesario conocer algunas funciones que nos serán de ayuda para administrar el comportamiento de este timer. -
NewAsyncTimer . Con esta función creamos un nuevo timer asíncrono. Cada timer creado, tiene asociado un identificador (ID) que es de tipo entero, mismo que es retornado por la función: iIdentificador = NewAsyncTimer(…);
Esta función requiere de 4 parámetros: o Intervalo: se define el tiempo de ejecución del timer (valor doble) o Contador : un valor de -1 significa que el timer se estará ejecutando hasta que sea descartado por software. Para un valor mayor que cero, indicará el número de veces que se ejecutará antes de que el timer se descarte automáticamente. o Estado inicial : acepta los valores de 0/1. Un cero indica que el timer será creado pero estará detenido hasta que indiquemos por software lo contrario.
28
Para un valor de 1, indica que el timer automáticamente comienza a generar las llamadas callback de su función asociada. o Función de evento: requiere el nombre de la función callback que se ejecutará, por ejemplo “MiFuncion”. Manualmente deberemos crear la función callback de esta función que tendrá la siguiente estructura: int CVICALLBACK MiFuncion (int reserved, int timerId, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_TIMER_TICK: break; } return 0; }
Como podemos observar la estructura es muy similar a las que hemos manajeado hasta el momento para una función callback. o Dato callback: por el momento dejaremos en cero este parámetro. Más adelante trabajaremos el paso de datos/estructuras por referencia a una función callback. El aspecto de la línea de código donde creamos un timer sería como sigue: iIdentificador = NewAsyncTimer (.01, -1, 1, MiFuncion, 0);
-
SetAsyncTimerAttribute . Al igual que hemos manejado la función SetCtrlAttribute para controles, para el caso de un timer asíncrono tenemos su función equivalente que nos permite modificar el comportamiento del mismo.
Esta función requiere de 3 parámetros para su uso: o Identificador de timer . La variable entera que tiene la referencia del timer. o Atributo. Se puede seleccionar de una lista 5 posibles atributos a modificar. o Valor del atributo . De acuerdo al tipo de atributo a modificar, corresponderá el tipo de dato a colocar. Ejemplo de la instrucción SetAsyncTimerAttribute: SetAsyncTimerAttribute (iIdentificador, ASYNC_ATTR_ENABLED, 0);
-
DiscardAsyncTimer . Permite liberar los recursos asignados a un timer asíncrono, para lo cual bastará pasar por referencia el identificador del timer a eliminar. DiscardAsyncTimer (iIdentificador);
29
Ejercicio utilizando un timer asíncrono Diseñaremos una interfaz como la siguiente:
Funcionamiento.
-
El botón “Crear timer ”, deberá construir el timer asíncrono para que se ejecute a un intervalo de tiempo de 0.001 milisegundo. El timer deberá comenzar a ejecutarse automáticamente para incrementar el contenido del control numérico en 0.001 El botón “Pausa”, una vez que ha sido creado el timer y se encuentra en ejecución, deberá pausar su ejecución. El botón “Reanudar ” deberá eliminar la pausa al timer asíncrono, reanudando la actualización de incremento en el control numérico.
Una vez concluida la aplicación y estando en ejecución, revisar el rendimiento del procesador de la computadora y compararlo contra el ejercicio del timer síncrono con un intervalo de 0.001.
30
Manejo de ActiveX LabWindows tiene la capacidad de utilizar los ActiveX registrados en Windows, dentro de las aplicaciones que construyamos. Como antecedente podemos comentar que los ActiveX son una tecnología diseñada por Microsoft para el intercambio de información entre dos aplicaciones diferentes. Surgió de la combinación de dos tecnologías previas, OLE (Object Linking and Embedding - Inserción y vinculación de objetos) y COM (Common Object Model - Simulación de objetos comunes). Generalmente podremos identificar a un ActiveX por la extensión del archivo que lo contiene, siendo ésta .OCX
¿Cómo se registra un ActiveX en Windows? En el caso de que dispongamos de un archivo OCX y deseemos registrarlo para utilizarlo con LabWindows o cualquier otra plataforma de desarrollo, el proceso a seguir será el siguiente: -
Necesitamos disponer del siguiente archivo ejecutable: regsvr32.exe Normalmente este archivo se encuentra en C:\Windows Estando en la carpeta donde se encuentra nuestro archivo OCX, ejecutaremos la siguiente línea de comando. Para este ejemplo, se supone la existencia de un archivo OCX de nombre calendario.ocx que se encuentra en raíz. C:\>regsvr32 calendario.ocx Acto seguido nos presentará una ventana de confirmación del proceso de registro.
¿Puedo eliminar un ActiveX registrado? Si se desea retirar un ActiveX previamente registrado, bastará con ejecutar la siguiente línea de comando: C:\>regsvr32 /u calendario.ocx
Insertando y habilitando un ActiveX en nuestro panel UIR Cuando insertamos un ActiveX en alguno de los paneles de nuestro proyecto, es necesario seguir un sencillo procedimiento para generar un archivo de extensión .fp Este archivo contiene las diferentes funciones o métodos que podremos utilizar del ActiveX. Es importante saber que no siempre se tiene disponible la ayuda de las funciones de un ActiveX al insertarse en LabWindows. Esto queda sujeto a la documentación que se haya generado en el mismo ActiveX.
31
Para insertar un ActiveX, de nuestra paleta de controles en el editor de UIR, seleccionaremos la opción etiquetada como ActiveX… Esto nos mostrará la siguiente ventana:
En esta ventana podremos observar una lista con todos los diferentes controles ActiveX que se encuentran registrados en nuestro sistema operativo Windows. Tomaremos como ejemplo el control Calendario de Windows.
Hecho lo anterior, observaremos que se inserta en nuestro panel el control ActiveX solicitado:
Si
pulsamos
doble
clic
izquierdo 32
sobre
el
control,
podremos ver que tenemos la posibilidad de configurar nuestra ya conocida Constant Name y Callback Function , las cuales nos ayudan a identificar en código el control y capturar los eventos respectivamente.
Procedamos a generar el archivo .fp con las funciones disponibles. Sobre el control pulsaremos clic derecho y en el menú flotante seleccionaremos la opción
LabWindows nos mostrará la siguiente ventana en donde podremos especificar el prefijo a utilizar para el nombre de cada funcion, por ejemplo, si definimos un prefijo DEMO, cada una de nuestras funciones quedarán con el nombre como sigue: DEMO_NombreFuncion.
33
Así mismo, en esta ventana podremos seleccionar el directorio donde deseamos sea depositado nuestro archivo .fp generado. No olvidemos que este archivo .fp debe estar disponible para el proyecto, ya que de ahí estará tomando la información para poder ejecutar cada una de las funciones que invoquemos relacionadas con el ActiveX. Por el momento no modificaremos nada en la opción de “ Compatibility Options…”. Pulsamos “Next” y mostrará la siguiente ventana:
En la parte superior nos mostrará el nombre del control al que se generará el archivo .fp Podemos pulsar en el botón “ Advanced Options…” para mostrar la siguiente información:
34
En este pantalla podemos revisar cada una de las diferentes funciones que se van a generar. Finalmente, al continuar con el proceso de generación, tendremos la última pantalla que nos confirma que se ha generado la librería para CVI.
¿Qué cambios hay en nuestro proyecto? Recordemos la sección de nuestro entorno de desarrollo denominada panel de librerías. Ahí podremos observar que se ha agregado un nuevo elemento denominado Microsoft Calendar Control 2007. Este nombre puede variar un poco de acuerdo a la versión del ActiveX disponible en la computadora.
Si extendemos el contenido de este elemento, podremos observar en detalle cada una de las funciones que tenemos disponibles para el control ActiveX que hemos insertado en nuestro proyecto. También podemos observar el prefijo que tuvimos oportunidad de personal al inicio en el asistente para generar la librería .fp
35
Otro lugar donde podemos confirmar que nuestra librería ha sido cargada, es en el menú principal de nuestro entorno de desarrollo, en la sección de Instrument.
Podemos ver que en la parte superior de la lista, aparece el nombre que identifica a nuestra librería .fp El resto de las opciones de este submenú, nos permiten administrar nuestras librerías. Es decir, si disponemos de alguna otra librería de tipo .fp, aquí es donde podemos indicarle a nuestro proyecto que las incluya, las elimine o incluso, editarlas. Nosotros podemos crear desde cero nuestra propia librería .fp, sin embargo, ese es un tema que requiere dedicar varias horas de trabajo y por el momento, esta fuera del alcance de este curso.
Ejercicio utilizando el ActiveX de Calendario de Windows Diseñaremos una interfaz como la siguiente:
36
Funcionamiento: Esta aplicación deberá capturar los eventos del control Calendario que correspondan al momento en que modificamos la fecha seleccionada en él.
Una vez capturado el evento de modificación, en los controles inferiores (Día, Mes y Año) se deberá actualizar con la información correspondiente. Esta información la obtendremos del control Calendario. Finalmente, el botón de comando “ Actualizar calendario al día de hoy”, nos servirá para restaurar la fecha en el control Calendario a la actual de nuestro sistema.
Bien, pues comencemos a desarrollar nuestra aplicación. Una vez que hemos configurado nuestro UIR y generamos código, tendremos dos funciones Callback que nos servirán para: -
Cerrar nuestra aplicación Capturar evento del botón de comando
¿No debemos definir una función callback para el control Calendario?
Si. Nuestro control Calendario necesita de una función callback para que nos informe cuando se detecte un evento sobre el mismo, sin embargo, para los controles ActiveX LabWindows no puede asociar una función callback de manera directa como hasta ahora lo hemos hecho con controles y paneles. Más adelante veremos cómo podemos obtener una función callback de nuestro control Calendario. ¿Cómo utilizamos nuestro control Calendario en nuest ro código?
Al igual que nuestros paneles requieren de una referencia (manejador) para ser utilizados a lo largo de nuestro código, para cada control ActiveX que insertamos en nuestro código debemos generar una referencia para el mismo fin. La instrucción que nos permite obtener una referencia de un control ActiveX es la siguiente:
GetObjHandleFromActiveXCtrl (panel, control, handle); Donde: -
Panel. Es la referencia del panel en el que se encuentra insertado el control ActiveX - Control. El identificador del control, que como hemos visto, se compone por el nombre de la constante del panel + el nombre de la constante del control - Handle. Es la variable donde se almacenará la referencia de nuestro control. Esta variable es de un tipo de dato que no hemos manejado hasta el momento que es:
CAObjHandle
37
Si exploramos dentro de los archivos .h para encontrar qué tipo de dato es este, encontraremos que es un tipo entero, sin embargo, las funciones están diseñadas para esperar un dato de tipo CAObjHandle. Esta referencia del control Calendario, bien la podemos obtener al inicio de nuestra aplicación, incluyendo código en la función main. Así mismo, la variable de referencia nos conviene sea de alcance global.
Antes de comenzar a insertar funciones relacionadas con el control Calendario para obtener información de él, necesitamos crear la función callback que nos falta. Veamos en nuestro panel de librerías lo siguiente. La librería tiene dos grupos de funciones: - Event Callback Registration Functions - ICalendar El primer grupo nos ofrece lo siguiente:
Aquí tenemos cada una de las funciones que nos permitirán registrar nuestras funciones callback y que podemos asociar a nuestro control Calendario. Podemos ver que tenemos funciones para registrar eventos tales como: - Después de que se ha generado alguna actualización - Antes de generar una actualización - Un clic - Double clic - Etc.
38
¿Cómo registrar una función callback?.
Para ello, invocaremos la función que nos permita registrar el evento que nos interesa, por ejemplo, seleccionaremos la de nombre
Para insertar la función, podemos arrastrar y soltarla dentro de nuestro código. Esta función requiere de algunos parámetros. Para poder obtener asistencia en el llenado de la función podemos pulsar clic derecho sobre el nombre de la función y seleccionar Recall Function Panel (Ctrl+P) .
Esto nos mostrará el siguiente asistente: Podemos ver que algunos parámetros son llenados con información por default. Desafortunadamente en la mayoría de los casos, no dispondremos de una ayuda descriptiva sobre pará que son cada unos de los parámetros de las funciones de un control ActiveX. Sin embargo, con un poco de práctica podremos ir dominando esta falta de ayuda hasta que podamos manejar cualquier control ActiveX en LabWindows.
39
En los dos parámetros que se encuentran en blanco, el primero nos está solicitando lo que llama “Server Object”. Esto no es más que la variable donde actua lmente tenemos almacena la referencia de nuestro control Calendario. El segundo, está solicitando el nombre que tendrá nuestra función callback que se asociará con el evento que hemos seleccionado. Para este caso la h e llamado “MiFuncion”. Al final, nuestra línea de código quedaría como sigue:
Hasta este momento hemos registrado la función callback, ahora hace falta crear la función misma. Para ello, la estructura que debe tener la función es la siguiente: HRESULT CVICALLBACK Callback (CAObjHandle caServerObjHandle, void *caCallbackData); Por lo tanto, nuestra función quedaría como sigue:
40
Es importante definir el prototipo de nuestra función al principio, esto para que el compilador tenga conocimiento de la misma. Ahora sí, ya tenemos lista nuestra función callback en la cual podemos insertar el código necesario para leer información del control Calendario. Estas funciones las encontraremos en el segundo grupo de funciones de la librería creada. Lo que necesitamos conocer del control calendario es la fecha seleccionada, para ello requerimos funciones que nos informen el día, mes y año activos.
Complementando las funciones con sus parámetros e incluyendo el código para actualizar la interfaz de usuario, nuestro código quedaría:
Finalmente, necesitamos incluir código para que el botón de comando restablezca el control Calendario a la fecha actual. Si revisamos en la lista de funciones disponibles del control Calendario, encontraremos una que se llama Nuestra función quedaría como sigue:
41
Listo, nuestra aplicación que opera con el ActiveX de Calendario de Windows está terminada. Con este ejemplo hemos visto el proceso de insertar, generar código y utilizar funciones de un control ActiveX. Para cualquier control ActiveX es el mismo proceso, el reto al que nos estaremos enfrentando es el comprender el contenido de las funciones del mismo. Veremos que existen controles con unas cuantas funciones que son sencillas de entender y en algunos casos, pueden resultar algo extensas en su número de funciones y relaciones que guardan entre ellas. Por ejemplo, para el caso del reproductor Windows Media Player, los grupos de funciones disponibles son los siguientes:
Y cada grupo puede tener una lista extensa de
funciones disponibles. ¿Complicado?. La verdad es que es más sencillo de lo que aparenta ser.
42
Para muchos controles ActiveX ayuda tener presentes el concepto de programación orientada a objetos (POO). Si bien, el compilador de Ansi C de LabWindows no tiene soporte para una POO, los ActiveX al momento de su construcción pudieron haber sido escritos bajo este paradigma. Entonces, ¿cómo se manejaría un ActiveX de este tipo en LabWindows?. Dado que un objeto pudiera ser el resultado de una serie de herencias de clases más altas, antes de comenzar a utilizar una función en particular de un ActiveX, necesitamos obtener la referencia de la clase más alta y comenzar a bajar clase por clase, hasta llegar a nuestra función con la referencia correcta. ¿Cómo identificar las clases dentro de mi librería .fp? Una clase sería un grupo de funciones en nuestra librería .fp Entonces, necesitaríamos obtener la referencia de ese grupo, para después, con esa referencia obtener una segunda de otro grupo y así sucesivamente hasta llegar al grupo que contiene la función que nos interesa utilizar.
Aquí es donde tenemos que deducir nosotros esa relación que pudieran guardar los grupos de funciones entre sí. Algunas aplicaciones que nos ofrecen controles ActiveX y que podemos utilizar en nuestros proyectos de LabWindows son: -
Adobe Acrobat Reader Flash Player Reproductor Windows Media Player Quick Time Player Etc.
Con la experiencia de este ejercicio paso a paso, estamos en posibilidad de construir una nueva aplicación utilizando otro control ActiveX.
43
Ejercicio utilizando el ActiveX de Adobe Reader Este ejercicio consistirá en construir una aplicación en LabWindows que nos permita visualizar archivos PDF embebidos en nuestro panel. El aspecto de nuestra interfaz de usuario sería la siguiente:
Les complemento adicionales.
con
algunas
pantallas
El botón de “Seleccionar archivo…”, deberá permitir buscar archivos de extensión PDF.
44
Una vista de cómo luciría nuestro visor de archivos PDF.
Listo, adelante con la construcción de su aplicación.
45
Manejo de bases de datos LabWindows nos permite interactuar prácticamente con cualquier base de datos que necesitemos trabajar. Para lograr esto se auxilia de un toolkit denominado LabWindows/CVI SQL Toolkit , el cual proporciona un grupo de funciones de alto nivel que permiten establecer la comunicación con la base de datos. Algunas de las características de este toolkit, son el que soporta comunicación con bases de datos a través del estándar ADO (Active Data Object) y con manejadores ODBC (Open Database Connectivity). Entre las funciones que disponemos para el manejo de la información de la base de datos, tenemos las que nos permiten leer el tipo de dato de la columna que se esté consultando, crear tablas, ejecutar selecciones, inserciones, actualizaciones y eliminar a través de sentencias SQL. Antes de comenzar a utilizar bases de datos con LabWindows, daremos un repaso de algunos conceptos básicos de bases de datos.
Conceptos de base de datos Una base de datos es una colección organizada de datos. Las aplicaciones de administración de bases de datos más actuales (MySQL, SQL Server, Oracle, etc), implementan esta organización a través de lo que se conoce como tablas. Las tablas están organizadas en registros también conocidos como renglones y en campos, también conocidos como columnas. Cada tabla de una base de datos debe tener un nombre único. Lo mismo aplica para los nombres de los campos que integran una tabla. Las tablas de una base de datos pueden tener diversos usos. La siguiente tabla es un ejemplo en donde se utiliza para almacenar información de los resultados de un programa que lleva a cabo pruebas secuenciales. La tabla tiene columnas para el número de unidad bajo prueba (UUT), nombre de la prueba, resultado de la prueba y dos mediciones.
Los datos al interior de una tabla no tienen un orden específico. Ordenarlos, agruparlos y otro tipo de operaciones con la información ocurre cuando de utiliza la sentencia SELECT para 46
extraer la información de la tabla. Un renglón puede tener columnas vacías, lo cual significa que el renglón contiene valores nulos (NULL). Hay que destacar que el valor nulo en una base de datos, no es lo mismo que el valor nulo utilizado en la programación en lenguaje C. Cada columna en una tabla tiene un tipo de dato definido. La disponibilidad de los datos dependerá de cada administrador de base de datos (DBMS). El toolkit de SQL de LabWindows usa un grupo común de tipos de datos. La siguiente tabla muestra los tipos de datos soportados por el LabWindows/CVI Toolkit SQL.
Structured Query Language (SQL) El SQL consiste de un estándar ampliamente soportado para el acceso a bases de datos. Los comandos de SQL son utilizados para manipular los renglones y columnas en las tablas de una base de datos. Los comando de SQL se dividen en dos tipos de sentencias: DDL y DML. -
-
DDL (Data Definition Languaje - lenguaje de definición de datos) : las sentencias DDL nos sirven para crear tablas y sus componentes: tablas, índices, relaciones, disparadores (triggers), procedimientos almacenados, etc. DML (Data Manipulation Languaje - lenguaje de manipulación de datos) : las sentencias DML son aquellas utilizadas para insertar, borrar, modificar y consultar los datos de una base de datos.
A lo largo de este documento, nos enfocaremos en mayor medida a las sentencias DML. La siguiente es una lista de los comandos más comunes de SQL: -
CREATE TABLE . Permite crear una nueva tabla especificando el nombre y tipos de datos para cada una de las columnas. SELECT. Extrae todos los renglones en una tabla que cumplen con la condición especificada. INSERT. Agrega un nuevo registro a la tabla. Esto permite asignar los valores deseados a cada una de las columnas.
47
-
UPDATE. Actualiza los valores en las columnas especificadas para todos los renglones que cumplan con la condición definida. DELETE. Elimina todos los registros que cumplan con la condición especificada.
Ejercicios con código SQL Vamos a realizar algunos ejercicios utilizando código SQL con Microsoft Access. Debido a que Access tiene limitaciones para procesar código SQL por lotes, será necesario que ejecutemos una a una las siguientes líneas de código SQL. El objetivo es que al final tengamos lista una base de datos con tres tablas e información incluida con la que trabajaremos. Primero necesitamos crear una base de datos en blanco, para ello abriremos Access.
1
2
3
1. Primero pulsaremos clic sobre el icono de “ Base de datos en blanco”. Esto nos habilitará la sección número 2. 2. En esta parte definiremos el nombre de nuestra base de datos y la ubicación de la misma. 3. Indicaremos que Access proceda con la creación de nuestra base de datos en blanco (sin tablas).
48
Veremos la siguiente pantalla. Por default nos propone una tabla en blanco con el nombre “Tabla1”. Esta tabla no la necesitamos, por lo que procedemos a indicarle a Access que la cierre de la siguiente manera:
Ahora con nuestro entorno de desarrollo limpio, buscaremos abrir el editor de SQL desde el menú principal en la opción Crear y posteriormente clic en la opción Diseño de consulta.
Access nos mostrará la siguiente pantalla, misma que podemos cerrar.
49
Ahora habilitaremos el editor de SQL pulsando clic en el siguiente botón:
Listo!! Tenemos nuestro editor para recibir sentencias de SQL.
Bien, a continuación se encuentran las sentencias de SQL que deberemos ejecutar una a la vez. Esto será, copiar la sentencia de este documento y pegar reemplazando lo que exista en el editor (donde dice SELECT;). Posteriormente pulsar clic en el botón confirmando la acción. Comencemos!
50
Las siguientes sentencias son para crear nuestras tres tablas. a) CREATE TABLE Frecuentan(bebedor varchar(20) NOT NULL,bar varchar(20) NOT NULL); b) CREATE TABLE Sirven(bar varchar(20) NOT NULL,cerveza varchar(20) NOT NULL); c) CREATE TABLE Le_Gusta_Beber(bebedor varchar(20) NOT NULL,cerveza varchar(20) NOT NULL);
Al concluir esta parte deberemos ver lo siguiente en Access.
Ya tenemos listas nuestras 3 tablas, ahora comencemos a insertar datos en cada una de ellas ejecutando de igual manera las siguientes sentencias. Para la tabla Frecuentan: a) b) c) d) e) f) g) h)
insert insert insert insert insert insert insert insert
into into into into into into into into
Frecuentan Frecuentan Frecuentan Frecuentan Frecuentan Frecuentan Frecuentan Frecuentan
VALUES('Hugo','Los Correa'); VALUES('Hugo','Los Tres Amigos'); VALUES('Hugo','El Portal'); VALUES('Paco','Los Tres Amigos'); VALUES('Paco','El Cortijo'); VALUES('Luis','Los Correa'); VALUES('Luis','El Portal'); VALUES('Tere','El Fuerte');
Para la tabla Sirven: a) b) c) d) e) f) g) h) i) j) k) l) m)
insert insert insert insert insert insert insert insert insert insert insert insert insert
into into into into into into into into into into into into into
Sirven Sirven Sirven Sirven Sirven Sirven Sirven Sirven Sirven Sirven Sirven Sirven Sirven
VALUES('Los Correa','Budweiser'); VALUES('Los Correa','Heineken'); VALUES('Los Correa','Tecate'); VALUES('Los Correa','Modelo Especial'); VALUES('Los Tres Amigos','Budweiser'); VALUES('Los Tres Amigos','Heineken'); VALUES('Los Tres Amigos','Tecate'); VALUES('Los Tres Amigos','Corona'); VALUES('El Portal','Budweiser'); VALUES('El Portal','Corona'); VALUES('El Portal','Sol'); VALUES('El Fuerte','Modelo Especial'); VALUES('El Cortijo','Indio');
51
Para la tabla Le_Gusta_Beber: a) b) c) d) e) f) g) h) i)
insert insert insert insert insert insert insert insert insert
into into into into into into into into into
Le_Gusta_Beber Le_Gusta_Beber Le_Gusta_Beber Le_Gusta_Beber Le_Gusta_Beber Le_Gusta_Beber Le_Gusta_Beber Le_Gusta_Beber Le_Gusta_Beber
VALUES('Hugo','Budweiser'); VALUES('Hugo','Modelo Especial'); VALUES('Hugo','Corona'); VALUES('Paco','Heineken'); VALUES('Paco','Corona'); VALUES('Luis','Heineken'); VALUES('Luis','Tecate'); VALUES('Luis','Corona'); VALUES('Tere','Negra Modelo');
¿Qué información hemos ingresado a nuestras tablas? Vamos a revisar la información de cada una de nuestras tablas. Para ello comenzaremos a utilizar nuestra sentencia SELECT de la siguiente forma.
En el mismo editor de SQL, comencemos con lo siguiente: select * from Frecuentan;
al ejecutar esta sentencia, Access nos mostrará la siguiente vista:
Aquí tenemos una vista que contiene el nombre de la persona (columna bebedor) y el nombre del bar (columna bar) que acostumbra visitar. He resaltado el nombre de la pestaña que tiene el nombre Consulta1, porque lo que estamos viendo es el resultado de la consulta, no la tabla en sí misma. Así ocurrirá con cada SELECT que ejecutemos, el resultado será una vista con la información que hayamos solicitado. Si quisiéramos ver el contenido de la tabla, bastará con dar doble clic en el nombre de la tabla.
52
Para ingresar una nueva consulta, bastará pulsar clic derecho sobre el nombre de la pestaña y seleccionar Vista SQL.
Continuemos con nuestra segunda consulta, select * from Sirven:
En este caso, tenemos una tabla que nos muestra el bar (columna bar) con sus respectivos tipos de cervezas que sirven (columna cerveza). 53
Concluyamos con la tercer sentencia select * from Le_Gusta_Beber:
En esta ocasión, tenemos el nombre de la persona (columna bebedor) y la cerveza que es de su agrado tomar (columna cerveza). En resumen, tenemos la información de los bares que les gusta visitar a cada una de las personas, así como la cerveza que ofrecen cada uno de los bares y la cerveza que le gusta tomar a cada uno de ellos. Con esta información comenzaremos a realizar algunas consultas interesantes. No entraremos en detalle sobre la explicación de cada una de las consultas en este documento, sin embargo, podemos discutir su funcionamiento, el objetivo principal es tener una idea del potencial que tenemos al utilizar el comando SELECT. Para ampliar la información sobre SQL, recomiendo consultar un tutorial sobre SQL. Comencemos: a) Queremos imprimir todos los bares que tiene registrados el sistema. SELECT bar FROM frecuentan UNION SELECT bar FROM sirven;
54
b) Queremos imprimir todas las marcas de cerveza que tiene registradas el sistema. SELECT cerveza FROM sirven UNION SELECT cerveza FROM Le_Gusta_Beber;
c) Queremos imprimir todos los bebedores que se tienen registrados en el sistema. SELECT bebedor FROM frecuentan UNION SELECT bebedor FROM Le_Gusta_Beber;
d) Queremos imprimir los bares que sirven una cerveza que le gusta beber a Hugo. select DISTINCT bar from sirven where cerveza IN (select cerveza from Le_Gusta_Beber where bebedor LIKE 'Hugo');
e) Imprimir los bebedores que frecuentan bares donde sirven alguna cerveza que les gusta. SELECT DISTINCT f.bebedor FROM Frecuentan f, Sirven s, Le_Gusta_Beber l WHERE f.bar = s.bar AND s.cerveza = l.cerveza AND f.bebedor = l.bebedor;
55
f) Imprimir el bar que sirve la mayor cantidad de marcas de cerveza. SELECT bar,COUNT(*) AS Bares FROM Sirven GROUP BY bar HAVING COUNT(*) >=ALL (SELECT COUNT(*) FROM Sirven GROUP BY bar );
g) Imprimir el bar que sirve la menor cantidad de macas de cerveza.
SELECT bar,COUNT(*) AS Bares FROM Sirven GROUP BY bar HAVING COUNT(*) <=ALL (SELECT COUNT(*) FROM Sirven GROUP BY bar );
56
h) Imprimir a los bebedores que frecuentan bares donde sirven más marcas de cerveza que la cantidad de marcas que a ellos les gusta. Imprimir al bebedor y al bar que frecuentan. SELECT bebedor, bar FROM Frecuentan f WHERE EXISTS ( SELECT bar FROM Sirven s WHERE f.bar = s.bar GROUP BY s.bar HAVING COUNT(*) > (SELECT COUNT(*) FROM Le_Gusta_Beber l WHERE f.bebedor = l.bebedor)) ORDER BY bebedor;
Cada una de estas sentencias de SQL las podemos ejecutar tal cual dentro de LabWindows/CVI, más adelante comenzaremos a analizar como lograremos esto. Por ahora continuemos revisando los requisitos de configuración previos a trabajar con LabWindows.
LabWindows/CVI Toolkit SQL Al inicio de esta sección se mencionó que LabWindows puede conectarse con bases de datos a través de un toolkit. Este toolkit lo podemos encontrar en los DVD’s de instalación de la Suite de National Instruments. Para el caso de la Suite 2009 Tercer Cuarto, se encuentra en el tercer DVD. En necesario instalar este toolkit antes de comenzar a trabajar con LabWindows. La instalación no requiere de configuración alguna, basta con seguir el asistente hasta concluir la misma.
Adminstrador ODBC La mayoría de las ocasiones al trabajar con una base de datos en LabWindows, requeriremos hacer algunas modificaciones de configuración al administrador de orígenes de datos que tiene Windows. Esto administrador al ejecutarlo mostrará la siguiente ventana.
57
Aquí definiremos el nombre de nuestro nuevo origen de datos, que no es más que seleccionar un controlador para el tipo de base de datos a utilizar y asociarlo en su caso, con nuestra base de datos. Para ello, cuando pulsamos en el “Agregar ”, veremos la siguiente ventana.
botón
De la lista de controladores existentes, seleccionaremos el que corresponda a nuestro tipo de base de datos a utilizar: - Microsoft Access - Visual FoxPro - Oracle - SQL Server - MySQL - PostgreSQL - Etc. Para cada tipo de controlador se requerirá una configuración en particular. En algunos casos como Microsoft Access, bastará con definir un nombre para identificar a nuestro origen de datos (este nombre lo ocuparemos al interior de nuestro código en LabWindows) y la ruta donde se encuentra la base de datos a utilizar. En otros casos habrá que definir un usuario, contraseña, ubicación del servidor y la base de datos a utilizar. Concluyendo el proceso anterior, tendremos listo nuestro origen de datos para ser utilizado por nuestra aplicación. En algunas ocasiones es posible que nuestro sistema Windows no cuente con el controlador de base de datos que necesitamos. En este caso tendremos que buscar el controlador para instalarlo. Por ejemplo, si necesitamos nuestro conector ODBC para MySQL bajo sistemas Windows, podríamos recurrir a un buscador en web y buscar de la siguiente forma.
58
Encontraremos el conector para descargar con información referente a su versión, plataforma de trabajo, tipo de instalador, etc.
Una vez instalado el controlador correspondiente, dispondremos del mismo en nuestra ventana de configuración de administrador de orígenes de datos.
LabWindows y bases de datos Comenzaremos conociendo las relaciones que existen entre las funciones del toolkit para el manejo de bases de datos con la siguiente figura.
59
¿Qué nos indica la figura anterior? Primero consideraremos nuestras acciones sobre una base de datos en dos grupos: 1) Para consultar información (implica la sentencia SELECT) 2) Para insertar, actualizar o borrar información (INSERT, UPDATE o DELETE)
En el primer caso, la secuencia que debemos seguir en el diagrama es la siguiente:
Para el segundo caso, la secuencia a seguir es la siguiente:
60
¿Cómo realizar una consulta en LabWindows? En este momento estamos más familiarizados con el concepto de referencias en Labwindows. Así como un panel o un control ActiveX requieren que obtengamos una referencia a ellos, en base de datos tendremos algo similar.
Primero comenzaremos por establecer nuestra conexión a la base de datos a través de nuestro ODBC (origen de datos) previamente configurado. De este ODBC lo que necesitamos conocer es el nombre que hayamos asignado. Para establecer la conexión contamos con la siguiente función: iRefODBC = DBConnect(“nombre del ODBC”); La variable que reciba la referencia (tipo entero), se conseja sea de ámbito global, ya que será utilizada para diferentes funciones relacionadas con la base de datos. El nombre del ODBC debe ir entre comillas, ya que el parámetro que espera es un string. La conexión a la base de datos basta que se realice una vez al iniciar la aplicación y concluirla cuando se cierre la aplicación.
El siguiente paso es ejecutar nuestra sentencia SELECT deseada. Por ejemplo, consultemos el contenido de la tabla Frecuentan. La función a utilizar es la siguiente: iRefConsulta = DBActivateSQL(iRefODBC, “select * from Frecuentan”);
Recordemos de nuestros ejercicios de consulta con Access, que al ejecutar una sentencia SELECT nos retornaba una vista con el contenido de la información solicitada. Para la sentencia que estamos ejecutando, el asterisco (*) significa que queremos ver todas las columnas de la tabla frecuentan.
61
LabWindows no puede mostrar una vista como lo hace Access, sin embargo, nos retorna una referencia a dicha vista (para el ejemplo en la variable entera iRefConsulta). Con esta referencia podremos leer el contenido de la vista. iRefConsulta = DBActivateSQL(iReferenciaODBC, “select * from Frecuentan”);
iRefConsulta
Lo siguiente que analizaremos, es cómo LabWindows puede vincular en base a la referencia obtenida, el contenido de cada columna de la vista que se ha generado.
iRefConsulta
Para poder vincular la información de la vista que hemos generado, necesitamos conocer el tipo de dato de cada una de las columnas contenidas para identificar la función de lectura adecuada en LabWindows. Por ejemplo: Tipo texto Vista generada Tipo texto
62
Las funciones que nos ofrece LabWindows para vincular nuestro código con el contenido de una columna en una vista, son las siguientes: -
DBBindColChar . Nos servirá para leer información de una columna de tipo carácter o string.
Donde:
. Retorna el estado de ejecución de la función. En caso de resCode error, aquí podemos saberlo. . Espera la variable que contiene la referencia a la statementHandle vista que se ha consultado. c o l u m n N u m b e r . Número de columna a leer. Para el ejemplo que estamos manejando tendríamos: 1
-
2
…
m a x L e n . Longitud de la cadena en bytes. locationForValue[] . Apuntador a la variable arreglo de char donde se almacenará la cadena a leer. *locationForStatus. Apuntador a la variable que almacenará el estado de la lectura de la información indicando si la información fue truncada o se leyó un NULL. formatString[]. Se utiliza para dar formato a la cadena a leer.
DBBindColShort. Utilizada para leer información de una columna con un tipo de dato short.
Donde:
-
locationForValue . Apuntador a la variable tipo short int donde se almacenará la cadena a leer.
DBBindColInt.
63
Donde:
-
locationForValue . Apuntador a la variable tipo short int donde se almacenará la cadena a leer.
DBBindColFloat.
Donde:
-
. Apuntador a la variable tipo float donde se locationForValue almacenará la cadena a leer.
DBBindColDouble. Utilizada para leer información de una columna con información de tipo doble.
Donde:
. Apuntador a la variable de tipo doble donde se *locationForValue almacenará el dato a leer.
Es importante que el número de columna que se ingrese en cada una de las funciones anteriores, corresponda con el orden de las columnas que existe en la vista que hemos generado.
Volviendo a nuestro ejemplo de consulta a la tabla Frecuentan, nuestro código desde la conexión a la base de datos hasta vincular la vista a variables de código quedaría como sigue:
La longitud de los arreglos de tipo char se han definido de 21 bytes, porque al construir nuestra tabla Frecuentan, definimos que el ancho de cada una de las columnas fuera de 20 caracteres. El byte adicional es para que se pueda incluir el carácter de fin de cadena.
64
Una vez que tenemos establecida la vinculación con las columnas de la vista, el siguiente paso es leer renglón por renglón de la vista generada. Para este efecto, LabWinidows nos ofrece las siguientes funciones: -
DBFetchNext. Permite avanzar al siguiente registro disponible.
Donde:
. Espera la variable que contiene la referencia a la statementHandle vista que se ha consultado.
La función retornará un valor diferente a cero cuando no haya más registros a dónde saltar. Cuando se realiza la vinculación de variables (sección anterior), nuestro cursor en la vista no se ha posicionado aún sobre los datos, necesitamos ejecutar por lo menos una vez la función DBFetchNext para tener acceso a los datos. cursor
Después de ejecutar DBFetchNext: cursor
-
DBFetchPrev. Permite regresar el cursor al registro inmediato anterior.
-
DBFetchRandom. Cuando conocemos la cantidad de registros que existen en la vista que hemos generado, podemos dar saltos a registros específicos a través de esta función.
65
Donde:
r e c o r d N u m b e r . El número de registro al que deseamos saltar.
Al ejecutar estas funciones, ¿dónde se encuentra la información leída?. Recordemos nuestro código donde vinculamos variables a las columnas de la vista. Variables vinculadas
Cada vez que ejecutemos por ejemplo DBFetchNext, el contenido de estas variables se actualizará con la información correspondiente a donde se encuentre nuestro cursor. Veamos la siguiente secuencia: Número de ejecución De DBFetchNext
Variable cBebedor
Variable cBar
Cursor en la vista
Ninguna
““
““
Primera
“Hugo”
“Los Correa”
Segunda
“Hugo”
“Los Tres Amigos”
Tercera
“Hugo”
“El Portal”
Cuarta
“Paco”
“Los Tres Amigos”
Así sucesivamente podemos ir recorriendo el contenido de nuestra vista.
66
¿Cómo quedaría nuestro código para leer todo el contenido de la vista?. A continuación se muestra una propuesta.
Es un ciclo que se ejecutará mientras el resultado de la función DBFetchNext sea igual a la constante DB_SUCCESS que tiene un valor de cero. Una vez que se alcance el final de la vista, se dejará de ejecutar el ciclo.
Cada vez que se termine de utilizar la información de una vista, es necesario liberar la referencia a la misma. Para ello disponemos de la función DBDeactivateSQL.
Finalmente, cuando se determine que no es necesario mantener abierta la conexión con la base de datos, disponemos de la función DBDisconnect para cerrar la misma.
Nuestro código final quedaría como sigue:
67
Ejercicio para leer el contenido de la tabla Frecuentan Diseñaremos una interfaz como la siguiente:
El objetivo es que al pulsar el botón “ Leer tabla”, leamos el contenido y lo coloquemos en la pantalla para lograr lo siguiente: MS Access
Para este ejercicio, introduciremos una nueva instrucción de nombre Fmt. A continuación incluyo algunos ejemplos de uso de esta instrucción:
68
Para mayor información sobre el uso de esta función, pueden referirse a la ayuda de LabWindows.
69
¿Cómo realizar una inserción, una actualización o eliminación de registros? Para llevar a cabo estas acciones, necesitaremos disponer solamente de la referencia al ODBC que comunica con la base de datos.
Al inicio de esta sección, se hizo el ejercicio de insertar información en una base de datos de Access. Sentencias similares son las que utilizaremos más adelante.
Para ejecutar esta función, necesitaremos previamente haber construido la sentencia SQL que deseamos ejecutar y tenerla lista en una arreglo char.
Donde:
connectionHandle . Es la variable que contiene la referencia a nuestra conexión con la base de datos. *SQLStatement. La cadena con la sentencia SQL a ejecutar
Un ejemplo de código para insertar el nombre de una persona y el bar que le gusta frecuentar, quedaría como sigue:
70
Ejercicio para insertar información a la tabla Frecuentan Modificaremos nuestra aplicación anterior para lograr lo siguiente:
Con esta nueva aplicación, lo que haremos es, dados un nombre de bebedor y un nombre de bar que frecuenta, a través del botón “Insertar registro” serán agregados a la tabla Frecuentan. Para verificar que esto se haya llevado a cabo, bastará con pulsar en el botón “ Leer tabla” para actualizar la lista con el contenido.
Comandos UPDATE y DELETE
A continuación veamos información sobre el uso de estas dos instrucciones. Update. Crea una consulta de actualización que cambia los valores de los campos de una tabla especificada basándose en un criterio específico. Su sintaxis es: UPDATE Tabla SET Campo1=Valor1, Campo2=Valor2,... CampoN=ValorN WHERE Criterio;
UPDATE es especialmente útil cuando se desea cambiar un gran número de registros o cuando éstos se encuentran en múltiples tablas. Puede cambiar varios campos a la vez. UPDATE no genera ningún resultado. Para saber qué registros se van a cambiar, hay que examinar primero el resultado de una consulta de selección que utilice el mismo criterio y después ejecutar la consulta de actualización. Si en una consulta de actualización suprimimos la cláusula WHERE todos los registros de la tabla señalada serán actualizados.
71