0% encontró este documento útil (0 votos)
177 vistas57 páginas

Curso de FiveWin: Programación en Clipper

Este documento presenta un curso de programación en Clipper para Windows usando FiveWin. Explica conceptos básicos como crear ventanas, compilar y enlazar programas, y los controles disponibles en Windows como botones y listas. También cubre temas más avanzados como programación visual, objetos, manejo de archivos y reportes. El objetivo es enseñar a desarrolladores de Clipper cómo crear aplicaciones con interfaz gráfica de usuario en Windows manteniendo su conocimiento en Clipper.

Cargado por

Luciana Ferrara
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como RTF, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
177 vistas57 páginas

Curso de FiveWin: Programación en Clipper

Este documento presenta un curso de programación en Clipper para Windows usando FiveWin. Explica conceptos básicos como crear ventanas, compilar y enlazar programas, y los controles disponibles en Windows como botones y listas. También cubre temas más avanzados como programación visual, objetos, manejo de archivos y reportes. El objetivo es enseñar a desarrolladores de Clipper cómo crear aplicaciones con interfaz gráfica de usuario en Windows manteniendo su conocimiento en Clipper.

Cargado por

Luciana Ferrara
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como RTF, PDF, TXT o lee en línea desde Scribd

CURSO DE FIVEWIN

PROGRAMACIÓN EN CLIPPER PARA WINDOWS


INDICE
INTRODUCIENDOSE AL CA-CLIPPER CON FIVEWIN
Introducción.
Filosofia del CA-Clipper para Windows.
Requisitos de Hardware y Software.
Escribiendo mi primer programa en Windows!
Compilación y enlazado.
Ventanas en Windows- Que son.
CONTROLES EN WINDOWS
Definición
Say
Get
Combobox
Radiobutton
Pushbutton
Listbox
Browses
Spinner
Checkbox
Meters
Cursores
Timers
Bitmaps
Folders
Scroll Bars
Tool-Tips
Cualquier Control!
PROGRAMACIÓN VISUAL
Que es un DLL?
El Resource WorkShop, o la forma de programación visual en CA-Clipper.
Menus - Nunca mas facil!
PROGRAMACIÓN ORIENTADA A OBJETOS
Destruyendo un mito.
Los archivos .INI - Dandole inteligencia al programa.
Manipulación de archivos.
APROVECHANDO LAS CARACTERÍSTICAS PROPIAS DEL WINDOWS
El Clipboard del Windows
De padres e hijos - Ventanas MDI
Ventanas Modales y no modales (lease Modeless).
Enlazado a un DDE.
Instalación de sistemas.
Reportes - La magia del reporte en CA-Clipper y Windows .
Utilizando controles VBX en CA-Clipper.
Que es Drap&Drog?
Haciendo ayudas en Windows.
El archivo de enlace.
ODBC
MULTIMEDIA
Multimedia: poniendo sonido y/o video a nuestros sistemas.
MANEJO DE ERRORES
El Debugger en CA-Clipper.
Manipulación de errores.
EPILOGO
Trucos sucios en CA-Clipper.
RAD en CA-Clipper Windows.
CARACTERISTICAS TECNICAS
INTRODUCIENDOSE AL CA-CLIPPER CON FIVEWIN

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.

Filosofía del CA-Clipper para Windows.


Programar en CA-Clipper para Windows es muy sencillo, y la filosofía se rige por una sola regla:
Aislar los procedimientos que no muestran datos en pantalla de los que si salen a la pantalla*. Es decir, las
"cajas negras", o rutinas de procesos (léase generación del libro diario, cálculo de las ventas del día, cálculo
de monto neto de un producto, etc.) NO CAMBIAN. Las presentaciones en la pantalla (nuestros famosos
@ ... say), SI CAMBIAN. Pero, afortunadamente para nosotros, estos cambios se hacen en modo visual. De
este modo, la curva de aprendizaje será mínima. Evidentemente, y gracias a la orientación a objetos del CA-
Clipper, podemos mejorar nuestros sistemas también en las "cajas negras", y en estas líneas mostraremos las
técnicas existentes. Ud. Siéntase libre de utilizar sólo las que necesite para sus propósitos.

*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.

Llame a su editor de textos favorito y escriba el programa x.prg:


#include "fivewin.ch"
function main()
local ow
define window ow from 0,0 to 10,80 title "CA-Clipper"
@ 1,1 say "Estoy programando en Windows!"
activate window ow
return(nil)

Ahora escriba el archivo bli.lnk:


BLINKER CLIPPER SYMBOL OFF
fi x
out minombre.exe
PACKCODE
PACKDATA
DEFBEGIN
name Minombre
description 'este es mi programa'
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
sear Five, FiveC, Objects
sear WinApi, Clipper, Extend, DbfNtx, Terminal
Compilación y enlazado
Clipper x /n
blinker @bli

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.

Ventanas en Windows - Que son


Antes de profundizar más en el tema, entendamos bien un concepto básico al programar en
Windows. Cuando uno programaba en DOS, tenía toda la pantalla para mostrar su programa, y uno se
preocupaba de restaurar la pantalla cuando era necesario (Recordemos los famosos SAVESCREEN() /
RESTSCREEN() ). En Windows, (que es un sistema operativo, tal como el DOS), se pueden trabajar, o una
sóla pantalla, o muchas pantallas pequeñas. Cada pantalla es conocida como ventana (de ahí el nombre
-Windows-), y cada una es manejada por el sistema operativo (Imaginemos que tenemos un monton de
monitores dentro de nuestro monitor DOS, esa es mas o menos la idea. Una ventaja de esto es que es vez de
utilizar el RESTSCREEN(), simplemente eliminamos la ventana). Cada ventana tiene características propias,
(Pueden crearse, cambiarse de lugar, de tamaño, eliminarlas, etc.), y no necesitamos programar nada de ello,
pues ya está programado en el API del Windows*. Basta con almacenar la ventana en una variable para
administrarla. Para crear una ventana en FiveWin, la sintaxis es:

*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.

DEFINE WINDOW <VARIABLE> ;


[ FROM <EJEX1>, <EJEY1> TO <EJEX2>, <EJEY2> ] ;
[ PIXEL ] ;
[ TITLE <TITULO> ] ;
[ COLOR | COLORS <COLOR> [,<COLOR>] ];
[ OF <VARIABLE2> ] ;
[ BRUSH <FONDO> ] ;
[ CURSOR <CURSOR> ] ;
[ ICON <ÍCONO> ] ;
[ MENU <MENU> ] ;
[ STYLE <ESTILO> ] ;
[ BORDER [ NONE | SINGLE ] ] ;
[ NOSYSMENU | NO SYSMENU ] ;
[ NOCAPTION | NO CAPTION | NO TITLE ] ;
[ NOICONIZE | NOMINIMIZE ] ;
[ NOZOOM | NO ZOOM | NOMAXIMIZE | NO MAXIMIZE ] ;
[ VSCROLL | VERTICAL SCROLL ] ;
[ HSCROLL | HORIZONTAL SCROLL ]
Donde:

VARIABLE Variable con la que manejaremos la ventana.


EJEX1,EJEY1 Coordenadas iniciales.
EJEX2,EJEY2 Coordenadas finales.
TITULO Título de la ventana.
COLOR Color de la ventana.
VARIABLE2 Variable de la ventana que contiene esta ventana
FONDO Fondo a poner en la ventana
CURSOR Cursor a mostrar en la ventana
ÍCONO Ícono a mostrar en la ventana
MENU Menu que mostrara la ventana

ACTIVATE WINDOW <VARIABLE> ;


[ VALID <FVALID> ] ;
[ <show: ICONIZED , NORMAL , MAXIMIZED> ]
[ ON [ LEFT ] CLICK <FLClick> ] ;
[ ON LBUTTONUP <FLButtonUp> ] ;
[ ON RIGHT CLICK <FRClick> ] ;
[ ON MOVE <FMove> ] ;
[ ON RESIZE <FResize> ] ;
[ ON PAINT <FPaint> ] ;
[ ON KEYDOWN <FKeyDown> ] ;
[ ON INIT <FInit> ] ;
[ ON UP <FUp> ] ;
[ ON DOWN <FDown> ] ;
[ ON PAGEUP <FPgUp> ] ;
[ ON PAGEDOWN <FPgDn> ] ;
[ ON LEFT <FLeft> ] ;
[ ON RIGHT <FRight> ] ;
[ ON PAGELEFT <FPgLeft> ] ;
[ ON PAGERIGHT <FPgRight> ] ;
[ ON DROPFILES <FDropFiles> ]

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:

rgb(255,255,255), rgb(128,0,0) ...lo que en DOS sería ("W+/R")

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)

Para definir un FONDO, la sintaxis es:


DEFINE BRUSH <oBrush> ;
[ STYLE <Style> ] ;
[ COLOR <nRGBColor> ] ;
[ FILE | FILENAME | DISK <cBmpFile> ];
[ RESOURCE | NAME | RESNAME <cBmpRes> ]
Note que el FONDO puede ser un archivo .BMP
Los modos predeterminados para aplicar fondos son: BORLAND, TILED, BRICKS, DIAGONAL,
HORIZONTAL, VERTICAL, FDIAGONAL, BDIAGONAL, CROSS, DIAGCROSS

Para liberarlo de memoria:


RELEASE BRUSH <oBrush>

Para definir un ícono:


DEFINE ICON <oIcon> ;
[ NAME | RESOURCE | RESNAME <cResName> ] ;
[ FILE | FILENAME | DISK <cIcoFile> ]

(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 ... ).

Ejemplos particulares de ventanas

CREANDO UNA VENTANA FUERA DEL MONITOR


local ow
define window ow from -2,-2 to -1,-1
activate window ow on init (tone(1000,10),ow:end())

CREANDO UNA VENTANA TRANSPARENTE


local ow,ob
define brush ob style NULL
define window ow from 0,0 to 30,80 brush ob
activate window ow
release brush ob

CAMBIANDO EL TAMANO DE UNA VENTANA


local ow
define window ow from 0,0 to 30,80
activate window ow ;
on init (tone(1000,30),;
ow:aminmaxinfo({10,10,20,20,30,30,40,40}), tone(1000,30), ow:end())

CAMBIANDO DE LUGAR UNA VENTANA


local ow
define window ow from 0,0 to 5,10
activate window ow;
on init (tone(1000,30),ow:move(200,200),tone(1000,30),ow:end())

VENTANA SIEMPRE ADELANTE(VISIBLE)


local ow
define window ow from 10,10 to 30,30
activate window ow on init setwindowpos(ow:hwnd,-1,0,0,0,0,3)
NOTA: Todas las salidas en pantallas de Windows son ventanas. Es decir, un get es una ventana, un say es
una ventana, etc. todas estas pequeñas ventanas estan "pegadas" a la ventana sobre las cuales la dibujamos.
Luego, al ver un dato sobre una ventana, lo que estamos viendo es realmente una ventana sobre una ventana.
Nos damos entonces cuenta que en Windows existen "n" ventanas, y que cada una de ellas es un objeto, con
sus propiedades y atributos (Por ejemplo, el array de aminmaxinfo, que define los taamnos posibles de una
ventana). Gran parte del manejo de ellas esta bajo responsabilidad del Windows y del Fivewin. No nos
debemos preocupar de ellas, pero si podemos manipularlas. Ahora, como cada una de ellas es una ventana
con sus propios atributos, podemos definir a cada una con un color distinto, un tipo de letra distinto. Es mas,
podemos cambiarlos de lugar, hacerlos invisibles, etc. Así, que sencillo es hacer "magia" en Windows!
Por otro lado, cada ventana tiene en Windows un puntero que la mencióna. Este puntero (que es un valor
numerico, unico para cada ventana) puede ser referenciado como ow:hwnd. Este puntero nos servira mas
adelante, para efectuar acciones que el Fivewin de manera "natural" no hace, pero que con sus herramientas
podremos hacer (Ya vimos el ejemplo de una ventana siempre visible).

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 ] ;

ACTIVATE DIALOG <od> ;


[ VALID <fvalid> ] ;
[ WHEN <fcuando> ] ;
[ ON [ LEFT ] CLICK <fclick> ] ;
[ ON INIT <finicio> ] ;
[ ON MOVE <fmover> ] ;
[ ON PAINT <fpintar> ] ;
[ ON RIGHT CLICK <frclick> ] ;
[ CENTER | CENTERED ] ;
[ NOWAIT | NOMODAL ]

od : variable que almacenara al objeto diálogo


recurso : recurso externo*
titulo : titulo del diálogo
x1,y1,x2,y2 : coordenadas
punterorecurso : puntero que apunta al recurso cargado
estilo : estilo del diálogo
color1,color2 : colores del diálogo
fondo : fondo del diálogo
ventana : ventana madre
ícono : ícono del diálogo
fuente : fuente del diálogo
idayuda : puntero de ayuda
NOWAIT : El programa no se detiene en esta linea, se sigue ejecutando

fvalid : función que post-valida


fcuando : función que pre-valida
fclick : función que se ejecuta al hacer click con el mouse sobre el diálogo
finicio : función que se ejecuta al iniciar el diálogo
fmover : función que se ejecuta al mover el diálogo
fpintar : función que se ejecuta al pintar
frclick : función que se ejecuta al hacer click derecho

*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> ] ;

ACTIVATE FONT <of>


DEACTIVATE FONT <of>
RELEASE FONT <of>

of : variable que contendra al objeto fuente


nombre : nombre de la fuente
largo,ancho : largo y ancho de la fuente
deposito : depósito (ventana destino)
tipodeescape : tipo de escape
Las fuentes nos permiten definir los tipos de letras que utilizaremos en nuestras pantallas. Podemos utilizar
incluso, una distinta para cada control, para cada ventana, etc. Mas adelante ampliaremos el concepto, incluso
con casos prácticos.

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.

Un enfoque práctico - diálogos o ventanas?


En terminos estrictos, un programa que hagamos puede mostrar su información en una ventana o en un
diálogo (Uno de los dos). Cualquiera de los siguientes programas es válido:

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:

Si se va a utilizar una pantalla : Puede ser una ventana o un diálogo.


Hasta 5 pantallas : Una ventana fuera de pantalla, y diálogos
mas de 6 pantallas : MDI (Tecnica que describiremos mas adelante)

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).

og : variable que contendrá al objeto get.


mvar : variable con que se iniciara el get.
id : Numero definido en el Resource WorkShop (El famoso puntero!).
od : variable del Diálogo que la contiene
idhelp : Numero asociado al Help
fvalid : Función de validación!
picture : Picture del get. Igual al de DOS
color1,color2 : Colores posibles (Segun el criterio RGB antes descrito)
fuente : Tipo de letra que utiliza este get
cursor : Cursor que mostrara este get al pasar sobre el
mensaje : mensaje que mostrara en la ventana (MDI)
when : función pre-validación
cambio : función que se activa al cambiar el contenido del get!
memo : si el get es un campo memo!
Un ejemplo típico de gets, sería entonces:
local od
local og:=array(5),of
local mvar:={cliente->cliente,cliente->nombre,cliente->dirección,cliente->distrito,cliente->telefono}
define dialog od resource "mirecurso"
define font of name "times new roman" size 10,20
redefine get og[01] var mvar[01] id 101 of od color (rgb(255,255,000),rgb(128,128,000))
redefine get og[02] var mvar[02] id 102 of od font of
redefine get og[03] var mvar[03] id 103 of od on change tone (1000,1)
redefine get og[04] var mvar[04] id 104 of od valid (tone(1000,1),.t.)
redefine get og[05] var mvar[05] id 105 of od memo
activate dialog od centered

Asi de facil!

REDEFINE BUTTON [<ob>] ;


[ ID <Id> ] ;
[ <bar: OF, BUTTONBAR > <obar> ] ;
[ <resource: NAME, RESNAME, RESOURCE> <recurso1> [,<recurso2>]
[ <file: FILE, FILENAME, DISK> <bmp1> [,<bmp2>] ] ;
[ <action:ACTION,EXEC> <facción> ] ;
[ MESSAGE <mensaje> ] ;
[ <adjust: ADJUST > ] ;
[ WHEN <fcuando> ] ;
[ UPDATE <update> ] ;
[ TOOLTIP <ctooltip> ] ;

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.

ob : variable del objeto button


id : Numero definido en el Resource WorkShop (El famoso puntero!).
obar : Si el botón pertenece a una barra de funciones (MDI)
recurso1,recurso2: Gráficos que munestra el botón (por defecto y al presiónarse).
bmp1, bmp2 : Gráficos que munestra el botón (por defecto y al presiónarse).
od : Diálogo en que se pone el botón
facción : acción (lease función) que ejecuta
fcuando : función de pre-validación
fvalid : función que valida

Un ejemplo típico de botones, sería entonces:


local od,ob,obu
define window ow from 0,0 to 30,80
define buttonbar obu of ow
redefine button ob id 101 of obu action tone(1000,1) file ("c:\uno.bmp"),("c:\dos.bmp")
activate dialog od centered
REDEFINE BUTTON [ <ob> ] ;
[ ID <Id> <of:OF, WINDOW, DIALOG> <od> ] ;
[ ACTION <acción.> ] ;
[ <help:HELP, HELPID, HELP ID> <idhelp> ] ;
[ MESSAGE <mensaje> ] ;
[ <update: UPDATE> ] ;
[ WHEN <fcuando> ] ;
[ VALID <fvalid> ] ;
[ PROMPT <prompt> ] ;
[ <lCancel: CANCEL> ] ;

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 .

ob : variable del objeto button


od : Diálogo en que se pone el botón
acción : acción (lease función) que ejecuta
id : Numero definido en el Resource WorkShop (El famoso puntero!).
idhelp : Numero asociado al Help
mensaje : mensaje que mostrara en la ventana (MDI)
fcuando : función de pre-validación
fvalid : función que valida
prompt : texto del botón

Un ejemplo típico de botones, sería entonces:


local od,ob:=array(2)
define dialog od resource "mirecurso"
redefine button ob[1] id 101 of od action tone(1000,1)
redefine button ob[2] id 102 of od action od:end()
activate dialog od centered

REDEFINE CHECKBOX [ <oc> VAR ] <mvar> ;


[ ID <id> ] ;
[ OF | WINDOW | DIALOG <od> ] ;
[ HELPID | HELP ID <helpId> ] ;
[ ON CLICK <fclick> ];
[ VALID <fvalid> ];
[ COLOR | COLORS <color1>;
[,<color2>] ] ;
[ MESSAGE <mensaje> ] ;
[ UPDATE ] ;
[ WHEN <fcuando> ] ;

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).

oc : variable que contiene al objeto checkbox


mvar : valor inicial del checkbox
id : Numero definido en el Resource WorkShop (El famoso puntero!).
od : Diálogo que contiene al checkbox
helpid : Numero asociado al help
fclick : función que se evalua al hacer click con el mouse sobre el control
fvalid : función que valida
color1,color2 : colores del checkbox
mensaje : mensaje (en ventana MDI)
fcuando :función que pre-valida

Un ejemplo típico de un checkbox, sería entonces:


local od,oc:={},mvar:={.t.}
define dialog od resource "mirecurso"
redefine checkbox oc[1] var mvar[1] id 101 of od on click tone(1000,1)
activate dialog od centered

REDEFINE COMBOBOX [ <oc> VAR ] <mvar> ;


[ ITEMS <aitems> ] ;
[ ID <id> ] ;
[ OF | WINDOW | DIALOG <od> ] ;
[ HELPID | HELP ID <helpid> ] ;
[ ON CHANGE <fcambio> ] ;
[ VALID <fvalid> ] ;
[ COLOR | COLORS <color1>;
[,<color2>] ] ;
[ UPDATE ] ;
[ MESSAGE <mensaje> ] ;
[ WHEN <fcuando> ] ;

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.

oc : variable que contiene al objeto combobox


mvar : variable inicial del combobox
aitems : array de items.
id : puntero al recurso.
od : Nombre de la variable que contiene al diálogo
helpid : Numero asociado al help
fcambio : Función que se evalua cuando hay una selección en el combo
fvalid : Función que valida
color1,color2 : Colores del combobox
mensaje : Mensaje que aparece en la ventana MDI
fcuando : Función de pre-validación

Un ejemplo típico de un combobox, sería entonces:


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)
activate dialog od centered
REDEFINE METER [ <om> VAR ] <actual> ;
[ TOTAL <total> ] ;
[ ID <Id> ] ;
[ OF <od> ];
[ UPDATE ] ;
[ FONT <fuente> ] ;
[ PROMPT <prompt> ] ;
[ NOPERCENTAGE ] ;
[ COLOR | COLORS <color1>, <color2> ] ;
[ BARCOLOR <color3>, <color4t> ] ;

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.

Un ejemplo típico de un meter, sería entonces:


local od,om, mactual:=1,mtotal:=mifile->(reccount()),contador:=1
define dialog od resource "mirecurso"
redefine meter om var mactual total mtotal
activate dialog od centered nowait && NOWAIT: El sistema continua con nuestro
código!!!
set dele off && No importan deleteados para total del meter
mifile->(dbgotop())
while mifile->(!eof())
om:set(contador++)
sysrefresh() && Obligo a pintarse la pantalla
if mifile->(!deleted())
...MIACCIÓN
endif
mifile->(dbskip(1))
enddo
set dele on
od:end()

REDEFINE LISTBOX [ <ol> VAR ] <mvar> ;


[ <items: ITEMS, PROMPTS> <arritems> ] ;
[ <files: FILES, FILESPEC> <cFileSpec> ] ;
[ ID <id> ] ;
[ ON CHANGE <fcambio> ] ;
[ ON [ LEFT ] DBLCLICK <fdocleclick> ] ;
[ <of: OF, WINDOW, DIALOG > <od> ] ;
[ <help:HELPID, HELP ID> <idhelp> ] ;
[ VALID <fvalid> ] ;
[ <color: COLOR,COLORS> <color1> [,<color2>] ] ;
[ MESSAGE <mensaje> ] ;
[ <update: UPDATE> ] ;
[ WHEN <fcuando> ] ;
[ BITMAPS <arrbitmaps> ] ;
[ ON DRAWITEM <ubmpelegido> ] ;

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).

ol : Variable que contiene al objeto listbox


mvar : Valor inicial del listbox
arritems : Array de elementos mostrados en el listbox
cFileSpec : Si lo que se muestran son archivos, mascara de archivo ("*.dbf")
id : Numero del puntero del recurso
fcambio : Función que se ejecuta al cambiar de elemento
fdobleclick : Función que se ejecuta al hacer doble click sobre el listbox
od : Diálogo que contiene al listbox
idhelp : Numero que se relacióna a la ayuda
fvalid : Función que valida el listbox
color1,color2 : Colores del listbox
mensaje : Mensaje que muestra el listbox (Ventanas MDI)
fcuando : Función que pre-valida
arrbitmaps : Array de bitmaps a mostrarse en el listbox
ubmpelegido : Bitmap mostrado al ser elegido un elemento.

Un ejemplo de un listbox sería:


local ol,od,mvar:=""
define dialog resource "mirecurso"
redefine listbox ol var mvar id 101 of od items {"Disco A","HD","Disco Red"} ;
bitmaps {"c:\a.bmp","c:\b.bmp","c:\c.bmp"}
activate dialog od

REDEFINE LISTBOX [ <ob> ] ;


FIELDS [ <campo1,campo2,...>] ;
[ FIELDSIZES <arrtamanos> ] ;
[ HEAD | HEADER | HEADERS <arrencabezados> ] ;
[ ID <id> ] ;
[ ON CHANGE | ON CLICK <fcambio> ] ;
[ ON RIGHT CLICK <frclick> ] ;
[ ON DBLCLICK <fdobleclick> ] ;
[ OF | WINDOW | DIALOG <od> ];
[ <color: COLOR,COLORS> <nClrFore> [,<nClrBack>] ] ;

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

Un ejemplo típico de un listbox de archivos, sería entonces:


local od,ob
define dialog od resource "mirecurso"
use cliente
redefine listbox fields cliente->código,cliente->nombre headers "CÓDIGO","NOMBRE" id 101 of od
activate dialog od centered

DEFINE TCBROWSE <ol> ID <nid> OF <od>


ADD COLUMN TO <ol> ALIGN <align> TAG "MALIYET" SIZE <nsize> ;
DATA <data> HEAD <head> COLOR <color1>,<color2>

ol : variable que contiene al objeto listbox


nid : numero de puntero
od : nombre de variable objeto ventana
align : alineamiento: left/right/centered
nsize : tamaño en pixels
data : campo a mostrar
head : encabezado
color1,color2 : colores de la columna, en formato RGB()

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.

Un ejemplo típico sería


local ot
define tcbrowse ot id 101 of od
add column to ot align left size 20 data cliente->nombre header “NOMBRE” color rgb(0,0,0),rgb(255,0,0)
add column to ot align left size 20 data cliente->edad header “EDAD” color rgb(0,0,0),rgb(255,255,0)

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.

REDEFINE RADIO [ <or> VAR ] <mvar> ;


[ ID <id1,id2,id3...> ] ;
[ OF | WINDOW | DIALOG <od> ] ;
[ HELPID | HELP ID <helpid> ] ;
[ ON CLICK | ON CHANGE <fcambio> ]
El checkbox nos permite selecciónar entre dos estados. El radio nos permite selecciónar entre una serie de
estados. Por ejemplo, si deseamos mostrar un indice activo, el radio es ideal para elejir UNA opción de las
mostradas. Aparece en pantalla como un circulo blanco, y en color negro el vigente. El modo de determinar
cual es el radio vigente es accesando a la variable codeblock del objeto del siguiente modo: eval(or:bgetset).
Esto devolvera el numero de radio vigente.

or : variable que almacena al objeto radio


mvar : Valor inicial del objeto
id1,id2,id3... : cada recurso radio creado (Se crean indivudualmente)
od : Diálogo que contiene al radio
helpid : Numero que se relacióna a la ayuda
fcambio : Función que se evalua al cambiar de radio vigente

Un ejemplo típico será:


local od,or,mvar:=1
define dialog od resource "mirecurso"
redefine radio or var mvar id 101,102,103 of od on change tone(1000,1)
activate dialog od centered

REDEFINE SCROLLBAR [ <os> ] ;


[ ID <id> ] ;
[ RANGE <mínimo>, <máximo> ] ;
[ PAGESTEP <step> ] ;
[ UP | ON UP <facciónup> ] ;
[ DOWN | ON DOWN <faccióndown> ] ;
[ PAGEUP | ON PAGEUP <facciónpgup> ] ;
[ PAGEDOWN | ON PAGEDOWN <facciónpgdn> ] ;
[ ON THUMBPOS <fpos> ] ;
[ OF | WINDOW | DIALOG <od> ]

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()

os : Variable que contiene al objeto scrollbar


id : Numero de recurso definido
mínimo,máximo : valores mínimo y máximo que puede adpotar la variable
step : De cuanto en cuanto aumenta/decrece el scrollbar
facciónup : Función que se ejecuta al presiónar la flecha arriba/derecha
faccióndown : Función que se ejecuta al presiónar la flecha abajo/izquierda
facciónpgup : Función que se ejecuta al presiónar entre la flecha abajo/izquierda y el botón de
desplazamiento
facciónpgdn :Función que se ejecuta al presiónar entre la flecha abajo/izquierda y el botón de
desplazamiento
fpos : Función que se ejecuta al arrastrar el botón de desplazamiento
od : diálogo que contiene al Scrollbar
Un ejemplo de esto sería:
local od,os
define dialog od resource "midiálogo"
redefine scrollbar os id 101 of od range 0,255 on up tone(1000,1) on down os:setpos(os:getpos()-1)
activate dialog od

REDEFINE SAY [<os>] ;


[ <label: PROMPT, VAR> <texto> ] ;
[ PICTURE <picture> ] ;
[ ID <Id> ] ;
[ <dlg: OF,WINDOW,DIALOG > <od> ] ;
[ <color: COLOR,COLORS > <color1> [,<color2> ] ] ;
[ <update: UPDATE > ] ;
[ FONT <fuente> ] ;

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

Un ejemplo típico de says, sería entonces:


local od
local os,of
define dialog od resource "mirecurso"
define font of name "times new roman" size 10,20
redefine say os prompt "Mi nombre" id 101 of od color (rgb(255,255,000),rgb(128,128,000)) font of
activate dialog od centered

DEFINE TIMER <ot> ;


[ INTERVAL <intervalo> ] ;
[ ACTION <facción> ] ;
[ OF | WINDOW | DIALOG <od> ]
ACTIVATE TIMER <ot>
DEACTIVATE TIMER <ot>
RELEASE TIMER <ot>

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)

REDEFINE BITMAP [ <ob> ] ;


[ ID <id> ] ;
[ OF | WINDOW | DIALOG <od> ] ;
[ NAME | RESNAME | RESOURCE <recurso> ] ;
[ FILE | FILENAME | DISK <bitmap> ] ;
[ ON ClICK | ON LEFT CLICK <fclick> ] ;
[ ON RIGHT CLICK <frclick> ] ;
[ SCROLL ] ;
[ ADJUST ] ;
[ CURSOR <cursor> ] ;
[ MESSAGE <mensaje> ] ;
[ UPDATE ] ;
[ WHEN <fcuando> ] ;

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.

ob : variable que contiene al bjeto bitmap


id : Numero de puntero del recurso
od : Nombre del diálogo que contiene al bitmap
recurso : Nombre del recurso mostrado (Si el gráfico esta dentro del recurso)
bitmap : Nombre del archivo bitmap
fclick : Función a evaluar al hacer click con el mouse
frclick : Función a evaluar al hacer click derecho con el mouse
cursor : Cursor a mostrar al pasar sobre el bitmap
mensaje : Mensaje a mostrar en la ventana MDI
fcuando : Función de pre-validaciohn

De ese modo, un ejemplo sería:


local od,ob
define dialog od resource "mirecurso"
redefine bitmap ob id 101 of od resource 1102 scroll (Puedo ver un segmento del gráfico en el recuadro
asignado)
activate dialog od centered
REDEFINE FOLDER [of] ;
[ID <id>];
[ OF | WINDOW | DIALOG <od> ] ;
[PROMPT "index1","index2"];
[DIALOGS "od1,"od2"]

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.

of : Variable que contiene al objeto folder


id : Numero de puntero asociado al recurso
od: : Nombre de el diálogo que contiene al folder.
index1,index2 : Nombre de los diálogos (cada pestaña del folder)
od1,od2 : Numero de puntero asociado a cada diálogo/recurso

Un ejemplo tipo sería:


local od,ofo,ob1,ob2
define dialog od resource "mirecurso"
redefine folder ofo id 101 of od prompt "Primero","Segundo" dialogs 101,102
redefine button ob1 id 101 of ofo:adialogs[1] action od:end()
redefine button ob2 id 101 of ofo:adialogs[2] action tone(1000,1)
activate dialog od
return(nil)

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:

define window ow ... menu mimenu(parametros) menuinfo 1


Menuinfo 1 indica que las ventanas abiertas se mostraran con un separador despues de las opciones del popup
1 como selecciones del menu.

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)

Envio el valor men[x] como parametro, y en el programa le efectuo un enable()/disable() (Activar/desactivar)


al ingresar a la rutina y al salir de ella.
owp:tile() Si owp es una ventana MDI, se mostraran acuñadas una tras la otra
owp:cascade() Si owp es una ventana MDI, se mostraran en cascada.

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:

set resources to "recurso.dll"


redefine dialog od resource "midiálogo".
En nuestro archivo DLL tendremos un diálogo de nombre "midiálogo", con las características necesarias. El
comando "set resources" nos permite abrir el archivo, y relaciónarlo con nuestro ejecutable.De ahi en adelante
estarán a nuestra disposición los datos contenidos en este recurso.

El Borland Resource Workshop


Al ingresar a este programa, y luego de la ventana inicial de presentación, nos aparecera una ventana MDI
(hay quew irse familiarizando con los terminos), con un menu de opciones:

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.

Preferencias: Configuración del WorkShop

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.

Salir: Salir del WorkShop


Editar
Undo: Permite dehacer la ultima acción efectuada.
Redo: Permite rehacer el ultimo "undo" hecho
Cortar: Permite retirar un dato, almacenandolo en memoria.
Copia: Permite copiar en memoria un dato.
Pegar: Permite jalar de memoria el dato previamente almacenado.
Deletear: Borra un dato.
Deletear item: retira un dato.
Duplicar: Duplica un dato.
Selecciónar todo: Permite selecciónar todos los datos en el recurso activo.

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.

Ahora, hagamos un training básico del uso del 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.

Editar un array de constantes


Ubiquese en el array (stringtable) y presióne Enter. Presióne Ins para anadir un nuevo item al array, [Ctrl-Del]
para retirar un elemento del array. Sugerimos por el momento no manipular estos arrays (No incluirlos en sus
programas), despues veremos como hacerlo en un modo mas conveniente.

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.

Como prueba de lo hecho:

Escribir el programa X.PRG:


#incluse "fivewin.ch"

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)

static function midiálogo(ow)


local od,og:=array(1),mvar:={space(20)},ob:=array(2)
define dialog od resource "mirecurso"
redefine get og[1] var mvar[1] id 101 of od;
picture "@!" color rgb(255,255,255),rgb(000,000,128)
redefine button ob[1] id 102 of od action tone(1000,1)
redefine button ob[2] id 103 of od action (od:end(),ow:end())
og[1]:ctooltip:="Este es el tool-tip del get!"
activate dialog od centered
return(nil)

Escribir el bli.lnk:

BLINKER CLIPPER SYMBOL OFF

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

LIB Five, FiveC, Objects


LIB WinApi, Clipper, Extend, DbfNtx, Terminal

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.

(El DLL y el ejecutable deberan estar en el mismo directorio).


El CTL3DV2.DLL debera estar en \windows\system*
El BWCC.DLL debera estar en \windows\system*

*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).

INTRODUCCIÓN. UNA NUEVA FILOSOFIA.


Desde hace algún tiempo hemos oído hablar de una frase nueva en el dicciónario de informática, "Orientado a
Objetos". Hemos preguntado a amigos y nos han hablado de lenguajes de programación, de entornos,
polimorfismo, reusabilidad, analisis y diseño, etc. Al final, probablemente no entendimos nada y lo "dejamos
ahí". De hecho, "Orientado a Objetos" no es un lenguaje de programación, ni entornos, ni palabras extrañas.
Es tan sólo una forma nueva de ejecutar nuestro trabajo, una nueva filosofía de trabajo, que nos permitirá
apreciar las cosas que hacemos en forma natural. Por el momento, nos olvidaremos de la programación
orientada a Objetos, y concentraremos nuestra atención en OO:

¿QUÉ ES OO?¿QUÉ ES UN OBJETO?


Entendamos un objeto como un grupo de procedimientos escritos, con relación entre sí. Para un programador,
podriamos afirmar que un objeto es un array, que contiene variables y funciones que pueden ser evaluadas.
Como es un array, podemos alterar sus variables y mantenerlas existentes mientras exista esta variable array.
Es decir, imaginen que podemos hacer algo asi como:
objeto:={halla_edad_del_cliente(código_del_cliente), nombredelcliente:="Jose",
cambia_sueldo_del_cliente(nuevo_sueldo), sueldo_del_cliente:=1000 ,... }

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:

Sujetos: Cliente, mercadería, almacén, factura.


Verbos: pide mercadería, exista en almacén, retira la mercadería, despacha la mercadería, paga la factura.

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.

LOS ARCHIVOS .INI - DANDOLE INTELIGENCIA AL SISTEMA

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.

-Con esta metodologia, me he ahorrado hasta un 50% de trabajos de compilación/enlazado, pues me ha


bastado definir una variable de entorno en la parte crítica del sistema, para luego analizarlo. De hecho, cada
vez que se me ha pedido que deshacer algo de un sistema, lo he "desactivado", y mi código ha permanecido
limpio. Por otro lado, haciendo una rutina de configuración, he conseguido que el sistema sea configurable
hasta por el usuario.

-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!)

APROVECHANDO LAS CARACTERÍSTICAS PROPIAS DEL WINDOWS

EL CLIPBOARD DEL WINDOWS


El Windows es un sistema operativo que permite ejecutar más de una aplicación por vez. Esto trae una ventaja
consigo: Es posible transmitir información entre las distintas aplicaciones. Para poder transmitir información
entre aplicaciones, el Windows provee de un depósito de acceso común, llamado Clipboard.

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.

la sintaxis para crear un acceso al Clipboard es la siguiente:

DEFINE CLIPBOARD <oclp> ;


[ FORMAT TEXT | OEMTEXT | BITMAP | DIF ] ;
[ OF <ownd> ]

Donde:
oclp: Es el nombre de la variable que almacenara a objeto clipboard
ownd: Es el nombre de la variable ventana activa.

ACTIVATE CLIPBOARD <oclp>


Activa el objeto Clipboard*
A continuación, un ejemplo que graficará mejor la implementación de esta clase:
#include "fivewin.ch"

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)

static function probar(ow,oc)


local cadena:=space(30)
msgget("Ingrese un texto para poner en el Clipboard","ATENCIÓN",@cadena)
oc:settext(cadena)
msginfo(oc:gettext(),"VENTANA MOSTRANDO EL TEXTO RECUPERADO")
winexec("clipbrd")
return(nil)

DE PADRES A HIJOS - VENTANAS MDI


Primero, Que es MDI? (Multiple Document Interfase)

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.

El esquema de nuestros sistemas era:


Menu-Facturas-Menu-Clientes-Menu-Facturas
Ahora puede ser
Menu-facturas-clientes-facturas (sin cerrar la sesión de facturas!)

Sintacticamente, es muy sencillo hacerlo:


define window owp from 0,0 to 30,80 title "EJEMPLO MDI" mdi (Solo añadimos la palabra mdi)

Cuando creamos ventanas hijas:


define window owh mdichild from owp... (Solo añadimos las palabras mdichild from owp)

Al llegar a este punto, nos detenemos un momento a pensar...

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)

Y activamos a ambas, ventana y diálogo:


activate dialog od nowait on init od:move(0,0)
activate window owh
return(nil)

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)

static function mimenu()


local om,men:=array(2)
redefine menuitem men[01] prompt "" id 101 of om action mdi1(men[01])
redefine menuitem men[02] prompt "" id 102 of om action mdi2(men[02])
return(om)

static function mdi1(men)


local ow,mdi1:=tsstrarr(tsgetini("mdi1"),"|")
men:disable()
define window ow mdichild of owp title mdi1[1];
from val(mdi1[2]),val(mdi1[3]) to val(mdi1[2])+1,val(mdi1[3])+1
ow:bgotfocus:={||od:setfocus()}
define dialog od resource "MDI1" of ow
activate dialog od nowait on init od:move(0,0)
activate window ow on initÑ
ow:setsize(od:nwidth,od:nheight) valid cerrar(ow,men,mdi1)
return(nil)

static function cerrar(ow,men,mdi1)


local eje:=getcoors(ow:hwnd),coor,antes:=mdi1[2]+"|"+mdi1[3]
men:enable()
coor:=padl(eje[1],3,"0")+"|"+padl(eje[2],3,"0")
if coor<>antes
arrini:=tsgraini("ejemplo.ini","mdi1",mdi1[1]+"|"+coor)
endif
return(.t.)

static function mdi2(men)


local ow
men:disable()
define window ow mdichild of owp title "MDI2" from 0,0 to 1,1
ow:bgotfocus:={||od:setfocus()}
define dialog od resource "MDI1" of ow
activate dialog od nowait on init od:move(0,0)
activate window ow on init ow:setsize(od:nwidth,od:nheight) valid (men:enable(),.t.)
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> ] ;

ACTIVATE [ DDE | LINK ] <oDde>


DEACTIVATE [ DDE | LINK ] <oDde>
RELEASE [ DDE | LINK ] <oDde>

Donde:

odde: variable que contendra al objeto dde


cservice: Nombre del servicio DDE a invocar
ctopic Topico del servicio DDE
citem: Item del servicio DDE
uend: Validación para fionalizar el enlace DDE

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).

Dentro de miexe.ini, pondremos una variable llamada exe=c:\midir\por_aqui\mas_aca\miexe.exe


que será el path en donde deseamos instalar nuestro ejecutable. Nuestro sistema, al iniciarse, verificará la
existencia de este archivo. Si no existe, entrara a la rutina de instalación.
if !file(tsgetini("exe",arrini,"c:\xxx_xxxa.xxx"))
instalar()
return(nil)
endif

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).

Nuestra rutina de instalación hará lo siguiente:

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)

static function logica(ow)


local od,os:=array(2),ob:=array(2),ofo:=array(2)
ofo[1]:=tfont():new("times new roman",10,24,,.t.)
ofo[2]:=tfont():new("arial",7,16,,.f.)
define dialog od resource "instalar" color rgb(255,255,255),rgb(255,255,255)
*Este es mi diálogo, aqui defino el path y otras características para instalar el modulo
redefine say os[1] prompt "" id 1 of od color rgb(000,000,128),rgb(255,255,255)
os[1]:setfont(ofo[1])
redefine say os[2] prompt "" id 2 of od color rgb(255,000,000),rgb(255,255,255)
os[2]:setfont(ofo[2])
redefine button ob[1] id 101 of od action (procede(os),od:end())
redefine button ob[2] id 102 of od action od:end()
activate dialog od centered valid (ow:end(),.t.)
return(nil)
static function okfiles()
local arrfiles:=tsrangoini(arrini,"[inifiles]","[finfiles]"),contador,rpta:=.t.
*En mi .INI tengo definidos los archivos que copiaré del diskette al disco duro.
if len(arrfiles)=0
rpta:=.f.
msgalert("No existe definición de archivos en mini.ini","FATAL")
endif
for contador:=1 to len(arrfiles)
if !file(arrfiles[contador])
rpta:=.f.
msgalert("No existe archivo "+arrfiles[contador]+"!","FATAL")
exit
endif
next
if !file("ctl3dv2.dll") .or. !file("bwcc.dll")
rpta:=.f.
msgalert("No existe archivo ctl3dv2.dll / bwcc.dll !","FATAL")
endif
return(rpta)

static function procede(os)


creapaths(os)
* Creo el arbol de directorios.
sysrefresh()
if copiafiles(os)
* copio archivos
sysrefresh()
if creagrupos(os)
*creo grupo de trabajo (Ventana de Grupo/Acceso directo)
sysrefresh()
msginfo("INSTALACIÓN FINALIZADA.","ATENCIÓN")
endif
endif
return(nil)

static function copiafiles(os)


local arrfiles:=tsrangoini(arrini,"[inifiles]","[finfiles]")
local pathexe:=tsgetini("exe",arrini,""),rpta:=.t.
pathexe:=substr(pathexe,1,rat("\",pathexe))
for contador:=1 to len(arrfiles)
os[2]:settext("Instalando archivo "+arrfiles[contador]+" en "+pathexe)
copy file (arrfiles[contador]) to (pathexe+arrfiles[contador])
if !file(pathexe+arrfiles[contador])
rpta:=.f.
msgalert("No se puede copiar archivo en "+pathexe+arrfiles[contador]+" (Revisa
exit
endif
next
copy file ("ctl3dv2.dll") to (getsysdir()+"\ctl3dv2.dll")
copy file ("bwcc.dll") to (getsysdir()+"\bwcc.dll")
return(rpta)
static function creagrupos(os)
local odde,rpta:=.t.
local pathexe:=tsgetini("exe",arrini,"")
pathexe:=substr(pathexe,1,rat("\",pathexe))
os[2]:settext("Creando grupos...")
define dde odde service "progman" topic "progman"
*Creo enlace DDE con el program manager
activate dde odde
odde:execute("[deletegroup(MINI)]")
odde:execute("[creategroup(MINI)]")
odde:execute("[showgroup( MINI - MI SISTEMA,1)]")
odde:execute("[additem("+pathexe+"mini.exe,Modulo Mini,"+pathexe+"
odde:execute("[additem("+pathexe+"mini.hlp,Ayuda - Mini)]")
*ejecuto funciones del program manager (Para ello necesite de la documerntación pertinente)-
release dde odde
*Libero el enlace DDE
return(rpta)

static function creapaths()


local cadena,path,buffer,arrpath:=tsrangoini(arrini,"[inipaths]","[finpaths]")
local conta1,conta2,letra
for conta1:=1 to len(arrpath)
buffer:=""
path:=arrpath[conta1]
path:=substr(path,at("=",path)+1)
for conta2:=1 to len(path)
buffer:=""
path:=arrpath[conta1]
path:=substr(path,at("=",path)+1)
for conta2:=1 to len(path)
letra:=substr(path,conta2,1)
if letra="\"
lmkdir(buffer)
buffer+=letra
else
buffer+=letra
endif
next
if substr(buffer,len(buffer),1)="\"
lmkdir(buffer)
endif
next
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> ]

or Nombre de la variable que contiene el objeto reporte


titulo Titulo del reporte
encabezado Encabezado del reporte
pie Pie del reporte
fuentes Letras a utilizar
pen Tipo de barra para dibujar
nombrefile nombre del archivo
recurso nombre del recurso
afile a un archivo
adevice a un lugar especifico
nombrerepo nombre del reporte
COLUMN [ <orc> ] ;
[ TITLE <Titulo, ...> ] ;
[ AT <col> ] ;
[ DATA <data, ...> ] ;
[ SIZE <tamano> ] ;
[ PICTURE <Picture, ...> ] ;
[ FONT <fuente> ] ;
[ < TOTAL > [ FOR <total> ] ] ;
[ < LEFT | CENTER | CENTERED | RIGHT > ] ;
[ < SHADOW > ] ;
[ < GRID > [ <pen> ] ]

orc Nombre de la variable que almacena la columna


titulo Titulo de la columna
col Columna en que se listara
data campo a mostrar
tamano tamano de la columna
picture picture del dato
fuente tipo de letra
total totalizar columna al final
pen ancho de la barra divisoria

GROUP [ <og> ] ;
[ ON <grupo> ] ;
[ HEADER <encabezado> ] ;
[ FOOTER <pie> ] ;
[ FONT <fuente> ] ;
[ < EJECT > ]

og Variable que contendra al objeto grupo


grupo Función que con un valor logico indica cuando hacer un quiebre (p.e. cliente<>"N")
encabezado Encabezado del grupo
pie Pie del grupo
fuente Tipo de letra a usar para el grupo

ENDREPORT

ACTIVATE REPORT <or> ;


[ FOR <for> ] ;
[ WHILE <while> ] ;
[ ON INIT <Init> ] ;
[ ON END <End> ] ;
[ ON STARTPAGE <StartPage> ] ;
[ ON ENDPAGE <EndPage> ] ;
[ ON STARTGROUP <StartGroup> ] ;
[ ON ENDGROUP <EndGroup> ] ;
[ ON STARTLINE <StartLine> ] ;
[ ON ENDLINE <EndLine> ] ;
[ ON CHANGE <cambio> ]

or Nombre de la variable que contiene al reporte


for Por (condición)
while Mientras (condición)
init Función invocada al iniciarse el reporte
end Función invocada al terminar reporte
startpage Función invocada al iniciar una página
endpage Función invocada al terminar una página
startgroup Función invocada al iniciarse un grupo
endgroup Función invocada al terminar una grupo
startline Función invocada al iniciarse una linea
endline Función invocada al terminar una linea
cambio Función invocada al pasar a un nuevo registro

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.

La temática será la siguiente:

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.

UTILIZANDO CONTROLES VBX EN CA-CLIPPER


Un control VBX es un control que fue creado con el proposito de que pueda ser utilizado por cualquier
aplicación. Mientras en Fivewin tenemos los controles (get, say, etc.) "embebidos" (dentro) del ejecutable, en
otros lenguajes los controles son externos al ejecutables, y son invocados. De ese modo, se crean archivos de
controles con una extensión VBX (Estos VBX son a 16 bits, lo "nuevo" en tecnologia sugiere los controles
OCX, o controles en 32 bits, que serian mas rapidos de ejecutar). El Fivewin permite la manipulación de
controles VBX. Un caso típico de un control VBX es el de un gráfico. Si nosotros desearamos añadir un
gráfico estadistico de barras a nuestra aplicación, deberiamos crearlo, pues la libreria de Fivewin no tiene un
similar. Al invocarf al control gráfico VBX, podremos mostrar el reporte estadistico con un gráfico que lo
acompañe, dandole un feeling profesiónal a nuestros sistemas. En general, la logica para añadir un VBX en
nuestras aplicaciones es muy sencilla, y consta de dos pasos:
a)Definir el control VBX, y b)Configurar sus valores. A continuaciomn, veamos un ejemplo bastante sencillo
de como añadir el gráfico en nustra aplicación*

*Nota: Para añadir el gráfico, necesitaremos de los siguientes archivos:


(gsw.exe y graph.vbx)
define window ow from 0,0 to 30,80 title "UNO"
@ 1,1 vbx ovbx size 10,10 filename "graph.vbx" of ow
activate window ow on init setea(ovbx)

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)

Algo que es importante destacar:


1- Un control VBX tiene una serie de parámetros, que al manipularse dan el aspecto deseado al VBX
(datareset/graphtytle/mquickdata, etc), y que varian de VBX a VBX. Podremos saber los parametros de un
VBX leyendo su documentación. (En mi caso, lo he logrado probando parametros del VBX desde el Visual
Basic).

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.

HACIENDO AYUDAS EN WINDOWS


Hacer ayudas en Windows es una de las tareas mas tediosas que se nos pueda presentar. Usualmente, inicamos
un proyecto con un gran entusiasmo, hacemos los primeros modulos a gran velocidad, y desarrollamos las
cajas negras. Pero a medida que avanza el tiempo, se nos va haciendo cada vez mas tedioso el continuarlo, y
al final solemos hacer lo que no deberíamos hacer: Que se acabe el proyecto como sea. Esto significa sin
manuales, sin ayuda, con bugs, etc. Esa tendencia debemos de finalizarla, pues esta de por medio la calidad de
persona que tenemos. Lo ideal es hacer un proyecto, y seguirlo con la misma "pasión" que nos guiaba al
principio.
En general, hacer una ayuda en Windows consta de tres partes:
-Crear el texto de la ayuda (Pudiendo definir fuentes, colores e incluso añadir gráficos*)
-Crear los tópicos (un texto que al hacer click sobre el nos lleve a otro texto -Puede ser una pequeña ventana
dentro de la página actual, o una nueva ventana-)
-Compilar la ayuda (El archivo de ayuda es un compilado,*.HLP. Como tal, tiene dentro de el todo el texto
que hayamos escrito, asi como los gráficos. recomiendo ser un poco tacaño con los gráficos, pues de lo
contrario nos encontraremos con archivos de ayuda en Windows de 2 Mb o mas, y que aún no dicen nada.
Esto, claro, obedece a la politica que uno vaya a utilizar en sus proyectos. Yo tengo la vieja costumbre DOS
de entregar un aplicativo en un diskette, y no en las decenas de diskettes que acostumbra entregarse en
Windows).

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).

Existen varios formatos gráficos:


*.BMP
Los archivos BMP fueron creados con el proposito de utilizar gráficos en forma rapida. Un archivo BMP es,
como reza su nombre, un mapa de bits, sin compresión alguna (Se graba el archivo tal cual se lee). Es por
ello, que es rapida su visualización (Se lee y se pinta en pantalla, sin decodificar o descomprimir). El
inconveniente de estos archivos es su gran tamano. Un archivo de 300 x 200 pixels en blanco y negro,
utilizara 60000/8 bytes siempre, aun asi este en blanco. El archivo BMP es el unico (de los aqui analizados)
que no viene comprimido. El mismo archivo en "true-color" utilizara 300X200X24=1440000/8=180,000
bytes. (unos 180Kb)
*.GIF
Los archivos GIF fueron creados con el proposito de utilizar gráficos de baja resolución. Un formato GIF
soporta 256 colores, no mas. Adiciónalmente, tiene un formato de compresión, por lo que un archivo GIF
puede ser facilmente la mitad de un BMP (De alli que sea utilizado en Internet).

*.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).

NOTA: Existen otros formatos, de menor importancia/difusión.

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:

BLINKER CLIPPER SYMBOL OFF


No se utilizan los siombolos del Clipper por defecto (Hara el ejecutable mas pequeño, retirando modulos que
no se necesitan en Windows).
PACKCODE
El código de las funciones en disco se empaqueta. En memoria se desempaqueta (descomprime).
PACKDATA
La data de las funciones en disco se empaqueta. En memoria se desempaqueta (descomprime).
fi b
Archivos a enlazar
out b.exe
Nombre del ejecutable final
Las siguientes lineas son para aplicativos exclusivos en Windows
DEFBEGIN
name Miexe
Nombre del ejecutable (Documentación)
description ´miexe´
Nombre del ejecutable (Al instalar nuevos programas en add programs -Windows 3.X-, aparecera este
nombre)
exetype Windows 3.1
En que plataforma (mínimo) corre.
code moveable discardable preload
El código del programa se puede descargar/mover de memoria, si otra aplicación lo requiere.
data preload moveable
La data del programa se puede mover de memoria, si otra aplicación lo requiere.
stacksize 10000
Tamano de la pila del ejecutable.
heapsize 1024
Tamano de la entorno del ejecutable.
segment 'PLANKTON_TEXT' nondiscardable
segment 'EXTEND_TEXT' nondiscardable
segment 'OM_TEXT' nondiscardable
segment 'OSMEM_TEXT' nondiscardable
segment 'SORTOF_TEXT' nondiscardable
segment 'STACK_TEXT' nondiscardable
Segmentos (code) que no se pueden descargar de memoria (Básicos/Root)
DEFEND

LIB Five, FiveC, Objects


LIB WinApi, Clipper, Extend, DbfNtx, Terminal
Librerías necesarias.

-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.

Valores (Parametros) utiles para la administracion de un video:


*Detener un video (Pausa)
mcisendstr("stop video",@rpta,od:hwnd)
*Reiniciar video
mcisendstr("play video",@rpta,od:hwnd)
*Para adelanter/retroceder cuadro por cuadro un video
mcisendstr("status video position",@rpta,od:hwnd)
actual:=val(rpta)
mcisendstr("seek video to "+alltrim(str(actual+/-1))),@rpta,od:hwnd)
mcisendstr("play video",@rpta,od:hwnd)
mcisendstr("stop video",@rpta,od:hwnd)
*Para que el video se repita en forma ciclica (Crear un timer que llame a estas lineas en una funcion)
mcisendstr("status video position",@rpta1,od:hwnd)
actual:=val(rpta1)
mcisendstr("status video position",@rpta2,od:hwnd)
total:=val(rpta2)
if total=actual
mcisendstr("play video from 0",@rpta,od:hwnd)
endif

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:

Para depurar con el depurador:


Compilar con /b (clipper miprograma /b)
En el directorio de programa, añadir fwdbg.dll.
Armarse de paciencia.

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:

Errores de lógica del Sistema


Estos errores son los típicos errores: Una variable no definida, un campo no existente, un bloqueo no
efectuado, etc. En estos casos, el Fivewin tiene un gestor de errores (ERRSYSW) que nos informara en una
ventana el tipo de error que se presento y, al salir del programa, generara un archivo llamado error.log, que es
en donde se guardara la información pertinente al error. (De esta información, la realmente util es la que me
informa en que linea se cayo el aplicativo).

Veamos un ejemplo de un archivo error.log:


Application
===========
Path and name: I:\BONO\BONO5.EXE
Size: 333,056 bytes
Max files handles permited: ( SetHandleCount() ) 50
Error ocurred at: 20/09/97, 15:50:31
Error description: Error BASE/1002 Alias does not exist: _ABONO && Este es mi error

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 protección general


Un error de protección general (GPF ERROR) es el error mas crítico que sucede en Windows. Pero,
despreocúpese. El 90% de estos errores son causados por el Windows, y son poco comunes. Aún el Microsoft
Word presenta eventualmente GPF´s.

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).

RAD En CA-Clipper Windows


RAD (Rapid Aplication Development, o desarrollo rápido de aplicaciones) es una tendencia que nace en
sistemas, cuya tendencia reza el tener herramientas que permitan un rapido desarrollo. Normalmente, yo uso
el Resource WorkShop, y un procesador de textos (Uso el Qedit TSR para DOS, una herramienta fabulosa,
que me permite mover columnas, y ejecutar macros DOS -p.e. clipper mifile /blinker @bli -sin salir del editor
). Creo una sesion DOS en la cual levanto el editor de textos. En un ciclo de trabajo tipo:
(Sesion DOS - editor de textos) corrijo una variable
(Sesion DOS - editor de textos) compilo/enlazo con blinker en modo incremental
(Sesion Windows - Administrador de programas) Pruebo el programa
tardo 1.5 segundos con una PC Pentium 75 con 16 Mb RAM.
Ningun otro lenguaje me da un ciclo tan corto!

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]

También podría gustarte