Creando un Escritorio "Fantástico"
Por: George Burt, Presidente de TrueShot Produce Systems, Inc.
Traducción : Juan Manuel Espinosa G.,  Desarrollador de Software


Introducción

La Ventana de Escritorio

La ventana de Escritorio descrita en este artículo es una combinación de estilos que se tomo de diferentes programas. Es un tributo al poder fácil y entendible flexibilidad que hace de dBASE una plataforma superior de desarrollo. Como es a menudo el caso, una simple vista de diseño puede enmascarar mucho de la complejidad del software. Es difícil hacer que el software se vea fácil.

Desktop.wfm, es de hecho es una versión ligeramente modificada de una forma real que el autor usa en su contabilidad y el sistema de información que diseñó para la industria de la producción. La idea era crear una interfase de fácil uso que incluso un neófito de la computadora podría usar.

Observe el Diagrama. Los botones que corren abajo el lado y por la cima son botones “impactantes” o de una idea fantástica. Es decir, estos cambian de alguna manera cuando usted se mueve encima de ellos. Esto ayuda al usuario a saber que si usted pulsa en esta área, algo pasará. En este caso, los botones en la izquierda y por encima adoptan varias conductas y estados que ayudan a que el usuario entienda lo que está pasando. Cuándo el cursor del ratón se mueve por una de estas áreas, este resalta y va de un color gris a un color vivo como si quisiera decir “yo soy una opción!”. Cuando se aprieta uno de estos botones, asume que fue “pulsado”. Esto ayuda al usuario a recordar qué artículo fue finalmente seleccionado.

Adicionalmente, un pulsado de los botones en la izquierda causa un panel fuera del borde detrás del  contenedor de botones, creando un agradable efecto animado. El propósito, en este caso, es proporcionar una opción de dos niveles. Cada botón trae adelante más opciones.

La vista completa de esta forma se fabricó. Nada de esto fue creado automáticamente. Si usted fuera a crear muchas formas grandiosas como esta, pagaría para crear varios controles personalizados y formas con capacidades de clasificar según tamaño y habilidades de despliegue. Esta forma no usa nada de eso. En cambio, toda la funcionalidad se ata a los objetos mismos. Esta forma hace uso extenso de CODEBLOCKS. Un codeblock es un grupo pequeño de órdenes que atan a los eventos de un objeto.

Empieze con un Botón impactante

Como se describió antes, los botones usados en la izquierda y la parte superior de la forma reaccionan a varios eventos del usuario. Antes de ir a los eventos, veamos los objetos que constituyen un botón impactante.

En primer lugar, arrastre un botón de su paleta a la forma.  Luego arrastre una imagen y déjelo caer encima del botón.  Haga clic derecho en la imagen y apunte a datasource a la imagen gris, en este caso company1.gif.

Cambie la propiedad alignment (alineacion) a «true size» (tamaño real) y cambie la propiedad border (borde) a «ninguno». A estas alturas usted tiene un control de imagen que no tiene ningún borde y llena exactamente el gráfico que está desplegando.

El propósito del botón es proporcionar una apariencia de «resaltado» cuando el ratón se mueve encima de él.  En primer lugar, líbrese del texto. Luego, cambie la propiedad del speedbar a verdadera.  Esto es para que el botón no mantenga el enfoque.  Luego, use las teclas de flechas  para posicionarlo de modo que su esquina superior izquierda este alineada con la esquina superior izquierda de la imagen.  La idea es posicionar el botón para que si usted presionara la flecha derecha una vez (de este modo moviendo el botón hacia abajo un pixel) el borde superior del botón será escondido por la imagen.  Entonces presione la tecla flecha arriba DOS VECES para que el borde del botón sea de nuevo visible.  Haga lo mismo con el borde izquierdo.   Ahora, mantenga presionadas las teclas shift-flecha abajo para dar tamaño al botón de modo que su borde inferior simplemente sea visible.  Finalmente repita el procedimiento para el borde derecho.

A estas alturas, usted puede estar preguntándose por qué es necesario usar el botón, después de todo, que usted podría simplemente cambiar el borde de la misma imagen para parecer un botón.  Mientras este acercamiento trabaja y es mucho más simple, causa que la imagen brinque y cambie. En contraste, haciendo un botón subyacente visible crea un efecto muy uniforme.

El evento onMouseMove

Ahora que las partes del botón impactante están en su lugar, es tiempo para trabajar en como traerlo a la vida.  Este paso involucra vinculación de código a varios eventos.  Los eventos afectan, y se conectan a un objeto.  Cuando el usuario mueve el ratón encima de un objeto, los eventos onMouseMove de ese objeto se disparan; lo que significa que ejecutan cualquier código puesto en el evento del onMouseMove.

Deducir qué instrucciones necesitan ser ejecutadas cuando el ratón se mueve encima de la imagen, piense sobre el comportamiento que usted quiere. Primero, el botón debe ponerse visible con el efecto de fabricación «de levantamiento» de la imagen  También, debe ser cambio de gris a color.  Más allá  esto confirma al usuario que esto es de hecho una opción que tendrá un poco de efecto si ellos fueran a pulsar el botón.

En programación orientada a objetos, es de gran ayuda pensar en términos de objetos y qué pueden hacer esos objetos.  El pseudo código para realizar esto podría ser como sigue.
 
 
Eh pushbutton 1, hágalo visible
Eh imagen 1, haz que tu propiedad datasource sea el archivo «company.gif»
   

El pseudo código no es suficientemente explícito.  Usted podría tener muchas formas ejecutándose al mismo tiempo.  Estas instrucciones se supone que están dirigidas a los objetos en esta forma, o alguna otra forma. Puesto que es esta forma, necesitamos decirlo «form.»
 
 
form.pushbutton1.visible = true
form.image1.datasource = 'filename company.gif'
   

De modo que estas son las instrucciones, dónde las pondrias?

Puesto que nosotros queremos esto pase cuando el ratón se mueve encima del objeto imagen, sólo tiene sentido que el código se coloque allí.  Haga clic derecho en la imagen y llame ventana  de Inspector.  Pulse la pestaña de eventos en la parte superior.  Encuentre el evento llamado «OnMouseMove» y haga clic. Como se mencionó antes, nosotros queremos usar codeblocks en lugar de las funciones.  Usted notará que hay dos botones a la derecha de onMouseMove, una herramienta una «T». Para crear un bloque del código o codeblock, usted debe hacer clic en la «T» y despues elegir «codeblock».

Con eso hecho, ahora usted puede hacer clic en la herramienta y aparece un pequeño editor .  Primero, pulse el botón de radio «commando» y limpie el código proporcionado «null». En seguida, teclee en:
 
 
form.pushbutton1.visible = true
form.image1.datasource = 'filename company.gif'
   

Y entonces pulse el botón «OK»

Ahora si usted ejecuta esta forma, usted debera ver una imagen en blanco y negro que es lo que nosotros quisimos ver.  ¡Pero el borde o efecto de «relieve» ya está allí!  La conducta predefinida para este objeto necesita estar como no visible o más bien visible = falso. Remóntese al diseñador de la forma.  Una de las propiedades que están disponible para cualquier objeto es la propiedad visible.  Todos los objetos siempre son visibles en el diseñador de la forma, pero cualquier objeto con visible puesto en falso no será visible cuando la forma realmente está corriendo.  Pero aquí hay otro problema, es difícil seleccionar el pushbutton porque sólo una paqueña porción es visible porque la imagen casi completamente la tapa.  Usted podría ir a la ventana de inspector y podría usar el campo de despliege en la parte superior para encontrar el objeto, pero vamos directamente al código fuente.  En dB2K, no hay ninguna diferencia entre un cambio hecho al código fuente y uno hecho a través del diseñador de la forma. Haga clic derecho en cualquier parte de la forma y escoga «Editor de codigo/diseñador.» Enseguida, encuentre el código que parece similar a lo siguiente:
 
 
this.PUSHBUTTON1 = new PUSHBUTTON(this)
   with (this.PUSHBUTTON1)
      height = 1.5909
      left = 2.4286
      top = 0.3636
      width = 5.2857
      text = ""
      colorNormal = "BtnText/BtnFace"
      pageno = 1
      value = false
   endwith
   

Note que la altura del pushbutton es 1.5909 y otras propiedades se definen entre el with y endwith.  Inserte una nueva línea en cualquier parte entre el with y endwith y teclee:
 
 
Visible = false
   

Cierre el Editor.  Si usted fuera ahora a inspeccionar el objeto pushbutton1, su propiedad visible ahora estaría como falso.  Éste es un ejemplo de las herramientas bidireccionales (two-way tools).

Ahora, si usted ejecuta la forma, usted debe tener una imagen gris, sin bordes alrededor de esta, de hecho.  Si usted mueve su ratón encima de la imagen, esta debe levantarse y colorearse.  ¡Ahora nosotros tenemos nuestro Botón impactante!  Excepto, no que no es todavia impactante.  Puede hacer el truco una sola vez y entonces se queda allí atrancado.  Esto pasa porque hay ningún código que le diga que se baje y se ponga gris. Veamos como ahora necesitamos un nuevo evento!

Idealmente, debe haber un evento que se dispare cuando el ratón ya no esta sobre la superficie de un objeto; un evento de OnMouseOut.  Mientras nos han prometido uno en una liberacion futura de dB2K, mientras nosotros tenemos que hacerlo.  Examinemos el problema:  nosotros necesitamos un evento que se dispare cuando el ratón se separa de la imagen.

Lógicamente, si el movimiento del ratón esta furea de un objeto, ¿no tiene que moverse hacia otro objeto ?  En este caso, la propia forma puede ser el evento.  Cuando el ratón se está moviendo encima de la forma, no se debe estar moviendo encima de la imagen.  Así que tengamos la forma de decir pushbutton1 (de quien la forma es el padre) apagarse y decir image1 (de quien la forma es el padre) para desplegar la imagen gris de nuevo.

Haga clic derecho sobre la forma eliga al Inspector.  Pulse en la pestaña de eventos en la parte superior entonces haga clic sobre la linea de OnMouseMove.  Pulse el botón «T» y escoga codeblock.  Pulse el botón del comando de radiobutton entonces teclee (después de quitar «null»):
 
 
form.pushbutton1.visible = false
form.image1.datasource = 'filename company1.gif'
   

¡Ahora ejecute la forma y funciona!  Cuando usted mueve su ratón sobre la imagen, sube y se colorea, cuando usted aleja, baja la imagen y se pone gris.  Si usted ya ha ejecutado esta forma , podrá notar un problema.  Cuando usted mueve el ratón alrededor, la imagen parpadea.  El evento de OnMouseMove se dispara ciento de veces cuando usted mueve el ratón alrededor porque su trabajo es ejecutarse a cada movimientos del ratón.

Nuestro objetivo es tener una interface del usuario uniforme, asi que necesitamos arreglar este problema.  El problema en realidad no es que el evento se dispare un monton de veces, El problema es que piensa que debe reasignar la propiedad datasource de la imagen y hacer el boton visible cientos de veces.

La solución es hacer una bandera que guarde el registro para saber si el trabajo necesitado ya se ha realizado.  Una vez que la imagen está coloreada y el botón es visible, no necesitamos cambiar regresar esas propiedades hasta que el ratón se mueva otra vez hacia la forma. Haga clic derecho sobre la imagen eliga el Inspector.  Haga clic en la pestaña de eventos, haga clic en  onMouseMove y entonces pulse la herramienta.  Haga los cambios siguientes.
 
 
if not form.image1.color
  form.image1.color = true
  form.image1.datasource = 'filename company.gif'
  form.pushbutton1.visible = true
endif
   

«Color» es una propiedad personalizable, es decir, es una propiedad que usted puede construir.  Se vuelve una propiedad del objeto como la altura (heigth), colorNormal o nombre (name).  Nosotros vamos a hacer la propiedad «Color» verdadero si el objeto esta levantado y en color y falso si esta plano y gris.  Si usted fuera ejecutar la forma con este cambio, sin embargo usted obtendría un error.  Porque «color» es una propiedad personalizada, no existe hasta que nosotros lo creemos.  Desde que el evento onMouseMove anterior asume que hay una propiedad «color» de image1, choca cuando lo busca.  Es como si el programa dijera «Quién? el Color?  Yo no sé de ningun tonto Color!»

De nuevo, necesitamos un nuevo evento.  un evento que asignará la propiedad «color» en cuanto se abra image1.  Eso es lo que el evento de onOpen hace para existir.  Haga clic derecho en la imagen y eliga el panel inspector.  Pulse la pestaña de sucesos y pulse el botón en la línea «OnOpen». Pulse el botón «T» y escoga «codeblock». Pulse el botón de la llave y selecione comando.  Líbrese del «null» y tipo:
 
 
this.color  = false
   

Note el uso de la palabra «this.». De una manera intuitiva, tiene sentido para decir «esta bandera de 'color' se fija a falso.» «this.» es una manera de referirse específicamente a la imagen, sin nombrarla explícitamente.  Porque la palabra «this.» se usa en código atado al objeto image1, sólo podría referirse al objeto image1.  Es como si estuvieras viendo a alguien y le dijeras decir «yo estoy mirándolo» contrario a decir «yo estoy mirando a Juan Pérez». La diferencia es que «yo estoy mirándolo» trabajará con cualquiera que te suceda que este en frente en cambio «yo estoy mirando Juan Perez» es sólo útil si usted está hablando de hecho sobre Juan Pérez.

Otra manera de lograr la misma cosa habría sido teclear:
 
 
form.image1.color = false
   

Piense sobre eso.  Éste no es el único botón impactante que nosotros vamos a usar.  Nosotros también vamos a tener varios mas de estos.  Si somos inteligentes sobre la manera que codificamos esto, nosotros no tendremos que cambiar el código para cada objeto.  Considere lo que tenemos que hacer si tenemos cinco imagenes de botones impactantes.

En el primero tenemos que decir:
 
 
form.image1.color = false
   

En el segundo tenemos que decir
 
 
form.image2.color = false
   

Y así sucesivamente.

O, si nosotros simplemente decimos:
 
 
this.color = false
   

Entonces siempre va a fijar su propiedad personalizada «color» a falso.  Este tipo de versatilidad es uno de los conceptos más importantes en la programación orientada a objetos.

Los cambios del código descritos resuelven el problema del parpadeo cuando usted mueve el ratón alrededor sobre la imagen.  Sólo se pone colorido y levantado una vez gracias a la bandera «color».

Desafortunadamente, el parpadeo vuelve cuando nos movemos alrededor sobre la forma.  Esto es porque nosotros no le hemos enseñado cómo determinar si el botón impactante ya esta gris.  Necesitamos cambiar el evento onMouseMove de la forma de la manera siguiente:
 
 
if form.image1.color
   form.image1.color = false
   form.pushbutton1.visible = false
   form.image1.datasource = 'filename company1.gif'
endif
   

Grandioso.  ¡Ahora nosotros tenemos un botón impactante libre de parpadeo!

Luego necesitamos agregar el efecto de «empuje» cuando se ha seleccionado.

Para esto solo necesitamos cambiar borderstyle de los pushbutton1 de 0 (cero) a 7.

Para esto necesitamos un nuevo evento para disparar cuando el usuario pulsa en el botón.  Si esto se hiciera en un pushbutton, nosotros usaríamos el evento de OnClick. Puesto que el evento va a pasar al objeto image1, lo mas cercano disponible al evento OnClick es el evento  OnLeftMouseDown.  Haga clic derecho en el objeto image1 y eliga el panel inspector.  Pulse la pestaña de evento y pulse el evento de OnleftMouseDown.  Pulse «T» y eliga «codeblock» Pulse la llave y pulse el botón de radio radiobutton «comando». líbrese de «null» y tipo:
 
 
this.parent.pushbutton1.borderstyle = 7
this.on = true
   

Note el uso de «parent». Esto es otro aspecto importante de la programacion orientada a objetos.  Usamos «parent» por las mismas razones que usamos «this» en el ejemplo anterior.  Usted puede estar notando que nosotros todavía estamos usando el nombre explícito «pushbutton1». image1 no esta formalmente relacionanda a pushbutton1.  Se apilan unos encima de otros y nuestra intención es relacionarlos entre ellos, pero hasta donde la forma sabe, ellos son dos objetos separados, independientes.  Eso significa que el objeto image1 debe llamar el pushbutton por nombre si consigue dicirle cambiar borderstyles a 7 (la vista de empujado) de modo que si no hay ninguna relación formal entre pushbutton1 y el objeto image1, por qué usamos la referencia del padre anteriormente.  ¿No haría el trabajo siguiente también?
 
 
form.pushbutton1.borderstyle = 7
this.on = true
   

Sí, también funciona, pero yo estoy pensando adelante.  ¿Qué tan bueno es un botón impactante?  Normalmente, nosotros los usaremos en combinaciones.  Esta organización se presta para usarse en contenedores para sostener grupos de botones impactantes relacionados.   Un contenedor o recipiente es similar a una forma o una sub-forma.  Si usted mueve un contenedor (container), todos los objetos dentro del contenedor se quedan juntos al parejo del recipiente.  Por ejemplo, si usted decidiera que usted quiso todo el tablero de botones impactantes localizado abajo a lado izquierdo de la forma, en cambio, actualmente esté en el lado correcto, simplemente arrastre la forma al lado correcto.  Eso es.  Ningúna re-codificacion, ningún moviendo de objetos individuales. Asi que  ¿cómo se  relaciona esto al uso de el «parent» anteriormente?

Es simple y intuitivo trabajar con recipientes (containers), pero usted tiene que entender la relación entre un recipiente y los objetos en el recipiente.  Usando la palabra «parent» se refiere al recipiente que sostiene el objeto actual.  Puede ser una forma.  Asi que si el objeto image1 se refiere a «this.parent» y el padre de image1’s padre es la forma obviamente this.parent es la forma. Pero si usted pone el botón fantástico en un recipiente, «this.parent» se referiría al recipiente. El linea de fondo es que si usted usa «this.parent» en lugar de «form.», el código trabajará en una forma o cualquier recipiente.

Para recapitular, ésto es como creamos el boton fantástico

Obtenga dos archivos de la imagen que se clasifican adecuadamente según tamaño, uno gris, el otro de color.  Ponga un botón en la forma, elimine el texto. Ponga una imagen en la forma. Fije el datasource para la imagen a la imagen gris.  Cambie la alineación a «top left» (izquierda superior) fije el tamaño del objeto de la imagen para que él exactamente cubra la imagen que está desplegando. Luego, posicione el botón debajo de la imagen para que sólo sus bordes se muestren.  Fije la propiedad visible a falso.  Cree un codeblock en el evento onOpen de la imagen mismo que crea la propiedad personalizada, llamada «color», y se fija como falso.  Agregue un codeblock en el evento onMouseMove que verifica si la propiedad «color» es verdad.  Si es verdad, entonces nada se necesita hacer puesto que ya está en color.  Si «color» es falso, entonces nosotros necesitamos levantar el botón (hágalo visible), muestre la imagen en color en lugar de la imagen gris, y ponga la propiedad «color» en verdadero puesto que el botón impactante está ahora en color.  Luego, necesitamos obtener el recipiente, si es la forma, o un contenedor, para asegurarse que el objeto no está en color y no esta levantado.  Si el evento onMouseMove de la forma o el contenedor está disparando, entonces el ratón no está encima del botón impactante.  Esta forma o el evento de OnMouseMove del contenedor deben verificar la propiedad «color» del objeto de la imagen del botón impactante.  Si esta en color, entonces debe fijar la propiedad visible del pushbutton a falso, y muestra la imagen gris.  Finalmente debe fijar la propiedad «color» a falso puesto que el botón impactante ya no se muestra en color.  Por último, un codeblock debe atarse al evento onLeftMouseDown del objeto de la imagen del cual se debe cambiar el borderStyle del pushbutton a 7 que le de una apariencia de «presionado» .  ¡Guau!

El usuario más avanzado dB2K reconocerá la oportunidad para un control personalizado.  No hay ninguna duda que mucho código podría re-usarse si este acercamiento fue seguido.  Por otro lado, para el desarrollador intermedio o principiante de dbase pueden beneficiarse de ser un poco menos sofisticado.  Teniendo todo el codeblocks atado a los objetos les permite saltar de objeto en objeto para inspeccionar la interacción entre los eventos y propiedades de los objetos usados en la forma.  No hay una necesidad de saltar al código fuente para ver algo.  El editor del codeblock muestra el snipets de código con el que cada evento cuenta.

Así, ahora que nosotros tenemos un botón fantástico totalmente funcional, es tiempo de hacer juntos algunos trabajos.

Grupos de Botones Fatásticos

Porque al dBASE le falta un evento del onMouseOut, los objetos tienen que trabajar para decirnos juntos cuando el ratón esta encima de ellos. El ratón no puede estar disparando eventos onMouseMove de más de un objeto al mismo tiempo, para que nosotros podamos asumir de modo seguro si el ratón esta sobre un objeto, no puede estar encima de otro. Mire el código real que es asociado con el evento OnMouseMove del recipiente de la primera imagen en “desktop.wfm.”
 
 
form.taskbar.image1.onmiddledblclick()
form.taskbar.image2.onmiddledblclick()
form.taskbar.image3.onmiddledblclick()
form.taskbar.image4.onmiddledblclick()
form.taskbar.image5.onmiddledblclick()
form.taskbar.image6.onmiddledblclick()
   

El primero piensa noificar que hay seis comandos. Cada uno corresponde a las seis imágenes mostradas en el tablero que corre abajo a un lado (refiérase al diagrama del escritorio). El contenedor que sostiene estos seis botones fantásticos se llama “taskBar” (barra de tareas). Cada elemento del botón fantástico (pushbutton, imagen, texto) esta contenido dentro del recipiente llamado  “taskBar”. para referirse a él, usted tiene que usar notación de punto. El código anterior se refiere explícitamente a los objetos de la imagen. Observe la notación del punto:
 
 
form.taskbar.image1.onmiddledblclick()
   

“form” se refiere a la propia forma. La forma actúa como un recipiente para todos los objetos usados en esta forma.
“taskbar” se refiere a un recipiente. Los recipientes sostienen otros objetos
“image1” se refiere al objeto de la imagen contenido en el contenedor “taskbar”
“onMiddleDblClick()” se refiere a un evento que es asociado con la imagen “image1”. Note los paréntesis al final. Esto le indica a dBASE proseguir y ejecutar el código contenido en ese evento.

¿Qué carajos es el onMiddleDblClick? Hace años, era común para un ratón tener tres botones. El evento onMiddleDblClick es un lugar conveniente para sostener código que usted no quiere que el usuario active directamente. Mientras es ciertamente posible para un usuario tener un ratòn de tres botónes y hacer doble clic mientras esta encima de una imagen, no es probable. Los usuarios experimentados protestarán al instante que esto es confuso y que un método personalizado simplemente debe atarse al objeto. Esto es verdad, pero hay una razón muy buena para no hacerlo en este caso. Más adelante abundaré sobre esto.

Si nosotros miramos el código atado al evento onMiddleDblClick de image1 se ve como sigue:
 
 
if this.color
   if this.on
   else
      this.datasource = 'filename company1.gif'
      this.parent.pushbutton1.borderstyle = 0
      this.parent.pushbutton1.visible = false
      this.color = false
   endif
endif
   

El pseudo código en español sería:
 
 
If this image's color flag is set to true,
And if this image's "on" flag is true, then do nothing.
But if this image's "on" flag is false then
Set this image's datasource to the filename company1.gif (gray image)
Set this image's parent's pushbutton1's border style to a normal button look
Make the pushbutton invisible
Because the cool button is gray and not raised up, the "color" flag needs to be set to false
   

El evento OnMiddleDblClick de la imagen la hace gris y llana lo que indica al usuario que la opción no esta seleccionada actualmente y no es el objeto que es actualmente “selecionado”.

Cuando el contenedor llamado “el taskBar” recibe un movimiento del ratón, simplemente dice a cada botón fantástico que sea llano y gris. Ésta es la conducta correcta porque si el ratón está moviendose sobre el contenedor mismo, no está apuntando a ningun botón fantástico.

Ahora nosotros hemos visto que una imagen se levanta y se vuelve a color si es que el evento  OnMouseMove se dispara. Se hara llano y gris si es que el evento onMiddleDblClick se dispara, qué otra conducta se necesita? Si el usuario pulsa en la imagen para elegirla, el boton fantástico coolbutton tiene que:
a) ponerse colorido, b) empujado, y c) lanza la acción apropiada. El código siguiente le muestra hacer eso. Este código se conecta al evento onLeftMouseDown de la imagen:
 
 
form.taskbar.pushbutton1.borderstyle = 7
this.parent.onmiddledblClick()
this.on = true
this.parent.onmousemove()
form.m1.onmiddleDblClick()
form.loadwfc("m1.wfc")
   

El pseudo código en Español sería:
 
 
Set this form's container named taskbar's pushbutton1's border style to look pushed in.
Run this image's parent's (the parent is the container named "taskbar") onMiddleDblClick method which makes all the cool buttons flat and gray.
Set this image's "on" flag to true. "On" is a flag that we created and is not a normal property of an image. We could have named the property "Sally" or "Edward", instead, the name "on" is meant to tell us whether the object is pushed in and therefore is the cool button that currently is on.
Next, run this parent's onMouseMove event which will turn this object to color and turn on the pushbutton behind it (remember that we changed the border to have a "pushed in" look)
Next, run the container called "m1"'s onMiddleDblClick event. This needs much more explaining, but briefly it clears out the "m1" container so that it has no objects in it.
Finally, the form's "loadwfc" method (or procedure) is run. This procedure populates the "m1" container and then slides it into view.
   

Mire el diagrama para ver los varios eventos y cómo los eventos actúan recíprocamente.

El Tablero superior

These are one-level cool buttons (no sub-menus)
El tablero de la parte superior es un recipiente nombrado “opBar” que trabaja como “taskBar.” La única diferencia importante es que todos estos botones fantásticos instantaneamente lanzan algo cuando se pulsan en lugar de deslizar fuera un menu-subalterno. Puesto que todos los otros codigos trabajan idénticamente al contenedor “taskBar”, los detalles nos los saltamos.

Enmarcando los Botones fantásticos

Agregar un marco alrededor de los dos recipientes (taskbar y opbar) ayuda al usuario a entender que son grupos separados de botones fantásticos que podrían comportarse lógicamente diferentemente. Un método es cambiar el borderStyle de los recipientes. Quise imitar como se ve Microsoft Outlook y así miraba el marco que se use allí. Hay maneras múltiples evidentemente de lograr esto. Yo establecí cuidadosamente en el uso de pushbuttons clasificado según tamaño y los puse para crear el efecto deseado. Pushbuttons son una opción buena porque vuelven (despliegan) muy rápidamente, use recursos eficazmente, y tienen las características visuales necesarias. Note que cada uno de estos pushbuttons tiene su propiedad “speedbar” puesta en verdadero. Mantiene el objeto del enfoque receptor. Esta propiedad “enabled” también se fija a falso de modo que si el usuario pulsa en el marco, no se comportara como un pushbutton.

El problema con usar pushbuttons es que tienen costuras. Aquí las costuras se han rodeado. No se ven del todo mal, pero dan un efecto granular que no es ideal. Es sencillo remendar estas costuras poniendo pequeños objeto paintbox  sobre las costuras. Cuando usted crea el objeto paintbox, usted sólo tiene que cambiar dos propiedades. 1) fijar borderStyle a “3” qué significa sin bordes. 2) fijar la propiedad ColorNormal a “btntext/btnface” Este fijara el color al mismo color que los pushbuttons usan. Usted podría estar interesado en saber que estos colores son a su vez obtenidos de Windows. Esto permite a su esquema de color ser cambio para igualar el esquema de color en cualquier máquina.

Para terminar el efecto visual nosotros hemos usado un gráfico y dos objetos de texto. Éstos se agregaron por las razones de estilo y no realizan ninguna función particular. Ellos no tienen ningún evento.

La Bandeja de despliegue lateral

La Bandeja de despliegue lateral introduce un rango competo de nuevos conceptos. Primero, tiene un agradable efecto por el que se “desliza” fuera desde abajo del contenedor “taskBar”. Segundo, usa una concepto “fantástico" de la imagen en lugar de un botón fantástico. En tercer lugar, y mas importante, es polimorfico y usa un sistema de creación de objetos Just-In-Time (creación al momento).

El Efecto Animado

El efecto animado es en el fondo muy sencillo. El código relevante toma lugar aquí:
 
 
form.m1.visible = false
form.m1.width = 9.14
form.m1.visible = true
form.m1.left += 1
form.m1.left += 1
form.m1.left += 1
form.m1.left += 1
form.m1.left += 1
form.m1.left += 1
form.m1.left += 1
form.m1.left += 1
form.m1.left += 1
form.m1.left = 10.86
   

"M1" es el nombre de contenedor que se "despliega" afuera. El Pseudo Código en español sería:
 
 
(Before this is called, M1 is moved to so that its "left" is zero)
Make the container called "M1" invisible
Make it the proper width
Make it visible again
Move it to the right one
Move it to the right one
repeat several times
Finally, make its left exactly equal to the screen coordinates where you want it to stop.
   

Usted podría estar preguntandose donde esta el código anterior. Esa respuesta se obtiene parte de la creación de objetos Just-in-Time y para que la discusión se retarde hasta esa sección. Lo que es importante aquí es que la animación no es difícil o misteriosa.

La Imagen Fantásitica

La Imagen Fantástica trabaja justamente como los botones Fantásticos sólo que no hace el “levantamiento”. Esto se hizo por las razones de estilo. El fondo blanco de la bandeja de despliege externo no parecía bueno con botones blancos. Todos los otros aspectos de este trabajo son los mismo sólo que no hay ningún botón para hacer visible.

Polimorfismo y Just-inTime (Justo-en-Tiempo)

Los aspectos de esta forma de escritorio son polimorficos. “Polimorfico" en este contexto tiene un significado ligeramente diferente que la tradicional POO tradicional (Programaón Orientada a Objetos), pero describe justamente esta forma. Polimorfico quiere decir “muchas formas.”pushbutton puede tener muchas combinaciones de borderStyles y colores, pero todavía es debajo el mismo pushbutton. Sólo sus propiedades cambian. Este polimorfismo se toma para otorgarlo para el programador experimentado. Nosotros constantemente alteramos las apariencias y posiciones y función de todos tipo de objetos.

Polimorfismo en esta forma significa que “shape" (la forma física) puede alterarse bien después que el “.EXE” se ha creado. Esto es logrado creando archivos del texto que contienen las definiciones del objeto. Éstos archivos de texto se abren en runtime (tiempo de ejecucion), (o después en este caso) y los objetos se generan en respuesta a la información contenida en estos archivos de texto.

¿Por qué haría usted esto?

Compilado, esta forma es muy pequeña (sólo más de 100k). Desplegar un nuevo “EXE” sobre  Internet no sería ningún problema. Pero las aplicaciones pueden ser mucho mas grandes. La aplicación original para la que esta forma fue diseñada era originalmente más de ocho megabytes. Incluso empacada, todavía es casi de tres megabytes. en 100k, usted puede enviar actualizaciones casualmente. A tres megabytes usted no puede actualizarlo tan casualmente. Porque la aplicación es tan grande y compleja, también tiene más bugs (errores)y más caracteristicas perdidas. Tradicionalmente, cuando usted encuentra un error, usted debe instalar un nuevo “.EXE” para corregir el error o agregar la mejora o herramienta. Si usted usa apropiadamente el poder de dBASE, esto no tiene que ser su única opción.

El archivo “M1.WFC”

Usted recordará que el evento OnLeftMouseDown de form.taskbar.image1 incluye la línea siguiente:
 
 
form.loadwfc("m1.wfc")
   

Esta linea llama el método (función, procedimiento, la rutina etc.) LoadWfc que se lista aquí:
 
 
Function LoadWFC
   parameter Mfile
   ObjInit = new file()
   ObjInit.open(Mfile,"RW")
   Mtemp211=0
   do while .not. objInit.eof()
      Mtemp211 ++
      Mtemp221 = Objinit.readln()
      try
         if substr(Mtemp221,1,1) = '{'
            Mcodeblock = rtrim(Mtemp221)
            Mtemp221 = Objinit.readln()
            Mtemp211 ++
            Mevent = rtrim(Mtemp221)
            Mtemp77 = &Mcodeblock.
            &Mevent. = Mtemp77
         else
            &Mtemp221.
         endif
      catch (exception e)
         msgbox("Error: "+e.message+chr(13)+"Line:;
"+tran(Mtemp211,"99999")+chr(13)+Mtemp221,"Error Message")
    endtry
  enddo
  ObjInit.close()
  ObjInit = null
   

El código anterior realmente es muy sencillo. Un archivo se pasa al parámetro Mfile. Ese archivo es un archivo del texto que contiene las líneas de código válido de dBASE. “Mfile” se procesa al momento en una línea. Busca cualquier línea que empieza con un corchete “{”. Si encuentra tal línea, el código sabe que está tratándose de un codeblock. Asigna el codeblock al evento que se lee enseguida. Por otra parte, simplemente ejecuta cada línea en la forma que la encuentre usando macro substitución. La cosa completamente es contenida en un bloque try-catch (prueba-captura) que le permite manejar errores de una manera elegante. Mire un snippet del código de “M1.WFC”
 
 
form.M1.IMAGE1 = new IMAGE(form.M1)
form.M1.IMAGE1.height =1.4545
form.M1.IMAGE1.left = 2
form.M1.IMAGE1.top = 0.2727
form.M1.IMAGE1.width = 4.8571
form.M1.IMAGE1.dataSource = "FILENAME salesman1.gif"
form.M1.IMAGE1.pageno = 0
form.M1.IMAGE1.borderStyle = 3
{;this.color = false; this.on = false}
form.M1.IMAGE1.onOpen
{;set proc to openapps.prg additive;}
form.M1.IMAGE1.onLeftMouseDown
{;if this.color; this.datasource = 'filename salesman1.gif'; this.color = false; endif;}
form.M1.IMAGE1.onMiddleDblClick
{;if not this.color; this.color = true; this.datasource = 'filename salesman.gif'; endif; this.parent.image2.onmiddledblclick(); this.parent.image3.onmiddledblclick();}
form.M1.IMAGE1.onMouseMove
{;this.color = false; this.on = false}
   

Todos lo que “LoadWFC” hace es ejecutar cada línea anteriormente. Cuando toca un codeblock (es decir empieza con un “{”), lo combina con la siguiente línea para ligar el bloque del código con el evento que sigue.

Respaldemonos ahora y veamos la manera en que “LoadWFC” consigue ejecutarse:
 
 
form.taskbar.pushbutton1.borderstyle = 7
this.parent.onmiddledblClick()
this.on = true
this.parent.onmousemove()
form.m1.onmiddleDblClick()
form.loadwfc("m1.wfc")
   

Note el segundo a la última declaración: form.m1.onMiddleDblClick ()

El código que ejecuta sigue: The code that it executes follows:
 
 
do while this.first <> null
   this.first.release()
enddo
   

Desde que este código se ejecuta de la perspectiva del contenedor llamado  “M1”, “this” se refiere a “M1”. Este código procesa todos los objetos contenidos en el recipiente liberando cada uno. Después de que este código ha terminado, el recipiente está completamente vacío. Puesto que el recipiente está vacío, “form.loadwfc ('m1.wfc')” ejecutará las líneas en “m1.wfc” qué multiplicara el contenedor “M1”. Recuerda que el contenedor “M1” está oculto detrás del contenedor  “taskBar”, para que el usuario no vea los objetos que se estan desplegando. Sólo después de que los objetos se han creado el recipiente “M1” hace el despliegue externo.

Puede parecer mucho problema para involucrarse, y estaría sin las herramientas apropiadas, pero observa lo que ha sido logrado:

Si el contenido de  “M1” necesita cambiar, todos que se requieren es que el archivo de texto “M1.WFC” sea reemplazado. ¡Éste es un archivo de 3.5k! Si usted tuviera una aplicación normal usted podría rolar las diferentes versiones de “M1.wfc” a cada cliente. Aun cuando usted actualizó el archivo “.EXE” el archivo en el futuro, los M1.WFC permanecerían en su estado personalizado.

Esta filosofía del polimorfismo puede extenderse para incluir cada objeto visual. De hecho, el autor extrae todos los elementos visuales para todas las formas y los incluye en éstos “.wfc” los archivos. Antes de que la forma se abra, todos los objetos visuales se crean. El efecto del precio neto es que las formas parecen, el acto y se siente el mismo. Pero cada elemento visual puede cambiarse de forma alguna sin la necesidad de re-distribuir el archivo “.EXE” de la aplicación. Sólo necesitaria enviar el pequeño archivo “.wfc”. De esta manera, una aplicación normal puede estar “personalizada” por cliente mientras retiene la habilidad de actualizar el archivo “.EXE” sin tener que recrear la personalización. Es una forma de como sortear actualizar su navegador de internet: usted puede conseguir nuevas caracteristicas, pero las páginas de HTML viejas todavía trabajan.

Una descripción completa de este proceso va más allá del alcance de este artículo, pero desde que el método es usado en “desktop.wfm”, alguna explicación estaba en puerta.

Conclusión

No todas las aplicaciones garantizan el tiempo y energía que se invirtio en crear el “Escritorio Fantástico”. de hecho toda su funcionalidad pueden reproducirse con mucho menos rodeo. Pero a veces quieres crear una forma que trabaje exactamente cuando te gustaría que lo hiciera. Desktop es tal forma. No era meramente el resultado final de usar objetos de dBASE de una manera tradicional. En cambio, con un concepto de diseño firme en mente, el poder y flexibilidad de dBASE hizo la creación exactamente lo posible deseado.

Esperanzadamente, el lector tomará de esto algunas ideas para cómo mejorar aplicaciones presentes para el usuario. Los mismos conceptos pueden usarse para crear formas que no se parezcan a esta en nada, pero utilizar la misma forma. Este es el poder de dBASE.

Para descargar la aplicación del Escrotorio Fantástico,  haga clic aqui
(es un archivo ejecutable empacado de 60Kb)



Acerca del Autor: George Burt es President of TrueShot Produce Systems, Inc. que ofrece una contabilidad gratuita y sistema de informacion especificamente diseñada para la industria de la produccion. Contabilidad TrueShot esta diseñada para ser completamente presonalizable mientras se mantiene actualizada. el sitio de TrueShot es http://www.TrueShot.com

Traducción por : Juan Manuel Espinosa, Desarrollador de Software en México, D.F.
Administrador de la Comunidad de dBASE en Español
puede contactarlo por e-mail en: juan_espinosa_mx@yahoo.com ó db2kSistemas@netscape.net