Curso de FiveWin: Programación en Clipper
Curso de FiveWin: Programación en Clipper
Introducción.
Muchos de nosotros (debo asumirlo), somos programadores en CA-Clipper, y lo amamos.
Conocemos a la perfección el modo de programar cualquier aplicación, y nos sentimos satisfechos por nuestro
trabajo. Tenemos un “Know How” (Saber como) de años de trabajo en esta herramienta. Pero una pequeña
inquietud se nos va haciendo cada vez más grande en nosotros: Windows. Algunos han pensado en cambiar su
herramienta de trabajo, y han tentado entre el Visual Basic, Visual Fox, Delphi y/o el PowerBuilder. Hasta
incluso algún 4GL (Herramienta de programación de cuarta generación). Sin lugar a dudas, estas herramientas
son las herramientas del futuro, pero es el presente el que se nos muestra incierto. Debemos pedir a nuestros
usuarios cambiar sus computadores (80386, quizás, con suerte 80486, con 04 Mb de memoria) a equipos
Pentium con 16 Mb de memoria, y adquirir un manejador de archivos cliente-servidor? Es muy costoso. Pero,
que sucede con los usuarios que nos piden sistemas en Windows, interfaces en Windows, reportes
WYSIWYG con gráficos -en Windows-, TODO en Windows? No podemos decirles "lo siento señor, pero yo
sólo trabajo en DOS (¡!)", perderemos nuestro mercado. Pues una nueva luz surge en nuestro horizonte. Una
herramienta que nos permitirá trabajar tranquilos en lo que sabemos y prepararnos para el futuro (en unos
cinco años, quizás) , mientras vivimos en el presente. Bienvenidos al CA-Clipper y FiveWin.
*Veamos un ejemplo:
function limpiar()**
if dato->(flock())
@ 3,3 say "Reemplazando campos"
while dato->(!eof())
dato->dato:=0
dato->(dbskip(1))
enddo
endif
dato->(dbunlock())
return(nil)
*El @ 3,3 say "Reemplazando campos" debería ser el llamado a una función DOSmuestralimpia(), de ese
modo la "caja negra" no mostrará datos en pantalla. Si hacemos nuestro fuente una función equivalente
WINmuestralimpia(), las cajas negras serán exactamente iguales, independientemente del entorno operativo.
**Pueden apreciar la tendencia a utilizar funciones (en vez de comandos) y punteros (para no cambiar los
alias activos).
Escribiendo mi primer programa en Windows!
Bueno: ¡Basta de palabras y entremos a la acción!. Pues allí vamos: Primero, ingrese al Windows. Una vez en
él, cree una sesión DOS (seleccióne el ícono MS-DOS y pulse dos veces el botón izquierdo del ratón.). Cree
el directorio \demo e ingrese en él.
Si están instalados los archivos correctamente, Ud. obtendrá el programa x.exe. Al tratar de
ejecutarlo desde el DOS, el programa le dirá algo así como "This program requires Microsoft Windows" (Este
programa requiere Microsoft Windows), y esto es lo correcto, pues es un programa hecho en Windows.
Ahora, si lo llama desde el administrador de programas de Windows (Archivo / Ejecutar c:\demo\x.exe),
¡Verá en pantalla su primer programa en Clipper para Windows! (Si el programa es invocado desde en
windows 95, la sesión DOS invocará a su vez al Windows y lo ejecutará). Demasiado simple (el programa),
dirá usted. Pues tengamos paciencia por ahora, que ya llegará lo bueno.
NOTA: En lo que respecta al archivo bli.lnk, este es un archivo de enlazado, que contiene información
técnica que por el momento no nos debe preocupar, pues más adelante lo veremos con detalle. Sólo baste
saber que el mismo archivo de enlace nos servirá para todos los programas que escribamos en adelante para
Windows.
*NOTA: API Aplication Programmer Interface, o Interface para el programador de aplicaciones, lo que
(como equivalencia) para el programador era en el DOS rutinas del BIOS.
Donde:
VARIABLE Nombre de la Ventana
FVALID Función de validación al cerrarse la ventana. Debera retornar .t. para cerrarla.
FLClick Función que se ejecuta al hacerse click sobre la ventana con el mouse.
FLButtonUp Función que se ejecuta al soltar el mouse.
FRClick Función que se ejecuta al hacerse click con el botón derecho sobre la ventana con el mouse.
FMove Función que se ejecuta al moverse de lugar la ventana.
FResize Función que se ejecuta al cambiar la ventana de tamaño.
FPaint Función que se ejecuta al pintarse la ventana.
FKeyDown Función que se ejecuta al presiónar una tecla sobre la ventana.
FInit Función que se ejecuta al iniciarse la ventana.
FUp Función que se ejecuta al presiónar flecha arriba.
FDown Función que se ejecuta al presiónar flecha abajo.
FPgUp Función que se ejecuta al presiónar Page Up.
FPgDn Función que se ejecuta al presiónar Page Down.
FLeft Función que se ejecuta al presiónar Flecha izquierda.
FRight Función que se ejecuta al presiónar Flecha derecha.
FPgLeft Función que se ejecuta al presiónar left.
FPgRight Función que se ejecuta al presiónar right.
FDropFiles Función que se ejecuta al soltar información sobre la ventana.
Las coordenadas simulan las coordenadas DOS, pero con 30 filas y 80 columnas. (En DOS, por
defecto, tenemos 25 filas y 80 columnas), salvo que se indique la cláusula pixel, que nos permitirá defiirla en
números de pixels (640x480, 800x600, etc.).
El COLOR es manejado en una forma especial: En Windows tenemos una paleta de colores que
varían cada uno en sus tonos base RGB (Rojo, Verde, Azul), desde 0 hasta 255. Es decir, el rojo más intenso
nos lo dará la combinación 255,0,0. El color de la ventana se define con una función RGB() que administra
estos colores, que es, para el ejemplo:
luego, definir una ventana de pantalla completa y en color azul medio sería:
define window ow from 0,0 to 30,80 title "mi titulo" color rgb(255,255,255),rgb(0,0,128)
Note que esta línea de código ha creado la variable ventana ow. Pero, para poder utilizarla (que se vea en
pantalla), utilizamos la línea:
activate window ow.
VARIABLE2 implica que esta ventana es "hija" de una ventana anteriormente creada. De ese modo, la
ventana hija se muestra dentro de la ventana madre. Si cerramos la ventana madre, esta cerrará a la hija. Esto
lo veremos en profundidad en el capítulo de ventanas MDI.
Hemos visto eventualmente ventanas que no tienen un color, sino un patrón de dibujos (Ladrillos, por
ejemplo). Estas ventanas tienen un FONDO definido (Fivewin trae algunos ya predeterminados que
aprovecharemos). Asimismo, hemos visto alguna vez que, al pasar por una ventana, el cursor (puntero del
mouse) cambia de forma. también hemos visto que al minimizar una ventana esta muestra un ícono (dibujo)
que la representa. Y, por supuesto, hemos visto que algunas ventanas tienen un menu insertado. Finalmente,
hemos visto algunas ventanas con formas especiales (Al ingresar al Word for Windows, hemos visto el bitmap
de presentación, que es una ventana sin titulo)
(tanto en el brush como en el icon, tenemos una sintaxis RESOURCE, que será la que utilizaremos
oficialmente, una vez que lleguemos al capítulo de recursos.)
Veamos un breve ejemplo de como hacer una ventana, con unos atributos adiciónales:
local ob,ow,oi
define brush ob style BORLAND
define icon oi file "c:\micono.ico"
define window ow from 0,0 to 30,80 title "mi titulo" brush ob icon oi
activate window ow maximized on init tone(1000,10)
release brush ob
Esta ventana tendrá el ícono micono y al iniciarse sonará un pitido. (Reemplazar c:\micono.ico con cualquier
ícono que tenga en su PC.)
Aquí tenemos tres variables: ob,oi,ow. Cada una de estas es un Objeto, que encierra dentro de él todas las
características definibles posibles (Que podremos manipular) . Esto significa que tenemos mucho más para
aprovechar de ellos. Al llegar al capítulo de objetos entenderemos plenamente este concepto y sus ventajas.
Por el momento, pensemos en ellos como variables muy importantes para nuestros sistemas.
NOTA: Existen una gran cantidad de opciones/alternativas al definir nuestras ventanas. Nosotros usaremos
normalmente unas pocas de ellas, y centraremos gran parte de nuestra atención en otro tipo de ventanas,
conocidas como diálogos. Estos "modelos" de ventanas tienen una gran ventaja sobre las ventanas normales:
Permiten el conectar recursos a ellas (Como en la programación visual, en donde uno "coloca" un get en un
sitio con el mouse, y el programa lo interpreta, no necesitamos más poner @ x,y ... ).
Diálogos, sintaxis:
DEFINE DIALOG <od> ;
[ NAME | RESNAME | RESOURCE <recurso> ] ;
[ TITLE <titulo> ] ;
[ FROM <x1>, <y1t> TO <x2>, <y2> ] ;
[ LIBRARY | DLL <punterorecurso> ] ;
[ STYLE <estilo> ] ;
[ COLOR | COLORS <color1> [,<color2>] ];
[ BRUSH <fondo> ] ;
[ WINDOW | DIALOG | OF <ventana> ] ;
[ ICON <ícono> ] ;
[ FONT <fuente> ] ;
[ HELP | HELPID <idayuda> ]
[ PIXEL ] ;
[ VBX ] ;
*NOTA: Los sistemas en Windows tienden a ser "data-driven". Esto es, manejadores de data. Este esquema
(data-driven) propone aislar los datos (variables, procesos) de un sistema de su interfaz gráfica (ventanas,
gráficos). La solución que se le da a este paradigma es la generación de recursos (Originalmente, se creó el
esquema data-driven para hacer al código del sistema independiente de la plataforma, sea Mac, PC, Unix,
etc. Esto, en la práctica, no se ha conseguido aún. Si bien existen herramientas y lenguajes -Java- que se
aproximan). Un recurso es un archivo, que contiene imágenes de ventanas, con punteros (cuando lea
punteros, al programador de “C” se le pararán los pelos (Lo digo por experiencia personal, pues programé en
“C” durante dos años, antes de entrar al Clipper). No se preocupen. En Fivewin, entenderemos un puntero
como un número, y no nos deberá interesar mas que eso). Haremos con alguna herramienta (WorkShop) el
archivo recurso, "conectaremos" los punteros al programa y estaremos listos para trabajar. De este modo, el
código fuente y el tiempo de desarrollo disminuyen en un 50% (No programamos, pintamos, y fuera de
nuestro código fuente).
Ok. Un diálogo tiene prácticamente la misma sintaxis básica de una ventana. Aunque existen diferencias
sustanciales:
a. Permite recursos (Que usaremos extensivamente)
c. Tiene menos parámetros que una ventana.
Dado que en la sintaxis de los diálogos aparece el rubro fuente, definiremos de una vez su sintaxis:
Fuentes: sintaxis:
DEFINE FONT <of> ;
[ NAME <nombre> ] ;
[ SIZE <ancho>, <largo> ] ;
[ FROM USER ];
[ BOLD ] ;
[ ITALIC ] ;
[ UNDERLINE ] ;
[ WEIGHT <ancho> ] ;
[ OF <deposito> ] ;
[ NESCAPEMENT <tipodeescape> ] ;
Tal cual dije anteriormente: Todo lo que se mostrará en windows es una ventana, y un diálogo no escapa a
esto. También es una ventana, pero con características particulares. Antes de dar ejemplos de como utilizar
diálogos, entrare en la discusión de las ventanas y diálogos, y su efecto práctico dentro de nuestros sistemas.
function main()
local ow
define window ow from 0,0 to 20,50
activate window ow
return(nil)
function main()
local od
define dialog od from 0,0 to 20,50
activate dialog od
return(nil)
Empero, existe una gran diferencia: En una ventana podemos activar un MDI/timer, no así en un diálogo
(SEUO). Casi todos los sistemas que crearemos utilizaran timers/MDI, y esta es una razón practica para tener
(cuando menos) una ventana siempre en nuestros sistemas. Salvo en los casos que el programa sea una rutina
sencilla, en donde si será permisible el uso de uno o dos diálogos (Por ejemplo, un proceso batch). Pero, y tal
como hemos visto, en una ventana no podemos definir recursos, y puesta en pantalla molestaria incluso.
Entonces viene a la imaginación hacer ambas cosas, una ventana y un diálogo, y hacer que la ventana este
fuera del monitor (Vea el primer ejemplo de ventanas particulares). La solución será algo asi:
function main()
local ow,oi
define icon oi file "c:\micon.ico"
define window ow from -2,-2 to -1,-1 title "Ventana de trabajo" icon oi
activate window ow on init activadiálogo(ow)
return(nil)
function activadiálogo()
local od,of
define font of name "times new roman" size 4,10
define dialog od resource "mirecurso" titulo "FLOJO!"
* Este diálogo si esta agradable, hecho en forma visual!
od:setfont(of)
* Ojo, a la clase diálogo le cambio el font, y con ello a todos los controles del recurso!
activate dialog od centered
release font of
ow:end()
return(nil)
Si bien no es muy heterodoxo, lo utilizo, y con muy buenos resultados. La ventana no aparece en mi pantalla
(el cliente ni sabe que existe), el diálogo lo veo tal cual lo dibuje, y al cambiar de tareas me aparece el nombre
e ícono de la ventana principal, pese a que el titulo del diálogo es otro (si asi lo deseo). Finalmente, mi
sugerencia entonces es la siguiente:
CONTROLES EN WINDOWS
Definición
En Windows, el interactuar con un usuario implica el permitirle ingresar información por pantalla. Al nacer
este entorno gráfico, se hizo especial énfasis en que el entorno de trabajo fuese agradable a la vista y sencillo
en su uso, mas aun considerando que el usuario utilizaría en adelante tanto el teclado como el mouse como
herramientas para el ingreso de información. Para ello, se crearon los objetos tipicos a usarse: uno que
permitiera ingresar texto, otro para selecciónar entre dos opciones, otro para mas de dos opciones, otro para
indicar acciones, etc. Estos son los controles del Windows, que conoceremos en esta lección.
Nota Importante: Para todos los controles, existen dos tipos de sintaxis: Una es con los clasicos @ x,y, y la
oltra con los redefines.
Aquí me concentraré en los que usan los redefines, que significa que han sido dibujados, y puestos en una
ventana en forma visual. El intentar colocarlos con coordenadas es un trabajo extenuante en Windows. Por
otro lado, es mucho más sencillo hacerlo en forma visual con el WorkShop, que veremos en el siguiente
capítulo. Obviamente, son libres de optar por cualquier tecnica, si bien sugiero altamente utilizar esta técnica,
que ahorra tiempo y esfuerzo, y que adiciónalmente nos prepara para pensar en una forma más, digamos,
visual. Por otro lado, en el caso de las cláusulas con @ x,y :a excepción hecha de las coordenadas y el tamaño
(En realidad cuatro coordenadas) la sintaxis es prácticamente la misma. Así que de todos modos este texto es
una muy buena referencia. Pero, insisto: Utilizen el WorkShop.
Notas Tecnicas:
1.- Cada control que definamos debera estar con su variable que la define.
2.- Los controles comúnes meterlos en un array.
3.- La variable VAR es de uso interno del Fivewin (Es parte de comandos). No la utilizen, o tendrán
problemas.
4.- Existe una función: SYSREFRESH(), que fuerza a que se hagan los trabajos pendientes de solución antes
de continuar con el programa*.
5.- Todos los controles son "ventanas hijas" (Child). Esto significa que se mueven paralelamente al diálogo
que las contiene (Es decir, estan "pegadas" al diálogo). No nos debemos preocupar por ello.
6.- Todos los controles en Fivewin son objetos. Si desea verlos en su forma nativa, compile pequeños
programas que contengan la sintaxis a analizar con el parametro /p (Crear archivo de pre-compilado). Se
sorprendera al ver lo que es el @ say! Y de aqui sabrá una cosa: Todo en Clipper son funciones. (De hecho,
el Fox, Visual Basic, etc. hacen los mismo. Todo lenguaje desarrollado en C hace lo mismo!)
*Imaginemos al Windows como una maquina de rebanar embutidos. En la parte de arriba, tendremos al
embutido por rebanar, en el centro el proceso de rebanar, y en la parte de abajo las tajadas del embutido. La
parte por rebanar son las funciones que mandamos, que son procesadas al centro y retiradas del procesador
en la parte inferior de la analogía. Cuando hay mucho trabajo, el Windows mantiene en la parte de arriba las
funciones pedidas, que se ejecutaran en algun momento, cuando se desocupen las funciones que se ejecutan
en ese momento. Es decir, las funciones que invocamos NO se invocan en ese momento. Esta función le dice
al Windows: OK, espero a que termines de rebanar para continuar. ¿OK? De aqui dos conclusiónes:
1.- Windows procesa en batch nuestros requerimientos. No lo hace en linea.
2.- Tengo hambre.
CONTROLES : SINTAXIS
REDEFINE GET [ <og> VAR ] <mVar> ;
[ ID <Id> ] ;
[ <dlg: OF, WINDOW, DIALOG> <od> ] ;
[ <help:HELPID, HELP ID> <idhelp> ] ;
[ VALID <fvalid> ] ;
[ PICTURE <picture> ] ;
[ <color:COLOR,COLORS> <color1> [,<color2>] ] ;
[ FONT <fuente> ] ;
[ CURSOR <cursor> ] ;
[ MESSAGE <mensaje> ] ;
[ <update: UPDATE> ] ;
[ WHEN <when> ] ;
[ ON CHANGE <cambio> ] ;
[ <readonly: READONLY, NO MODIFY> ] ;
[memo]
El get, al igual que el get del Clipper DOS, nos permite editar variables de tipo alfanumérico. Todos los
atributos del get DOS son válidos, pero con el enriquecimiento de poder utilizar fuentes distintas (fuentes
gráficas).
Asi de facil!
El botón nos permite un control que se activará cada vez que se marque el mismo En pantalla, aparece como
un recuadro que simula un botón rectangular con un gráfico. Es un "switch" de activación de una función
(conocida como evento en los lenguajes visuales). Note que, por su naturaleza, este control no almacena
variables . Este control lo veremos a detalle en el capítulo de ventanas MDI.
El botón nos permite un control que se activara cada vez que se marque el mismo En pantalla, aparece como
un recuadro que simula un botón rectangular con texto. Es un "switch" de activación de una función
(conocida como evento en los lenguajes visuales). Note que, por su naturaleza, este control no almacena
variables .
El checkbox es un control que nos permite activar/desactivar una opción. Normalmente, en sistemas DOS,
cuando deseabamos selecciónar el sexo de una persona, escribiamos marque "S" o "N". Este checkbox
marcara con una "X" el recuadro si se activa. De alli podemos deducir que, por sus estados, la variable inicial
es logica. Para poder saber el estado de el objeto, existe una variable dentro de el, que es un codeblock,
llamada bsetget. Luego, para saber el valor del mismo, haremos eval(oc:bsetget) (.t. marcado, .f. sin marcar).
El control Combobox es un get con una variante: Nos permite desplegar una ventana (debajo del get) con una
serie de opciones (Que evidentemente estan en un array). Un caso tipo lo vemos al selecciónar una unidad de
disco en un diálogo. Existen a su vez variantes del combo, aquellas que nos permiten elegir una variable de un
array, o aquellas que nos permiten incluso introducir un valor en el get. Para saber el estado de el combo en
cualquier momento, existe una variable dentro del objeto, llamada bsetget. Para evaluarla, haremos :
eval(oc:bgetset). Esto nos indicara el item actual. Mas adelante veremos esto a detalle.
El meter es un control que nos mostrara una barra horizontal enmarcada que se desplaza de izquierda a
derecha. Es decir, es una barra de desplazamiento. Un caso típico es el avance de un proceso. No almacena
variables, pero grafica el trabajo que se realiza.
om : variable que contiene al objeto meter
actual : valor actual (de inicio)
total : valor total
id : puntero asociado al diálogo
od : diálogo sobre el cual se muestra
fuente : tipo de letra a utilizarse para mostrar proceso
prompt : texto a mostrar en la barra de desplazamiento
color1,color2 : colores del texto de la barra
color3,color4 : colores de la barra.
El listbox de un array es un control que nos permite selecciónar de una lista que se muestra en pantalla
uno/unos elementos de un array. la diferencia con un combobox es que el primero despliega una ventana y
permite un get, y en esta caso la ventana siempre esta desplegada y no hay get de por medio. Adiciónalmente,
esta opción permite selecciónar mas de un elemento, y permite displayar gráficos acompanando a los
elementos del array, por lo que es ideal para definir series (P.E.:Una serie de discos de red, local, diskettes,
cada uno con su BMP descriptivo).
Este listbox es lo que conocemos en DOS como un Browse/Tbrowse/DBedit, etc. Con él podremos hacer la
muestra tabulada de información que hace tan popular y amigables a los lenguajes XBase. Por su naturaleza,
este control no almacena variables. El listbox de Windows tiene una serie de ventajas, que posteriormente
podremos apreciar. (Registros de distintos colores, filtros, bitmaps en campos, encabezados que son botones,
etc).
ob : Variable que almacena al objeto listbox de archivos.
campo1,campo2 : Campos a mostrar en el Browse.
arrtamanos : Array de tamanos al iniciar el Browse
arrencabezados : Array de encabezados
id : Numero de puntero en el recurso
fcambio : Función que se activa al hacer un cambio de registro
frclick : Función que se evalua al hacer click derecho con el mouse.
fdobleclick : Función que se evalua al hacer docle click con el mouse.
od : Diálogo que contiene al Browse.
color1,color2 : Colores del Listbox
Esto nos permitira ver un browse con columnas de distintos colores. Visualmente no tendra punto de
compraracion. Pero, como es un browse en donde se evalua cada columna, sera mas lento que el listbox antes
descrito. Util en maquinas potentes, donde la presentacion visual sea importante.
NOTA: Esto nos permitira ver un browse con columnas de distintos colores. Visualmente será impactante.
Pero, como es un browse en donde se evalua cada columna, será mas lento que el listbox antes descrito. Util
en maquinas potentes, donde la presentacion visual sea importante.
El Scrollbar nos permite crear sobre nuestra ventana una barra de desplazamiento que si contiene una
variable, y puede ser alterada por el usuario. Este control sirve para selecciónar visualmente un valor
numerico de un rango. Este control, aunado a un get, es lo que conocemos como un Spinner, que al presiónar
la flecha arriba del get aumenta el valor numerico del mismo, y la flecha abajo lo hace decrecer. Un Scrollbar
puede ser horizontal o vertical. La forma de determinar la variable que contiene el Scroll es acudiendo a la
función del objeto: os:getpos()
El say es eso: el mismo say del DOS, pero que puede tener una fuente grafica que lo defina. Recordemos que
todo lo mostrado en Windows es una ventana, con sus atributos. Pues esto también es una ventana.
os : variable que contiene al objeto say
texto : texto a poner en el diálogo
picture : forma de mostrar el texto
id : numero del recurso
od : nombre del diálogo que lo contiene
color1,color2 : colores del texto
font : fuente del texto
El timer es una utilidad (no es propiamente un control) que nos permite activar un proceso cada determinado
tiempo. Esta es una gran utilidad, pues nos permite hacer un proceso periodicamente, programandolo una sola
vez.
ot : Variable que contiene al objeto timer.
intervalo : Cada cuanto tiempo se efectuara la función (centesimas de segundo).
facción : Función que se evalua.
od : Ventana que contiene al timer.
Un ejemplo típico puede ser:
local ow,ot
define window ow from 0,0 to 30,80 title "Mi titulo"
define timer ot interval 1000 action tone(1000,1) of ow
activate window ow on init (ot:activate())
ot:deativate()
ot:release()
return(nil)
Un bitmap es un gráfico que podremos pegar en nuestros diálogos. Desde el logotipo de una empresa, hasta la
información grafica de un producto. Incluso, podremos crear un marco para visualizar parte del gráfico, y
podremos desplazarnos para ver una porción del mismo. Podremos hacer Zoom del gráfico, etc.
El folder es un gran avance en la operación de ventanas. Nos permite activar varias ventanas, mostrando solo
una y escondiendo las demás, pero permitiendo accesarlas con una pestaña. Un caso típico lo encontraremos
cuando deseemos ingresar una gran cantidad de información, que no entra en una pantalla, pero que debe
aparecer a la vez. (Por ejemplo, la configuración del Word Windows 6.0 / superior). Por su característica, no
contiene variables a almacenar. Eso si, una variable importante a utilizar internamente en el sistema será el
array de diálogos que estan contenidos dentro del folder.
Controles - adendum
Lo que sigue a continuación no son propiamente controles, sino herramienta de apoyo a los controles.
Tool-Tip
El tool-tip nos permite poner una "etiqueta" a un control. Cada vez que pasemos sobre ese control y dejemos
unos segundos sobre el el mouse, mostrara la etiqueta.
La forma de definirlo, es definiendo esa propiedad en el objeto control que se desee: (Todos los controles que
tienen tool-tip, tienen el metodo "ctooltip").
local od,oc:={},mvar:={"Uno"},arritem:={"Uno","Dos","Tres"}
define dialog od resource "mirecurso"
redefine combobox oc[1] items arritem var mvar[1] id 101 of od on change tone(1000,1)
oc[1]:ctoooltip:="Combo-Box"
activate dialog od centered
Menús
Seleccione resource/new, y busque menu.
Dentro del editor de menus, en View marque la ultima opcion. Esto mostrara en que forma quedara su menu.
En "Item text" escriba el nombre de la opcion (El simbolo & mostrara el subrayado, que indica que la
combinacion [Alt][Letra] activara el Popup (Cada opcion horizontal), y que la tecla [Letra] activara el
menuitem (Cada opcion vertical). Cada opcion tiene un "item id", que el el puntero que vincula la opcion al
programa.
Al momento de definir el programa:
function mimenu(parametros)
local om
define menu om resource "menu" && Nombre con que se graba el menu en el resource
redefine menuitem men[01] prompt "" id 101 of om action comision(men[01],)
redefine menuitem men[02] prompt "" id 102 of om action usuario(men[02],ofo,oi)
redefine menuitem men[04] prompt "" id 106 of om action owp:end()
redefine menuitem men[18] prompt "" id 151 of om action owp:tile()
redefine menuitem men[19] prompt "" id 152 of om action owp:cascade()
redefine menuitem men[20] prompt "" id 135 of om action repo5(men[20],ofo,oi)
return(om)
CUALQUIER CONTROL
Una vez que tenemos estas definiciones, haciendo combinaciones entre ellas podremos hacer cualquier cosa
de las que hemos visto hasta ahora en Windows, con la misma presencia de cualquier herramienta visual.
Ahora, eventualmente desearemos usar un control que no tengamos (Un ejemplo de esto serian los gráficos
estadisticos). El Fivewin nos permite utilizar archivos VBX (Si, los mismos que usa Visual Basic!) para
expandir nuestra capacidad de utilizar controles. Usando VBX, el Fivewin queda abierto a usarse con
cualquier control que exista en el mercado. Pronto veremos el uso de los VBX, con lo que podremos utilizar
cualquier control. Asimismo, recordemos que el Fivewin tiene en su libreria una herramienta para crear
clases, con lo cual podremos crear nuestras propias clases, quitando límites a esta herramienta, y haciéndola
mas potente que otros lenguajes de programación visuales.
QUE ES UN DLL?
Poco antes mencióne que la filosofia de la programación en Windows proponía hacer los sistemas "data-
driven". Para conseguir ello, se hizo necesario aislar del programa los siguientes recursos del sistema:
- Gráficos (Bitmaps)
- Pantallas
- Constantes (Arrays, menus)
- Iconos
- Funciones comúnes
dejando el manejo de variables y procedimientos dentro del sistema.
Para poner todos estos recursos en un deposito común, se creo el archivo .DLL, que es un archivo capaz de
almacenar en su interior toda esta información (Estamos en la epoca en que C era el unico lenguaje de
programación para Windows!). Ahora, para poder manipularla se crearon una serie de utilidades, dependiendo
de la empresa: Microsoft lanzó junto al Visual C el AppStudio, un aplicativo para manipular DLL´s. Borland
lanzo para su Turbo C y su Borland C el WorkShop. Mucho después nace la programación Visual, que
almacena automáticamente esta información en archivos DLL y/o RC a través de un IDE completo. (RC es
como un DLL, pero en ASCII, que almacena la información binaria como direcciones, como c:\raiz.bmp). El
archivo DLL es binario, y almacena en su interior a todos los archivos. Luego de haber conocido al WorkShop
y al Appstudio, debo recomendar, y por mucho, al WorkShop. Es mucho mas completo y "visual".
Volviendo al tema, entonces nosotros nos preocuparemos por escribir un recurso en el WorkShop, y en
nuestro programa haremos referencia al mismo. Tal como lo hemos visto en el capítulo anterior:
Archivo
Nuevo Proyecto: Nos permite crear un nuevo recurso. Notemos como, el manejador de recursos, no nos
permite crear un nuevo DLL! Pero no es preocupante: lo que sucede es que el WorkShop para funciónar viene
con archivos DLL, y bastaba con copiar uno para utilizarlo. Nosotros, utizaremos uno de todos los que vienen
con los ejemplos del Fivewin.
Abrir Proyecto:Nos permite abrir un archivo que contenga recursos. Ojo, no mencióno solamente DLL´s,
pues en Windows los recursos los podremos grabar en una serie de componentes (Entre ellos, el mismo
ejecutable!. Esto desvirtua el principio del data-driven, pero...) Al selecciónar la opción, podremos definir el
nombre del archivo (en un get), y/o el tipo del archivo (en un combobox). Si expanden el combo veran todos
los tipos de archivos que pueden almacenar DLL´s.Los siete primeros son recursos propiamente, y luego
vienen los ejecutables (Drivers, exes, vbx´s, etc.). Antes de editar un ejecutable, esten seguros de hacer una
copia de resguardo del mismo. Por el momento, con esta lección les he enviado un DLL. Procedamos a
abrirlo.
Grabar proyecto: Nos permite almacenar el proyecto. Utilize esta opción con cierta frecuencia cuando
trabaje, pues no hace resguardos automaticamente, y en alguna oportunidad podrian perder lo hecho, por una
falla del Windows.
Grabar como: Esto nos permite grabar el proyecto con un nombre distinto al original
Anadir al proyecto: Esta opción permite añadir un recurso que este rabado fisicamente en disco (Por
ejemplo, un BMP que deseamos meter en un DLL).
Remover del proyecto: Esta opción permite retirar del proyecto algun recurso no usado.
Instalar libreria de control: El WorkShop permite instalar algunas librerias de control. Basicamente un VBX
o un DLL que deseemos utilizar en nuestros aplicativos. Una vez que llamemos a una, este aparecera en la
sección de herramientas del generador de controles.
Remover libreria de control: Permite retirar las librerias de control cargadas con la anterior opción.
Note que al referirnos a un dato, lo hacemos en forma global. Y es que un dato puede ser, segun el recurso en
que estemos trabajando, un bitmap, un control, texto, etc.
Recurso
Nuevo: Permite definir un nuevo tipo de recurso. Una vez que selecciónamos la opción, apareceran los tipos
de recurso que podemos definir.
Editar: Permite editar un recurso. (ta cual si presiónamos enter).
Editar como texto: Cada recurso se puede almacenar como un dato binario (DLL), o como una cadena de
texto (RC).
Ver: Permite ver el recurso.
Grabar recurso como: Permite grabar el recurso como un archivo. Recordemos que un DLL contiene
distintos tipos de archivos, por lo que también puede grabar distintos tipos de archivos.
Renombrar: permite cambiar de nombre al recurso con el que estamos trabajando.
Opciones de memoria: Modo de cargar/descargar de memoria un recurso. No tocar.
Lenguaje: Permite seleccionar el lenguaje que usará al recurso DLL.
Mover: Permite mover un recurso a otro.
Identificadores: Permite definir identificadores.
Ver
Por tipo: Permite ver los recursos por tipo (Bitmaps, Diálogos, etc)
Por archivo: Permite ver los recursos segun el archivo que los contiene.
Mostrar item: Mostrara los detalles de cada recurso.
Mostrar tipos sin usar: Muestra todos los tipos de recursos, aun los que no se esten usando
Prevista vertical: Permite dividir ver en forma vertical la pantalla, una con la prevista.
Prevista Horizontal: Permite dividir ver en forma vertical la pantalla, una con la prevista.
No mostrar Prevista: No muestra una prevista
Ventana
Pegadas: Permite ver las ventanas calzando (ajustandose a) la pantalla.
Cascada: Permite ver las ventanas una detras de otra, en forma de cascada.
Ayuda
Muestra los ítems de ayuda del Resource WorkShop.
Ingrese al WorkShop
[Alt-V][V] (View Vertical del menu View) Ver prevista en forma vertical
[Alt-F][O] (Open del menu file) Abrir archivo DEMO.DLL
Utilize las flechas arriba-abajo para ver los recursos dentro de este DLL
[Alt-F][S] (Grabar) Acostumbrese a grabar a menudo! Sobre todo porque esta desarrollando en Windows, y es
probable que Ud. haga algo que inestabilize al sistema operativo!
Editar un Bitmap
Ubiquese sobre el Bitmap (En el ejemplo: Numero 1305: Ese es el puntero!) Presióne Enter. Hagale alguna
manchita (cualquier cambio) y presióne [Ctrl][F4] para grabar el cambio. Si Ud. esta acostumbrado a utilizar
otro graficador, desde dentro del recurso: [Alt-E][S][Alt-E][C]Seleccióna y copia al clipboard el bitmap.
Peguelo y retoquelo en la otra herramienta, y paselo al DLL con la misma tecnica. [Alt-E][P] pegar.
[Alt-F][S] Grabe el recurso.
Editar un diálogo
Ubiquese sobre el diálogo que aparece con el nombre demo, y presióne Enter. Le aparecera en la pantalla el
diálogo. Presiónando tab o haciendo click podra ubicarse sobre cualquier control existente. Si hace doble click
sobre la parte superior de la ventana de diálogo (el titulo), podra definir el tipo de ventana con la que esta
trabajando (Mas adelante veremos como sacarle provecho a ello). Por el momento, lo que puede Ud. hacer es
selecciónar el tipo de "font" (letra) del diálogo. Aqui una observación importante: Las fuentes que estan en su
maquina apareceran para selecciónarse, pero NO SON NECESARIAMENTE LAS MISMAS QUE SU
CLIENTE TIENE! (El ponerlo en mayusculas no significa que estoy gritando, pero si alguno aprende a gritos,
eso fue un grito!) caption es el nombre del diálogo, y menu el menu de este diálogo (Si deseamos que tenga
alguno). La clase nos permite definir como se vera el diálogo en pantalla. Por defecto tenemos 2 (Es mas
sencillo no definir clases de diálogos, al ajustar luego los controles). Presiónemos OK y regresemos al dialog
en si. Veremos ahora los controles. El primero es el botón gráfico . Vea en la parte inferior de su pantalla el
ID: 305 (recuerde el bitmap 1305. Este botón tiene el numero 305. es decir, si le sumamos 1000 veremos el
bitmap que muestra el gráfico. Sumando 3000 y 5000 veremos cuando esta selecciónado y cuando esta
pulsado, respectivamente. Conclusión: Cree los bitmaps del 1201 al 1800 (Los primeros 1000-1100 seran
controles que el WorkShop crea por defecto. Cuando creamos un cotnrol se crea desde el numero 101 ena
delante. Sería muy molesto crear el bitmap 1109 y que luego nos demos cuenta que se cruza con el get 109
que el WorkShop numero). Presionando Enter veremos sus características, que por el momento no
afectaremos. Pulse Esc. El segundo control el el Browse. En realidad, debemos definir los controles en 2
grupos: los normales (que e WorkShop trae dentro de su ejecutable, y que podemos ver en el menu Control) y
los "redefinidos" por nosotros, que son controles que apuntaran a las clases que manejamos en nuestros
programas! Esto es, el control Browse (Presiónen Enter) tiene una clase definida, llamada "twbrowse". Esta es
la clase que tenemos en el Fivewin. Normalmente, trabajaremos con los controles que vemos en este diálogo
demostrativo. pero si derearamos trabajar con una clase (por ejemplo, folder) deberemos crear en el menu
control una clase custom, a la cual le definiremos como nombre "tfolder". La desventaja de este tipo de
controles es que, como no pertenece al WorkShop, no podremos hacer una simulación de su comportamiento
(presiónando en la barra de herramientas el botón Test). El botón "1,2" nos permite definir en que orden
deseamos que se mustren nuestros controles. De aqui podremos, copiando y pegando, crear practicamente
cualquier control.Con el mouse, haciendo click sobre un control, podremos manipularlo: El mouse ubicado en
la esquina de un control permite definir el tamano de un control, la tecla del lo elimina. El botón derecho
permite duplicar el control (pueden también cambiar tamano y posición, pero arrastrandolo con el mouse es
mas sencillo). Al duplicar, definiremos la cantidad de veces que deseamos multiplicar el control, y la distancia
entre ellos, tanto en forma vertical como en forma horizontal. Recuerden pulsar [Ctrl-F4]para grabar y
retornar a la pantalla anterior.
Crear un cursor:
Ubiquese sobre el cursor (En el ejemplo: Numero cursor: Ese es el puntero!) Presióne Enter. Hagale alguna
manchita (cualquier cambio) y presióne [Ctrl][F4] para grabar el cambio. Note que en el caso de los cursores,
estos solo soportan dos colores, y la opción de mostrar regiones "transparentes". Igualmente, en el menu
Cursor/"Set Hot Spot", podremos definir cual es la "punta de la flecha del puntero", o la zona exacta a donde
apunta el puntero del mouse. Igualmente, en Cursor/Test, podremos probar el resultado de nuestro cursor en
pantalla.
Editar un ícono
Ubiquese sobre el ícono (En el ejemplo: ícono: Ese es el puntero!) Presióne Enter. Hagale alguna manchita
(cualquier cambio) y presióne [Ctrl][F4] para grabar el cambio. Si Ud. esta acostumbrado a utilizar otro
graficador, desde dentro del recurso: [Alt-E][S][Alt-E][C]Seleccióna y copia al clipboard el bitmap. Peguelo y
retoquelo en la otra herramienta, y paselo al DLL con la misma tecnica. [Alt-E][P] pegar. Note que los iconos
pueden ser de distintos tamanos y dimensiónes (Icon/"Size and atributes"): Utilize de 32 x 32 pixels, y a 16
colores, que es el estandar. (Los de 256 colores en SVGA impresiónan, pero en VGA decepciónan). [Alt-F][S]
Grabe el recurso.
Si bien este parrafo ha sido largo, ha resumido (creo yo) la funciónalidad del WorkShop. Un poco de practica,
alguna duda resuelta, y ya estamos en capacidad de programar en Fivewin.
En el siguiente numero veremos otros comandos del WorkShop. Y en adelante nos concentraremos ya no en el
modo de programar, sino en el modo de aprovechar el Fivewin.
function main()
local ow,oi
set resources to "demo.dll"
loadlibrary("bwcc.dll")
define icon oi resource "ícono"
define window from -2,-2 to -1,-1 title "Primer ejercicio" icon oi
activate window ow on init (midiálogo(ow))
freelibrary("bwcc.dll")
set resources to
return(nil)
Escribir el bli.lnk:
fi x
out x.exe
PACKCODE
PACKDATA
DEFBEGIN
name Miprograma
description 'Miprograma'
exetype Windows 3.1
code moveable discardable preload
data preload moveable
stacksize 10000
heapsize 1024
segment 'PLANKTON_TEXT' nondiscardable
segment 'EXTEND_TEXT' nondiscardable
segment 'OM_TEXT' nondiscardable
segment 'OSMEM_TEXT' nondiscardable
segment 'SORTOF_TEXT' nondiscardable
segment 'STACK_TEXT' nondiscardable
DEFEND
NOBELL
Compilar con :
clipper x /n
Enlazar con Blinker @bli
En el WorkShop, duplicar el recurso diálogo (Ponerse sobre el y elegir duplicar del menu) ponerle de nombre
"mirecurso". Entrar en ella, borrar todos los controles, a excepción de el get y el botón texto.
Duplicar el botón texto. Selecciónar el control get, pulsar Enter y cambiar el numero a 101. Hacer lo mismo
con los botones (numeros 102 y 103), de la barra de herramientas "1,2" poner el orden deseado. [Ctrl-F4]
graba el recurso y [Alt-F][S] graba el DLL. Cualquier problema escribirme.
*Estos controles son “públicos”. Cualquier programa de Borland los trae, si no es que ya estan en sus
máquinas actualmente. En caso que el programa no funcióne, instálelos.
PROGRAMACIÓN ORIENTADA A OBJETOS: DESTRUYENDO UN MITO
Nota: No pretendo con esto dar una lección de analisis/diseno/programación orientado a objetos: Lo que
intento es mostrar mi apreciación personal del tema. Cualquiera puede discrepar de mis opiniones (algunas
quiza muy sórdidas) pero que de otro modo no permitirian la facilidad del entendimiento. Luego de haber
leído varios libros al respecto, aún hay cosas a las que no les encuentro una explicación adecuada, que
permita a TODOS entender que es OO (he tenido que conocerlas verbalmente, por amigos, o textos sueltos).
Mas adelante podremos invocar una función del array, cambiar una variable, etc. Como un array, podemos
tener varios definidos a la vez (esto es conocido como instancias de objetos).
La ventaja?
Podemos crear un array (objeto) con las características de cada objeto -entidad- que conforme nuestro
sistema.
La ventaja?
Orden
La ventaja?
Código limpio, fácil de mantener.
PSEUDOCÓDIGO DE UN OBJETO.
crear clase usuario
variables internas:
*Solo son cambiadas por una función dentro de esta clase
claveusuario:="000001"
nombreusuario:=usuario->nombre
administrador:="Si"
variables externas:
*Cualquier función las cambia
funciones internas:
*Solo son invocadas por una función dentro de la clase
anadeusuario(arraydedatos)
reemplazausuario(arraydedatos)
retirausuario(códigodelusuario)
funciones externas:
*Cualquier función las invoca
ubicausuario(códigodelusuario)
editausuario()
claveok(claveusuario)
Fin
Sencillo, no? Pues ya esta creada la clase usuario. Las funciones son conocidas como
mensajes/métodos/comportamientos y las variables como atributos/características. Noten que, en adelante,
1.- Todo lo que se haga con un objeto, se hará en un mismo programa.
2.- Para otro sistema que necesite la entidad (lease objeto) usuario, usted usará este código. (A esto se le llama
reusabilidad). El nuevo sistema necesitará nuevas variables/funciones (P.E.: edad del usuario). Luego, en vez
de "chancar" nuestro código, (que es lo habitual al escribir en forma estructurada) añadimos una nueva
función. De este modo, ampliamos el horizonte de nuestras clases. Y la compatibilidad hacia atrás se mantiene
inalterable.
MODELOS DE LA REALIDAD
La computadora piensa como nosotros, y no nosotros como la computadora. Nuestras funciones EMULAN
EL PENSAMIENTO HUMANO.
Es decir, cuando hagamos un programa que da altas y bajas a clientes, ya no haremos la función clie_001(),
que muestra la ventana, edita los datos y los graba y clie_002(), que muestra la ventana, muestra los datos y
los retira, sino que haremos la función añade() y retira(). añade() invocará a la función pintaventana(),
editadatos() y graba(). Cada función hará una y sólo una acción.
LEVANTAMIENTO DE DATOS
A continuación veremos un caso muy interesante que nos muestra, desde el inicio, la forma en que toma vida
un sistema, vía el análisis orientado a objetos.
Un cliente pide mercadería, se verifica que exista en el almacén, y si hay se retira la mercadería del
almacén y se le despacha la mercadería, se genera una factura y se paga la factura.
Sabes (o recuerdas) lengua? (Si, del Colegio!) Pues prepárate para una lección:
Cada clase será un sujeto y cada verbo un mensaje. De este modo el usuario hace el análisis por nosotros, (y
lo firma dándolo por aceptado). Si el sistema falla mas adelante, él hara el análisis por nosotros! -La factura
no recalcula, cuando genero un nuevo ítem- nos dirá el usuario. Si hemos seguido el esquema, tendremos una
función recaulculafactura(). (Si no existe, tenemos una nueva función que escribir, no estamos modificando el
código original). Eso es analisis/diseño/programación OO!
EL MODELO ESPIRAL
El modelo espiral propone cuatro etapas (Dibuje una cruz). Cada etapa (c/u de las areas creadas), en sentido
horario, será: ANALISIS/DISENO/PROGRAMACIÓN/IMPLEMENTACIÓN
Dibujemos un espiral en sentido horario que termina en el centro de la cruz . Ud. tendrá algo asi como:
Esto que significa: Cuando le pidan a uno un sistema, desarrollara el ciclo analisis/ diseño/ programación/
implementación, acercándose cada vez mas al centro, que es el fnal del proyecto. Iremos añadiendo
funciones/variables a nuestras clases. Lo interesante, es que el sistema irá funciónando por etapas. Por
ejemplo, ya podrán utilizar facturas en soles, mientras las facturas en dólares aun no.
Otra gran ventaja será que el resultado de las clases (cada función) será el manual de procedimientos y
funciones de la empresa. Es decir, si manana cambia de lenguaje de programación, el analisis YA ESTARA
HECHO. Solo se necesitaran programadores, no analistas. Usted se ira de la empresa, pero este
esquema/manual permanecera.
Actualmente, yo no creo clases para mis entidades. Hago mis programas y funciones, pero con la filosofia
antes menciónada (cada función es una acción). Pasarla a objetos no me demandara esfuerzo. Pero si tengo
clases creadas para acciones críticas. Un lenguaje de programación no necesita ser orientado a objetos para
hacer programación orientada a objetos.
Nota: El Visual Basic 5.0 es un lenguaje eminentemente orientado a objetos. Clipper es desde hace años
orientado a objetos (vía classy). Pronto los seguirán los demás lenguajes. Todo lenguaje está convirtiéndose
en orientadoa objetos.
Hace un momento mencióné al objeto como el array con variables de una entidad (usuario, en el ejemplo).
¿Que tal un array con las variables de entorno del sistema? Vale. ¿Que tal si ese array es manipulable desde
afuera del sistema? Vale. ¿Y que tal si ese array contiene derivaciones logicas.? (vender_al_crédito=no) Vale.
Pues una vez pensé esto, y desde entonces lo utilizo con mucho éxito. En la libreria lib5.zip encontrarán un
programa TS.INI con un grupo de funciones que utilizo para tal propositro. Al iniciar el sistema, declaro una
variable publica arrini, y la cargo con el archivo .INI respectivo. Por ejemplo:
[inifonts]
roman|10|20|n
roman|10|20|s
[finfonts]
[colores]
colorbrowse=255|255|192
[inireporte1]
cabecera=GFTP S.A. REPORTE DE EMPLEADOS DE LA EMPRESA, POR ORDEN DE SUELDO
orden=sueldo
barrido=código+[ ]+nombre+[ ]+dirección+[ ]+transform(sueldo,"999,999.99")
[finreporte1]
[parametros]
impresora=LPT2
numerodecopias=4
administrador=Grenville
impuesto=18.00
máximodescuento=10.50
path=c:\mipath\
temp=c:\temp\
[flujo de facturas]
dólares=si
soles=si
crédito=no
tarjetacrédito=si
canje=no
[coordenadas]
ventanaprincipal=000|000
...
Noten que aquí almaceno las características del entorno del sistema: Si vendo al contado y/o al crédito, en
soles y/o dólares, si aceptan tarjetas de crédito, valor de descuento máximo, etc. De este modo, mi clase para
cualquier sistema de facturación es la misma, y los mensajes (funciones) se invocan cuando la variable de
entorno lo permite. De este modo:
-Cuando hagan un sistema de facturación, llegara un momento en el cual la implementación del sistema
dependerá únicamente de mover los "switchs" adecuados.
-Llendo un poco mas alla, he llegado a darle "inteligencia" a mis sistemas: El usuario decide si vende o no al
crédito, el sistema almacena las coordenadas de las ventanas en que quedaron, los colores, las fuentes son
configurables... Es decir, parece un sistema "profesiónal" (Y es que es un sistema profesiónal). He llegado a
hacer sistemas que son "interpretes" de archivos *.INI, es decir, he creado "plantillas" de trabajo que mis
sistemas leen, y son capaces de interpretar. (Un sistema de volcado de información, donde las estructuras de
archivos estan en la plantilla, los campos a leer, las validaciones, etc).
MANIPULACIÓN DE ARCHIVOS
Antes también mencióne que tengo una clase .DBF veamos este ejemplo:
DD.INI
[cliente.dbf]
cliente|c|006|0
nombre|c|040|0
*indice*
cliente|cliente|cliente.cdx
upper(nombre)|nombre|cliente.cdx
[cliente.dbf]
A.PRG
local arrfiles:={"cliente"}
public arrini,oa
arrini:=tsleeini("misistema.ini")
oa:=dbf():new()
a0(tsgetini("path",arrini,""))
if oa:abre(arrfiles)=0
...
else
msgalert("No se pueden abrir archivos!. Reintentar","FATAL")
endif
oa:cierra(arrfiles)
-Si no existe el archivo cliente.dbf, lo creara en el path definido en MISISTEMA.INI, si no existe el índice, lo
creara en el path definido en MISISTEMA.INI.
-Este el el principio de un dicciónario de datos, que para mi fue suficiente, pero que puede seguir creciendo!
-Noten que esta clase esta hecha para trabajar con SIXCDX, pero con muy pocos cambios puede trabajar con
otro tipo de índices (si pueden conseguir el SIXCDX, háganlo. Es muy sólido, y tiene muchas ventajas sobre
otros indices, aun DBFCDX!)
Asimismo, el tipo de informacíon que se puede pasar a través del Clipboard tiene algún formato específico:
Puede ser no sólamente texto, sino puede ser también un archivo gráfico. Actualmente el Clipboard es poco
utilizado por el programador, pues las aplicaciones más avanzadas en Windows permiten migrar cualquier
tipo de información directamente, vía DDE u OLE. En caso de migrar texto, el Fivewin permite, en un control
tipo GET, utilizar el botón derecho del mouse para hacer copiado/pegado de texto.
Donde:
oclp: Es el nombre de la variable que almacenara a objeto clipboard
ownd: Es el nombre de la variable ventana activa.
function main()
local ow,oc
define window ow from 0,0 to 10,50 title "Prueba del Clipboard"
define clipboard oc of ow
activate window ow on init probar(ow,oc)
return(nil)
Cuando hacemos un programa pequeño, generalmente nos bastan dos o tres ventanas para ejecutarlo. Pero,
cuando no se trata de un programa, sino de un sistema, y deseamos poder poner en pantalla a veces mas de
una ventana por vez, se pierde estética y funciónalidad. Mas aún, cuando de nuestro aplicativo, que tiene tres
o cuatro ventanas abiertas, pasamos a un Word (otra tarea), vemos con desazón que nuestras ventanas no
guardan la estética y orden de las ventanas de Word.
La solución es MDI:
MDI nos permite crear una ventana principal (Padre - como si fuera una pantalla), y al crear nuevas ventanas
(hijas), esten limitadas a aparecer DENTRO de la ventana padre. De ese modo, Podemos tener varias
"pantallas", y podemos hacer trabajar en una mitad de pantalla al Word, y en otra mitad a nuestro sistema, sin
preocuparnos que al abrir nuevas ventanas tapen a algun otro aplicativo. (Eso si, solo puede haber una ventana
padre por ejecutable).
Otra ventaja adiciónal, es la capacidad de abrir a la vez varias ventanas dentro de nuestra ventana Padre,
acercándonos más a la multitarea (Ventanas modeless, o ventanas que no detienen el flujo del sistema. Una
vez abierta la ventana, el sistema sigue ejecutandose, no se detiene en el activate dialog, sino que continuan
ejecutándose las lineas de código despues del activate...). Cuantas veces hemos necesitado, al crear una nueva
factura, crear un nuevo cliente, y hemos tenido que perder los datos ya ingresados, para ir a la pantalla de
clientes.
Pero, yo básicamente trabajo con diálogos, no con ventanas (recordemos que las ventanas no soportan
recursos, es decir, programación visual)
La solución es un truco muy sencillo: (Es un truco utilizado en todos los lenguajes de programación, solo que
poco documentado).
Luego de crear la ventana owh, le pedimos que cada vez que obtenga el control esta ventana se la de a un
diálogo:
owh:bgotfocus:={||od:setfocus()}
y definimos un diálogo (con los controles aqui, en forma visual), que este "pegado" a la ventana hija:
define dialog od resource "truquito" of owh (añadimos las palabras of owh)
La clausula nowait, permite que las siguientes lineas de código se sigan ejecutando. Asi se ejecuta el activate
window. El mensaje move(0,0), hará que la esquina superior izquierda del diálogo coincida con la de la
ventana que la contiene.
Ejemplo:
function main()
public owp
arrini:=tsleeini("ejemplo.ini")
loadlibrary("bwcc.dll")
set resources to "ejemplo.dll"
define window owp from 0,0 to 30,80 title "demo" mdi menu mimenu() menuinfo 1
set message to "En MDI tengo una barra de texto!" clock date keyboard
activate window owp
freelibrary("bwcc.dll")
set resources to
return(nil)
define window owp from 0,0 to 30,80 title "demo" mdi menu mimenu() menuinfo 1
menuinfo 1: implica que en la primera columna del menu aparecera una relación de las ventanas que esten
abiertas dentro de nuestra ventana MDI.
set message to "En MDI tengo una barra de texto!" clock date keyboard
Significa que en la ventana MDI aparecera una barra mostrando el reloj, la fecha y el estado del numlock,
capslock, Insert. (Tal como el Word muestra en la parte inferikor de su pantalla MDI padre).
local ow,mdi1:=tsstrarr(tsgetini("mdi1"),"|")
Tenemos definida una variable de ejemplo.ini:
mdi1=TITULO DE LA VENTANA|000|000
Donde 000|000 son las coordenadas de la ventana
activate window ow on init ow:setsize(od:nwidth,od:nheight) valid cerrar(ow,men,mdi1)
Pongo cualquier tamano de ventana. No me interesa, pues mi diálogo será quien defina realmente el tamano
de la ventana. Al ingresar al modulo, desactivo la opción del menu que lo invoco, y al salir del modulo (como
es modeless, debe estar como una acción al salir, no a continuación del activate!) lo reactivo. La función
cerrar almacenara las coordenadas de la ventana. De ese modo, al ingresar mañana al sistema, la ventana se
abrira donde se cerro!
arrini:=tsgraini("ejemplo.ini","mdi1",mdi1[1]+"|"+coor)
Grabo las coordenadas actuales de la ventana! El titulo de la ventana esta en el ejemplo.ini
Poco a poco, vemos como podemos ir haciendo cada vez mas profesiónal nuestra aplicaciones, con
presentaciones que no envidiaran a ningun otro lenguaje!
Muy Importante: En el Resource WorkShop, el diálogo que se genere para "colgarse" a una ventana hija
MDI, debe tener los siguientes atributos (Docle click sobre la ventana):
caption : En blanco
Window type :Child
Frame style : No border
Dialog style : (ninguno marcado)
El poner atributo child hara que se cuelgue a nuestra ventana, el quitar caption y noborder, permiten crear un
rectángulo sin bordes, necesario para dar la impresión que ambas son una sola ventana.
ENLAZADO A UN DDE
Un DDE (Dinamic Data Exchange, o enlace dinamico de datos), nor permite comúnicar aplicaciones
Windows. Por ejemplo, cuando tenemos un valor en Excel, que deseamos copiar a nuestro aplicativo,
copiamos la variable al Clipboard, y la pegamos a nuestra aplicación. Esto tiene dos limitaciones:
a. Debemos realizar el proceso manualmente. (No podemos automatizarlo)
b. Al ser un proceso manual, en forma repetitiva puede ser tedioso.
El DDE nos permite, desde nuestra aplicación, invocar a otra aplicación que esté trabajando, y pedirle que
ejecute una instrucción. (Por ejemplo, entregarnos el contenido de la celda Excel, o llenar una celda Excel con
una variable de nuestro sistema).
El DDE es una herramienta muy poderosa, pero tiene limitaciones: La mas importante es que solo podemos
invocar enlaces DDE que el otro aplicativo tenga definido. (Es decir, dentro del Excel, estan definidas las
funciones que se pueden invocar). Por ende, dependemos que exista la función, y que además exista
documentación de los servicios DDE para poder realizar el enlace en forma exitosa.
Por otro lado, no siempre vamos a desear hacer un enlace para cambio de datos: Podemos hacer un enlace
para pedir una acción específica. En el siguiente caso, examinaremos el uso del DDE para pedirle al program
manager (Es un ejecutable, progman.exe) que cree los grupos e iconos de trabajo de nuestro aplicativo a
instalar.
Sintaxis:
DEFINE [ DDE | LINK ] <oDde> ;
[ SERVICE <cService> ] ;
[ TOPIC <cTopic> ] ;
[ ITEM <cItem> ] ;
[ VALID <uEnd> ] ;
Donde:
Nota:
(Por lo general, cada aplicativo que tenga enlaces DDE lo tendra documentado en su archivo Help, o en el
manual del mismo).
Notemos ademas que, para activar un enlace DDE entre dos aplicaciones, ambas deben estar trabajando.
INSTALACIÓN DE SISTEMAS
Eventualmente, y una vez que terminemos de hacer un sistema, vamos a desear/necesitar hacer un programa
instalador, de modo tal que el usuario final tome su diskette, lo inserte en su PC, y desde el administrador de
archivos/explorador ejecute el comando instalar.exe. El sistema deberá encargarse de hacer la instalación. Por
experiencia personal, la forma más sencilla de hacer este instalador es creando una rutina dentro del mismo
sistema que estemos escribiendo. De ese modo estaremos entregando un solo ejecutable, que es importante,
en la medida que el aspecto crítico es el espacio limitado de un diskette. Normalmente, un sistema terminado
en Fivewin, y enlazado con el blinker 4.0 (con compresión), nos entregara un ejecutable de unos 400 Kb.
Adiciónalmente, necesitaremos entregar al cliente los archivos ctl3dv2.dll, bwcc.dll, el *.dll de nuestro propio
sistema y los archivos *.ini. (Eventualmente un archivo de ayuda en windows *.HLP)
Es decir:
miexe.exe 400 Kb
bwcc.dll 164 Kb
ctl3dv2.dll 027 Kb
Esto nos deja 800 Kb para archivos *.dll, *.ini y *.hlp propios. Es espacio más que suficiente (Si no nos
excedemos con los gráficos).
La rutina de instalación levantará un instalar.dll, que contiene lo básico para la instalación. (La ventana de
diálogo de selección de directorio, creada con Resource WorkShop, pero desactivando el "use ctl3dv2.dll"
(Esto, porque las PC´s pueden NO tener previamente instalado este dll en ellas. Este es un dll que se carga al
iniciarse el windows. El bwcc.dll se carga al cargar el sistema).
INSTALAR.PRG
#include "fivewin.ch"
function instalar()
local ow
if okfiles()
set resources to "instalar.dll"
define window ow from -2,-2 to -1,-1 title "INSTALACIÓN - FRACCIÓNAMIENTO"
activate window ow on init logica(ow)
ow:end()
set resources to
endif
return(nil)
Podrán apreciar que faltan rutinas que verifiquen que haya acceso de escritura (En caso de redes).
Supuestamente, en la pantalla de instalación, indico que se deben tener los atributos necesarios, el espacio
suficiente en disco duro, etc.
REPORTES - LA MAGIA DEL REPORTE EN CA-CLIPPER Y WINDOWS .
Uno de los grandes paradigmas que tuve cuando ingrese al mundo del Windows fue: Como se manejara un
reporte en Windows? (Con dibujos, lineas, fuentes "true type", etc.). Pues el mito lo acabaron de un porrazo
cuando me mostraron el primer ejemplo. En general, la lógica de creación de un reporte en Windows es
sencillísima:
-Creo una página en blanco (Como si fuera un archivo sin datos)
-Lleno de valores la página (Puede ser de abajo a arriba. Recuerden que estoy lenando una página en blanco.
Como no ha ido aun a la impresora, no hay problema del orden en que mande las cosas, ni si estan o no
superpuestas). Estos valores pueden ser fotos, textos, líneas, etc.
-Envio la página a la impresora.
-Borro la página.
(La creación, envio a impresora y borrado de página lo hace el Fivewin automaticamente).
Notemos ademas que la página a imprimirse es un archivo. Por ende, podemos verlo por pantalla, lo que nos
permite hacer una presentación preliminar del mismo, tipo WYSIWYG.
Por otro lado, como es el Windows el que administra la impresora, no importa que tipo de letra, color o figura
enviemos a la impresora. Nosotros solo diremos: "quiero imprimir con letras verdes grandes mi nombre". El
Windows hará el resto.
Sintaxis:
REPORT [ <or> ] ;
[ TITLE <Titulo, ...> [< LEFT | CENTER | CENTERED | RIGHT > ] ];
[ HEADER <encabezado, ...> [< LEFT | CENTER | CENTERED | RIGHT > ] ];
[ FOOTER <pie, ...> [< LEFT | CENTER | CENTERED | RIGHT > ] ];
[ FONT <fuentes, ...> ] ;
[ PEN <pen, ...> ] ;
[ < SUMMARY > ] ;
[ < FILE | FILENAME | DISK > <nombrefile> ] ;
[ < NAME | RESNAME | RESOURCE > <recurso> ] ;
[ < TO PRINTER > ] ;
[ < PREVIEW > ] ;
[ TO FILE <afile> ] ;
[ TO DEVICE <adevice> ] ;
[ CAPTION <nombrerepo> ]
GROUP [ <og> ] ;
[ ON <grupo> ] ;
[ HEADER <encabezado> ] ;
[ FOOTER <pie> ] ;
[ FONT <fuente> ] ;
[ < EJECT > ]
ENDREPORT
Nota: Todos los programas que generen reportes deberán tener en el encabezado la referencia al header:
include "report.ch". Por otro lado, si deseamos hacer presentación preliminar, debemos tener en el directorio
del sistema al archivo preview.dll que viene con el Fivewin.
use cliente
go 20
*Abrir archivo. Llevar puntero de donde sea necesario.
report or title "Mititulo" header "Uno","Dos" preview caption "Mi reporte!"
*Crear el reporte. Deseo ver en pantalla el preliminar.
column title "PRIMER CAMPO" data cliente->nombre size 60 shadow
column title "SUELDO" data cliente->sueldo picture "999,999.99" total
*Definir la(s) columna(s)
end report
*Fin de definición del reporte
activate report or while cliente->(!eof()) on startpage ponencabezado()
*Activo reporte. El skip de cliente será automatico. (Pero deberemos tener como alias activo cliente!).
Eso es todo!
Mas adelante veremos algunos ejemplos de reportes e la practica.
Incluso, veremos que hacer cuando este esquema de reportes no satisface las necesidades de nuestro reporte, y
utilizamos una tecnica propia de impresión, muy util.
function setea(ovbx)
local buffer:="",tab:=chr(9)
mifile->(dbgotop())
while mifile->(!eof())
buffer+=alltrim(str(mifile->numero))+tab
mifile->(dbskip(1))
enddo
buffer:=substr(buffer,1,len(buffer)-1)
ovbx:datareset:=1
ovbx:graphtytle:="Mi Demo"
ovbx:mquickdata:=buffer
ovbx:drawmode:=2
return(nil)
Qué es Drag&Drop?
Drag(Arrastrar)&Drop(Soltar)
En Windows es común ver que algunas utilidades (El administrador de Archivos en Windows 3.11, y la
papelera de reciclaje en Windows 95) nos permiten tomar algún elemento, hacer click sobre él, y sin soltar el
botón del mouse "arrastrar" el elemento y soltarlo. En Fivewin, esta técnica se ha expandido, de modo tal que
virtualmente cualquier control permite el arrastrar y soltar un elemento. Para ello basta con definir los
siguientes codeblocks:
ocontrol1:bdragbegin:={|nrow,ncol,nkeyflags|setdropinfo(ocontrol)}
ocontrol1:odragcursor:=ocursor
ocontrol2:bdropover:={|ocontrol1,nrow,ncol,nkeyflags|mifunción(ocontrol1,nrow,ncol,nkeyflags)}
De ese modo, el control ocontrol2 recibirá el parámetro del control que lo generó. El primer control deberá
tener como estandard el codeblock arriba indicado. El cursor lo generamos en el Resource WorkShop.
Ejemplo:
define cursor oc resource "arrastra"
define button ob[1] id 101 of od && Botón de borrar registro!
redefine listbox ol fields id 110 of od
ol:bdragbegin:={|nrow,ncol,nkeyflags|setdropinfo(ol)}
ob[1]:bdropover:={|obr,nrow,ncol,nkeyflags|mifunción(obr,nrow,ncol,nkeyflags)}
...
function mifunción(obr,nrow,ncol,nkeyflags)
dbdelete()dbskip(1)
obr:refresh(.t.)
return(nil)
Así de fácil!
Con un poco de imaginación, podemos hacer que una fotografia se imprima, al soltarla sobre un ícono
impresora, o que se meta al Clipboard un registro, etc.
Normalmente, en un proyecto se crea el texto de la ayuda en un archivo de extensión RTF (Rich Text Format).
Los tópicos (y otros añadidos) se relacionan en un archivo ASCII, llamado HPJ, y se compilan utilizando una
utilidad entregada por Microsoft, desde el lejano Windows 3.10, el HC31.EXE. (Esta utilidad la pueden
encontrar en Internet). Ahora, mantener el control sobre estos dos archivos (*.RTF y *.HPJ) es tedioso, por lo
que yo utilizo utilidades que automatizan esta tarea. En mi caso utilizo el AHTOOL.EXE (Buscarlo en
Internet como AHTOOL_7.ZIP), que es un programa Shareware que permite con gran facilidad crear ayudas
en Windows. No es como otras utilidades Shareware que permiten crear ayudas con limitaciones, sino que no
nos restringe en su uso.
La manipulación de gráficos en Windows es de por si una aventura, y enmarca un gran concepto teorico. Para
un mayor conocimiento del mismo, voy a darles algunas descripciones necesarias sobre gráficos:
Primero, debemos definir algo que si es estandar en gráficos, y es el numero de bits por pixel:
Una imagen en blanco y negro, solo necesitara un bit (0/1=blanco/negro) para definir el color que va en ese
punto
Una imagen en 16 colores, necesitara de 4 bits (2 a la 4)
Una imagen en 256 colores, necesitara de 8 bits (1 byte) por pixel
Una imagen "true-color" (a todo color), utiliza 24 bits por pixel.
El formato de compresión implica una cabecera y un detalle: la cabecera indica el tipo de archivo gráfico, y el
formato de compresión que se utiliza. El detalle es la información comprimida. Usualmente, se comprime
comparando un pixel con el siguiente, y definiendo un patron de cambio entre estos. (De rojo a azul, sigue
azul tres veces, etc).
*.PCX
Los archivos PCX fueron creados con el proposito de utilizar gráficos de alta resolución, en la epoca del
DOS. Un formato PCX soporta multiples resoluciones (Puede ser de 2,16, 256, y "true-Color").
Adiciónalmente,
tiene un formato de compresión.
*.JPG
Los archivos JPG fueron creados con el propósito de utilizar gráficos de alta resolución. Este formato permite
la pérdida de algunos pixels, pero comprimiendo con un ratio muy alto. Es decir, un JPG pierde calidad de
imagen, pero comprime como ningún otro.
Normalmente, el Windows 3.X como entorno operativo permite Bitmaps únicamente. Utilizar otro formato
gráfico depende de que el aplicativo sea capaz de leerlo (librerías propias del aplicativo).
El archivo de enlace.
El archivo de enlace nos permite definir la forma en que se comportara nuestro aplicativo dentro del entorno
Windows. El típico archivo de enlace (Blinker 3.2) nos muestra:
-De este modo, estamos creando un aplicativo en forma incremental (Al final del ejecutable, el blinker deja un
espacio vacio, para modificaciones). Esto significa que, al volver a enlazar el producto, si no hemos incluido
nuevas funciones, el tiempo de enlazado solo se hara sobre la parte afectada, en unas milagrosas decimas de
segundo! Para entregar el producto final, se debe anadir la linea:
blinker incremental off
Que hara que nuestro ejecutable tenga el tamaño estricto (sin este espacio para cambios).
Otro comando que es de utilidad es el:
blinker executable compress (versión blinker 4.X)
que permite que el ejecutable se "comprima", y pueda ser expandido en tiempo de ejecución. Una aplicación
típica del Fivewin nos ocupa unos 700+ Kb. Con este comando, el ejecutable queda de unos 320+Kb. De ese
modo, un instalable tipo queda:
miexe.exe 350Kb
midll.dll 300 Kb
instalar.dll 10 Kb
preview.dll 26 Kb
mihelp.hlp 200 Kb
bwcc.dll 165 Kb
ctl3dv2.dll 28 Kb
miini.ini 10 Kb
dd.ini 4 Kb
TOTAL: 1093 Kb (Quedando aun 300 Kb para el EXE, HLP, DLL, etcs!)
-Conforme nuestra aplicación vaya creciendo, nos encontraremos con que irá consumiendo más y más
recursos. El incrementar el stacksize a 12000 y el heapsize a 2048 normalmente es suficiente. En la parte de
trucos sucios en Clipper, veremos como enfrentarnos a problemas (a los cuales yo ya me enfrenté), que
aparentemente no tienen solución, por mas que uno mueva el tamano del stack/heap.
ODBC: CONECTANDO MI PC A COMPUTADORES CENTRALES
Cuanto hemos visto ha estado limitado al ámbito de los DBFS. Alguna vez necesitaremos conectarnos a una
base de datos (Puede ser a un AS-400, VAX, NT&SQL, etcs.) Para ello, debemos cumplir con el
condicionante de tener instalado el driver que permita accesar a estas bases de datos. Eso es ODBC ( Object
Data Base Conectivity, u objeto de conectividad a bases de datos). Si entramos en el ODBC Manager del
Windows, y lo tenemos instalado, podremos hacer esta prueba:
#INCLUDE "FiveWin.ch"
#INCLUDE "SQL.ch"
STATIC oWnd
function main()
local obrush
arrini:=tsleeini("odbc.ini")
set 3dlook on
define window ownd from 1, 1 to 20, 75 title "Probar ODBC"
activate window ownd on init testodbc()
return( nil )
FUNCTION TestOdbc()
LOCAL oODBC, oDlg,var:=upper(tsgetini("sql",arrini,"")) && o: SELECT * FROM ARCHIVO
LOCAL oName, cName
DEFINE ODBC oODBC CONNECT "DSN=" FROM USER && Abre ventana de conexion via ODBC
rb:=OdbcStmt():new(oodbc)
rb:execute(var) && Ejecuto SELECT
rb:initfields()
dbcreate("x.dbf",rb:afields) && Creo archivo .DBF!
dbusearea(.t.,,"x.dbf",,.f.)
while rb:skip()=0
dbappend()
for x:=1 to fcount()
ctext:=rb:odbcfget(x) && Lleno archivo DBF con valores obtenidos!
fieldput(x,ctext) && Lleno archivo DBF con valores obtenidos!
next
enddo
go top
browse() && EL select es ahora un DBF, y lo tengo en pantalla!
dbclosearea()
oODBC:End()
ownd:end()
return( nil )
NOTA: Las bases de datos tienen mas tipos que en nuestro conocido DBF (Hay tipo Integer, Long, etcs.,
dependiendo de la base de datos a utilizar) Lo que debemos hacer es obtener el equivalente en campos a mi
DBF segun la tabla que este usando. Me he concetado, hecho el select y cargado en un DBF 500 registros de
una base de datos MS-SQL en 5 segundos (En una 486 DX2 66 con 08 Mb RAM!) (El programa en Visual
Basic que lo hacia tardo 35 segundos para meterlo en un grid, en un Pentium 100 con 16 Mb RAM).
Igualmente de un VAX, he cargado datos a un DBF. Conectividad, señores!
Multimedia: poniendo sonido y/o video a nuestros sistemas.
NOTA: Para poder utilizar estas opciones, el computador cliente debe tener un equipo multimedia
instalado. El Windows administra estos medios a traves de los mci (Multiple Control Interface), que son
drivers que se instalan en Windows junto con un kit multimedia standard. Si su Windows no tiene estos
drivers instalados, no trabajaran estas opciones. (La mejor forma de saberlo es: ¿Tiene tarjeta de sonido la
PC?¿Suena cuando se usa en Windows? Si es asi, si estan instalados dichos drivers).
Poniendo audio:
Pongan esta linea en su programa:
sndplaysound("c:\windows\tada.wav") && o un archivo .wav en general
Un archivo .WAV es un archivo de sonido digital sin division de canales*. La linea arriba indicada ejecutara el
sonido (que puede ser una cancion completa), mientras a la vez Ud. sigue trabajando con su sistema. Es decir,
el sonido no va a detener la ejecucion de su programa.
Un archivo .MDI es un sonido digital con division de canales*. Este tipo de archivos pueden ser interpretados
con la funcion mcisendstr, que explicaremos en el siguiente parrafo.
*En general, cualquier fuente que genere sonido puede ser almacenada en un archivo .WAV. En cambio, un
archivo MDI, solo soporta sonidos sintetizados, que simulan instrumentos musicales. El archivo MDI tiene
entonces un espectro reducido de fuentes de origen de sonido, pero tiene la habilidad de poderse oir uno por
uno los sonidos antes de mezclarse, a diferencia de un WAV, donde no se pueden separar las mezclas de
sonidos que crearon el archivo.
Poniendo video:
Un archivo .AVI puede contiener tanto audio como video. (Generalmente es asi, mas no determinante).
Para usar un video avi, se utiliza la funcion mcisendstr. (En general, como la definicion sintactica lo dice, se
puede controlar varios tipos de controles con esta funcion: video, sonido .WAV, sonido .MDI, etcs)
Sintaxis:
mcisendstr(operacion,@rpta,ventana:hwnd)
Donde:
Operacion es una cadena de caracteres que indica la posible accion a realizar
rpta Es una variable que sera llenada por la funcion, y nos retornara una cadena de texto como
ventana: Es la ventana sobre la que correra la funcion
Veamos un ejemplo:
local od,ob,obo
define dialog od resource "ejemplo"
redefine bitmap ob resource 180
activate dialog od on init inicia(od,ob)
return(nil)
function inicia(od,ob)
local rpta:=space(100),mifile:="c:\demo.avi"
*me aseguro que no haya antes algun video en uso en la ventana
mcisendstr("close video",@rpta,od:hwnd)
*abro archivo avi, administrado por od
mcisendstr("open avivideo!"+mifile+" alias video style popup",@rpta,od:hwnd)
*pongo coordenadas del avi en la ventana
mcisendstr("put video destination at 0,0 20,60",@rpta,od:hwnd)
*Defino que sub-ventana mostrara el avi
mcisendstr("window video handle "+alltrim(str(ob:hwnd)),@rpta,od:hwnd)
*ejecutar!
mcisendstr("play video from 0",@rpta,od:hwnd)
return(nil)
La funcion mcisendstr recibe las cadenas y las interpreta. Cada vez que es invocada la funcion, llenara en rpta
(por referencia) lo que la funcion devuelve.
Hay muchos parametros soportados por la funcion mcisendstr. de hecho, no se si conozco todos. Les sugiero
navegar por el ejemplo de multimedia que viene con fivewin para ver los parametros soportados por esta
funcion (Pero, para video, los arriba indicados son suficientes).
NOTA: Para crear archivos AVI, yo utilizo el Adobe Premiere. Es un programa que con mucha facilidad
me permite (arrastrando y soltando) crear mis secuencias de animaciones. Por supuesto, tambien puede
dividir un archivo .AVI, extrayendo el sonido, o creando un AVI mas pequeño. Cuando la animacion debe
ser creada, utilizo el 3D Studio, que me permite crear imagenes tridimensionales, y darles animacion. Para
quien le interesa incursionar con mas seriedad en este asunto, incluso en Internet le venden a uno las
imagenes ya creadas , para que uno se limite a darles movimientos. Por supuesto, el Premiere es capaz de
leer un archivo del 3DS y convertirlo en AVI.
EL DEBUGGER EN CA-CLIPPER & FIVEWIN
Pese a que el Fivewin tiene un Debugger, depurar un sistema en Windows -sin importar el lenguaje de
programación- es una tarea de locos. Cada vez que alguien hace algo en su computador estando bajo
Windows, crea lo que se denomina un evento. Asi trabaja el Windows. Para el Windows, mover el mouse crea
elementos en este array que seran procesados. Presiónar una tecla es un nuevo elemento en el array que será
procesado. Tarde o temprano, el array tendra mas de un elemento.
Cuando mandemos depurar nuestro programa, y lo detengamos para este proposito (depurar), realmente no lo
habremos detenido, pues lo que le pedimos que hiciera ya esta hecho -esta siendo administrado por el
Windows!-. Del unico modo que podremos depurar un programa es deteniendo el proceso antes que sea
enviado a la cola de tareas del Windows. Y aun asi, no nos será de mucha ayuda, pues no podremos ver que
hace ESA linea de código. Solo podremos ver que hizo. Luego de muchos intentos, aborte esa idea por
considerarla poco practica. Consulte con gente sobre el tema, y todos coincidieron en una cosa. Para depurar,
pon mensajes conteniendo los datos necesarios para depurar antes de la linea. Conclusión:
NOTA: Pongan msginfo() para verificar como avanza el programa. Es mas rápido (criterio personal).
Rápidamente se acostumbrarán a utilizar esta técnica (si no es que no la usan ya).
MANIPULACIÓN DE ERRORES
Existen varios tipos de errores que se pueden presentar en Fivewin:
Stack Calls
===========
Called from ACONTENIDO(230) && Esta es mi linea!
Called from IMPRIMEA(216)
Called from RUTEA(146)
Called from (b)IMPRIME(33)
Called from TBUTTON:CLICK(0)
Called from TBUTTON:HANDLEEVEN(0)
Called from SENDMESSAG(0)
Called from TDIALOG:COMMAND(0)
Called from TDIALOG:HANDLEEVEN(0)
Called from DIALOGBOX(0)
Called from TDIALOG:ACTIVATE(0)
Called from IMPRIME(40)
Called from (b)MAIN(91)
Called from TBUTTON:CLICK(0)
Como se puede apreciar, en esa linea sucede el error y el error es que el alias no esta definido.
En ese caso, pongo en la linea anterior un msginfo() (para determinar que el archivo no pude abrirlo, y no
puse en neterr() que lo controlara).
Errores de velocidad/Windows/afinamiento
Estos errores son de afinamiento del sistema.
Veamos a continuación casos prácticos a los que me he tenido que enfrentar cuando he tenido algun error y la
forma en que los he resuelto (excluyo los primeros errores, pues son errores de programación, en donde la
forma de resolverlo es exclusiva del programador):
Se me ha presentado GPF´s cuando he tratado de crear un indice cuya llave no existe. Verificar si los indices
se pueden construir desde el Fox. También cuando el espacio en disco duro se ha terminado.
Se me ha presentado errores tipo "internal ..." cuando mi programa hace las cosas "demasiado aprisa". Por
ejemplo, cuando creo una ventana con demasiados controles, o un folder con multiples ventanas y
demasiados controles. En ese caso, +/- cada 50 lineas pongo un sysrefresh() (que obliga a procesar el bucle
hasta que no hayan elementos en el array de procesos) y antes de abrir la ventana.
También cuando el sistema es muy grande y el blinker no tiene el comando "incremental off".
Igualmente, aumente el tamaño del archivo de intercambio de Windows a unos saludables 12 Mb.
Se me ha presentado “colgadas” el caso en que estan abiertas aplicaciones que consumen recursos del
Windows. Aumento el stacks del config.sys
config.sys
stacks=18,256
(Si no tenia una linea que defina el tamano del stack, por defecto trabajaba con 9).
Se me ha presentado errores de "colgadas" cuando defino un recurso (un ícono) mal. Por ejemplo, en una
oportunidad defini un array de iconos, y envie el array como objeto ícono.
Se me ha presentado errores de que el windows botaba al DOS al ingresar a una aplicación (Windows 3.X).
Reconstruya el archivo de intercambio del Windows. Verifique que
Puede seguir la larga lista. Como podran apreciar, muchas de estas cosas son resultado de un "afinamiento" a
su computador. En general, cada caso debe de analizarse individualmente.
TRUCOS SUCIOS EN CA-CLIPPER
(Apreciación personal)
Hagamos un enfoque práctico: ¿Para que hacemos sistemas? Pueden hablarme de mística, vocación, amor a la
camiseta, etcs. Al final, y tengo la razón, es por dinero. Enfocados en este punto:
A nivel administrativo:
-Cuando vaya a desarrollar un sistema, cree un documento, en el cual pondra las especificaciones del trabajo a
realizar. Este documento debera estar suscrito por ambas partes, y debera incluir copia de cada uno de los
documentos recibidos en la parte tecnica. Debera indicar que hara el sistema.
-Cada vez que haga una visita/entrega, haga un acta firmada por ambas partes, en la cual detalle el trabajo
realizado en esta visita/entrega. Si es una entrega, especificarlo en el acta. Si es un cambio (o un añadido) en
el sistema, especificarlo en el acta, como CAMBIO EN EL SISTEMA asi, con mayusculas. Y que el
gerente/cliente apruebe dicho cambio.
Estos documentos le seran de mucha utilidad a Ud. pues demostrara a quien sea (al gerente/cliente que le
llamo preguntando que sucede que el sistema no cumple las espectativas) que Ud esta cumpliendo con su
parte del trabajo. Obviamente, preocupese de cumplir con su parte al pie de la letra. Normalmente, un
Gerente/cliente no esta con Ud. cuando hace el trabajo dia a dia. Cuando las "papas quemen", estos
documentos le serviran de salvavidas.
A nivel técnico:
Al analizar un sistema, debemos basarnos en el enfoque INPUT/OUTPUT (Ingresos/Salidas).
Dia 1:
- Pedir los reportes (sean Excel, Word, o algun sistema antiguo por cambiar).
- Pedir todos los documentos que involucran al sistema. Una copia de cada uno, que nos permitira ver si en
efecto, con esta informacion podemos crear todos los reportes que se nos han entregado.
-Hacer una copia de un sistema ya hecho (Puede ser el beep, si es la primera vez), sobre el cual trabajaremos.
Dia 2:
- Hacer un menu que accese a todas estas opciones INPUT/OUTPUT, y cada opcion debera llevar a un
browse. (De muestra de informacion/seleccion de informacion, etc).
Dia 4:
-En el caso de ingreso de datos, cada browse llevara a un dialogo de ingreso de datos
- Asegurarse que cada dialogo grabe la informacion correctamente.
Dia 6:
- Crear los reportes. No preocuparse si no estan al 100% visualmente hablando. Bastará con que esten
operativos, y muestren la información requerida.
Dia 8:
- A partir de aqui, vendran las correciones/validaciones al sistema.
Es decir, normalmente, con 8 horas de jornada diaria, en 8 dias tenemos el PROTOTIPO de un sistema.
(Primera entrega).
Nunca escriba una funcion de mas de 50 lineas! -excepcion del programa principal, en donde las definiciones
de variables pueden llevarse muchas lineas- Eso significa que Ud. esta escribiendo dos funciones en una!
dividalas. Asi su codigo se mantiene legible. (Mi editor me permite ver a 50 lineas. De ese modo veo una
funcion por pantalla).
Para la entrega al cliente, ahi recien enlazo sin modo incremental y con modo de compresion 1 (blinker 4.X).
CARACTERISTICAS TECNICAS
Requisitos de Hardware:
Para programar una aplicación (Requisitos mínimos):
Computador 80386SX.
04 Mb RAM.
HD con espacio disponible de 04 Mb.
Monitor VGA monocromatico.
Para ejecutar una aplicación:
Computador 80386SX, 04 Mb RAM.
04 Mb RAM.
Monitor VGA monocromatico.
Requisitos de Software
Windows 3.1.
CA-Clipper 5.2d.
FiveWin 1.9.2
Borland Resource WorkShop 4.0.
Blinker 3.2.
Características tecnicas
Corre en un equipo 80386SX con 04 Mb RAM, trabaja perfectamente en Windows 3.10, Windows 3.11,
Windows ´95, Windows NT.
Ventajas comparativas
-Es cinco veces mas rapido que el Visual Basic (Trabaja casi a velocidad de CA-Clipper DOS),
-Se programa un 20-30% menos de código que con una herramienta visual actual.
-Utiliza muy pocos recursos del sistema (04 Mb RAM, 80386SX, aun sin disco duro).
-Trabaja en redes (Novell, NT).
-Altamente orientado a objetos. Permite la creación de clases.
-Es la forma mas sencilla de migrar una aplicación de DOS a Windows.
Manual de FiveWin
Obtenido de la Web de Manuales en http://members.xoom.com/manuales
http://www.come.to/manuales
[email protected]