Los Documentos SDI en VFP 5.0

Por Rubén Iglesias
© Copyrights 1997 by FoxPress, All rights reserved
FoxPress, Febrero 1997

La llegada de Windows’95, sin duda ha modificado sustancialmente nuestros hábitos de programación y sobre todo en lo referente al diseño de las aplicaciones. Primero fue la completa desaparición de las que mostraban pantallazos consecutivos, ya que el entorno exigía que fuese posible acceder a varias ventanas paralelamente. Ahora, vamos un poco más allá, debemos de tener la posibilidad de crear ventanas que tengan entidad propia, esto es, que sean independientes de la aplicación que las creó, son las llamadas aplicaciones SDI (Single Document Interface). En contraposición a este tipo de aplicaciones, tenemos las MDI ó Multiple Document Interface, que son las que hasta ahora hemos hecho y que consisten en varias ventanas al mismo nivel y dependientes, en cualquier caso, de la ventana principal de la aplicación. En Visual Foxpro 5.0 se ha incorporado este nuevo planteamiento y con él surgen nuevas denominaciones para las ventanas. En definitiva, cambia la forma de realizar nuestras aplicaciones. Pasemos a analizar todo esto, que como veremos, es bastante fácil de incorporar a nuestras viejas aplicaciones.

 Debemos tener clara la diferencia entre los tipos de ventanas que podemos tener en VFP 5.0. Para ello vamos a utilizar el comando DEFINE WINDOW que, aunque antiguo, nos va a servir para ver gráficamente cada uno de los tipos.

 1) IN SCREEN; es una ventana que depende directamente de la de VFP y por tanto, cuando se minimiza queda dentro de ésta.

 DEFINE WINDOW ventanamadre ;
TITLE "Ventana IN SCREEN" ;
FROM 1,1 TO 30,70 MINIMIZE ZOOM FLOAT ;
CLOSE COLOR N/R

ACTIVATE WINDOW ventanamadre

 

 

 

  • NOMDI; si cuando se maximiza, el borde superior se coloca justo debajo del menú principal. Este es el valor por defecto.
  •  

  • MDI; si cuando se maximiza, el título de la ventana pasa a formar parte de la ventana de VFP.

    DEFINE WINDOW ventanamadre;
    TITLE "Ventana IN SCREEN" ;
    FROM 1,1 TO 30,70 MINIMIZE ZOOM ;
    FLOAT CLOSE ;
    COLOR R/N MDI

    ACTIVATE WINDOW ventanamadre

  • 2) IN WINDOW; una ventana IN SCREEN puede contener otras ventanas, que son denominadas IN WINDOW o ventanas hijas. Dependen directamente de ellas no pudiéndose sacar de los límites de su ventana madre. Cuando se minimizan quedan también dentro de la ventana madre.

    DEFINE WINDOW ventanahija IN WINDOW ;
    ventanapadre TITLE "Ventana IN WINDOW" ;
    FROM 3,3 TO 10,30 MINIMIZE ZOOM ;
    FLOAT CLOSE COLOR N/B*

    ACTIVATE WINDOW ventanahija

    3) IN DESKTOP; al igual que la ventana IN SCREEN depende de la ventana VFP pero a diferencia de ésta, puede sacarse fuera de los límites de la de VFP, de ahí que se denomine IN DESKTOP, porque en apariencia depende del escritorio de Windows. Las coordenadas de la ventana sí que son respecto al escritorio, no como en IN SCREEN que eran referidas a la de VFP. Cuando se minimiza, queda "flotando" sobre el escritorio, no pasa en ningún caso a formar parte de la barra de tareas.

    DEFINE WINDOW ventanadesktop IN DESKTOP ;
    TITLE "Ventana IN DESKTOP" ;
    FROM 10,2 TO 20,40 MINIMIZE ;
    ZOOM FLOAT CLOSE COLOR N/GR*

    ACTIVATE WINDOW ventanadesktop

    4) IN MACDESKTOP; también denominada Top-Level, es la principal novedad de la nueva versión. Se trata de una ventana que es independiente de la de VFP, por lo que en Windows’95 se convierte en una aplicación más, que formará parte de la barra de tareas. Este tipo de ventanas es el que permite crear aplicaciones SDI.

    DEFINE WINDOW ventanatop IN MACDESKTOP ;
    TITLE "Ventana TOP-LEVEL" ;
    FROM 10,60 TO 20,90 MINIMIZE ;
    ZOOM FLOAT CLOSE COLOR N/B

    ACTIVATE WINDOW ventanatop

     

    Después de hacer un breve repaso por todos los tipos de ventanas que podemos crear con VFP, detengámonos en esta última ya que es la verdaderamente nueva y la que nos interesa. Para ello, vamos a transformar una aplicación MDI hecha en VFP 3.0 en SDI con VFP 5.0.

    Este era el aspecto de la aplicación cuando se ejecutaba el .exe.

    Aparentemente, tenía aspecto Windows, sin embargo, los pequeños trucos utilizados para conseguirlo, demostraban que VFP 3.0 no había pensado en aplicaciones para Windows’95.

    El principal problema, radicaba en que siempre que ejecutábamos la aplicación, primero se cargaba el entorno de VFP y luego nuestras ventanas. Por tanto, la aplicación era MDI siendo la ventana madre la de VFP y esto convertía al objeto _SCREEN en fundamental.

    Esta aplicación contenía la ventana de VFP, un menú que sustituye al de VFP y una ventana IN SCREEN tipo MDI maximizada. En VFP 5.0, nada de esto es así. Comencemos la transformación.

     

    1. Cambio de la ventana principal a Top-Level y eliminación de la de VFP

    En VFP 5.0 es sumamente sencillo cambiar una ventana de In Screen a Top-Level ó viceversa, ya que se ha incorporado la propiedad ShowWindow en el objeto Form.

    Como se puede ver, disponemos también de la opción In Top-Level Form que posteriormente utilizaremos para otros formularios.

    Con este sencillo paso, la ventana principal, ahora, es independiente de la de VFP. Sin embargo, ésta sigue existiendo, con lo cuál no ganaríamos mucho. Pero VFP 5.0, también permite quitar esta ventana y por consiguiente, no se arrancará VFP cada vez que ejecutemos el .exe.

    También es un cambio sencillo. Esta vez tenemos que modificar el CONFIG.FPW de la aplicación. Antes debíamos adaptar VFP a nuestra aplicación, para ello incluíamos líneas como las siguientes:

    TITLE = && quita el título de la ventana de VFP
    SYSMENU = OFF && quita el menú de VFP
    STATUS BAR = OFF && quita la barra de estado

    Ahora todo esto no hace falta, ya que lo vamos a sustituir por

    SCREEN=OFF

    y con ello habremos hecho desaparecer de un plumazo la ventana de VFP, convirtiéndose nuestra ventana principal tipo Top-Level, en la ventana madre de la aplicación. Cuidado, no olvidemos, que si estamos probando la aplicación desde dentro de VFP, sí que existe el objeto _SCREEN ya que este CONFIG no se ejecuta, aunque siempre nuestra aplicación será independiente de VFP.

    Tampoco necesitamos redimensionar la ventana de VFP para que tenga una determinada apariencia al comenzar la aplicación, por lo que líneas como éstas

    _SCREEN.WIDTH=340
    _SCREEN.HEIGHT=370

    no hacen falta, ya que el tamaño será el que determinemos en la ventana principal.

    Un importante dato que tenemos que tener presente, es que ahora no podemos llamar a los métodos y propiedades del formulario activo mediante

    _SCREEN.ACTIVEFORM.NombreMétodo

    ya que acabamos de decir que no existe el objeto _SCREEN. Tendremos que hacer referencia directa al objeto que VFP crea al ejecutar el form Top-Level. Este objeto, tendrá el mismo nombre que el archivo .SCX que estamos ejecutando. Por tanto, todas las siguientes llamadas se harán con dicho nombre de objeto, como por ejemplo:

    Ajedrez.NuevaPartida

     

    2. Sustitución del menú por otro de tipo In Top-Level

    El menú principal de la aplicación es otro de los elementos que debemos modificar. En la antigua aplicación, a la hora de comenzarla teníamos algo así:

    DO menuprin.mpr
    READ EVENTS

    con lo que ejecutábamos primero el menú y luego desde el menú se irían llamando a los distintos formularios de la aplicación.

    Ahora, si estamos utilizando una ventana Top-Level como es nuestro caso, el orden de ejecución se invierte. Primero se muestra el formulario y luego se ejecuta el menú que quedará dentro de éste. Por tanto, el arranque será:

    DO FORM ajedrez
    READ EVENTS

    Lo que debemos hacer ahora, es transformar el menú que teníamos en In Top-Level y ponerlo dentro del formulario principal. Para hacer lo primero, VFP 5.0 ha añadido un checkbox en Opciones Generales... del generador de menús, que con sólo activarlo, convertimos el menú.

    Este cambio nos obliga a tener que ejecutar el menú de otra forma. En concreto, debemos llamarlo desde el Init del form Top-Level. Esta técnica, recuerda bastante a la que se utilizaba en las anteriores versiones no visuales para añadir menús a ventana modales.

    DO menuprin WITH Thisform

    Vemos que se pasa un parámetro al menú, en este caso Thisform. Es necesario, para indicar en qué formulario se ejecuta el menú. Existe la posibilidad de incorporar un segundo parámetro, de tipo lógico, que si es .T., crea un nombre único para el menú, con vistas a que éste pueda ser utilizado en otros formularios. En nuestra aplicación, no es necesario indicarlo.

    Es también evidente que las instrucciones para quitar y poner el menú de VFP, como SET SYSMENU TO ó SET SYSMENU TO DEFAULT, tampoco son de utilidad, ya que no existe el menú de VFP. En el caso, de que estemos ejecutando el .APP y no el .EXE, tampoco es problema, puesto que el formulario al ser Top-Level, es independiente de la ventana de VFP y no afecta a su menú.

     

    3. Modificación de las ventanas a In Top-Level

    Si mostrábamos previamente ventanas dentro de la aplicación, ahora tenemos que tener en cuenta que deben aparecer dentro de un formulario Top-Level. Es el caso del formulario Acercade que muestra información sobre la aplicación.

    Para convertir un formulario como hijo de otro de tipo Top-Level, debemos recurrir de nuevo a la propiedad ShowWindow, que ya conocemos y elegir la opción 1 In Top Level. Así conseguiremos que el formulario se vea. De lo contrario, no aparecería en pantalla.

     

    4. Creación de otro Form Top-Level dentro de la aplicación

    El tener como ventana principal un formulario Top-Level no significa que no podamos incluir otros del mismo tipo, que, por definición, puedan ser tratados independientemente por el entorno Windows. Por eso, vamos a crear un calendario con estas características.

    Para hacerlo, vamos a echar mano de los nuevos controles ActiveX que incorpora VFP 5.0, uno de los cuales, es un calendario. El formulario tendrá el siguiente aspecto:

     

    Y con la propiedad ShowWindow lo creamos como As Top-Level. Cuando ejecutemos la aplicación, podremos tener por un lado el Calendario y por otro la ventana principal.

     

    5. Manejo de los objetos de una ventana In Top Level

    Cuando creamos un formulario In Top-Level directamente como objeto, esto es, con el generador de formularios, surge un problema bastante importante, cuando se ejecuta, no se crea un objeto sino que sólo es una ventana. Este hecho, en la POO es una traba sumamente crucial ya que de ninguna forma podríamos acceder a los objetos contenidos a dicho formularios. La solución pasa indefectiblemente por tener que crear previamente una clase para el formulario en cuestión.

    Al igual que ocurre para el formulario Top-Level, ahora deberemos llamar a los métodos y propiedades del formulario In Top-Level creado, directamente con su nombre de objeto, nunca utilizando la propiedad ACTIVEFORM del objeto _SCREEN, que ya no existe.

    En nuestra aplicación, vamos a pasar el Grid que refleja los movimientos de las piezas dentro de una ventana In Top-Level y que deberemos refrescar cada vez que se realice un movimiento. Creamos, según lo dicho, una clase nueva con la propiedad ShowWindow a 1- In Top Level, que posteriormente instanciaremos mediante código.

    Ahora veamos el código que va a mostrar y ocultar este formulario, desde una opción de menú creada para tal efecto:

    ** Si no existe el objeto, creamos una
    ** variable pública para él y lo creamos
    ** partiendo de nuestra clase

    IF TYPE("oMov")="U"
    PUBLIC oMov
    oMov=CREATEOBJECT("mov")

    ** Le damos la posición correcta dentro del
    ** formulario Top-Level

    oMov.Left=335
    oMov.Top=15

    ** Lo hacemos visible

    oMov.Visible=.T.

    ** Redimensionamos la anchura del formula-** rio Top-Level para que permita ver el
    ** formulario añadido

    Ajedrez.Width=520

    ** Cambiamos la opción del menú para que la
    ** próxima vez se oculte la ventana

    DEFINE BAR 8 OF Opciones ;
    PROMPT "Ocultar Movimientos"

    ELSE

    ** Si existe el objeto, lo hacemos
    ** desaparecer, llamando a
    ** este método que hace un RELEASE oMov
    ** y cambia la opción del menú mediante
    ** DEFINE BAR 8 OF Opciones PROMPT "Ver
    ** Movimientos"

    oMov.QueryUnload

    ** Hacemos más pequeña la ventana
    ** principal

    Ajedrez.Width=330

    ENDIF

    Por último, en los lugares del programa donde refrescábamos el Grid con un

    Thisform.Grid1.Refresh

    deberemos cambiarlo por un

    IF TYPE("oMov")<>"U"
    oMov.Refresh
    ENDIF

     

    6. Creación de una barra de herramientas In Top-Level

    El último paso de la transformación, va a ser incorporar a nuestra aplicación SDI una barra de herramientas. Para ello, no podemos seguir la técnica habitual de creación de la barra como objeto en el código, sino que le debemos decir que se cree dentro del Top-Level. Ya que una barra, al fin y al cabo es también un formulario, dispone igualmente de la propiedad ShowWindow que pondremos a 1- In Top Level.

     

    Deberemos, por último, incorporar el código necesario para mostrar y ocultar la barra desde el menú.

    IF TYPE("oBarra")="U"
    PUBLIC oBarra
    oBarra=CREATEOBJECT("Barra")
    oBarra.Dock(0)
    oBarra.Visible=.T.
    DEFINE BAR 9 OF Opciones ;
    PROMPT "Ocultar Barra de Herramientas"

    ELSE

    oBarra.Visible=.F.
    RELEASE oBarra
    DEFINE BAR 9 OF Opciones ;
    PROMPT "Ver Barra de Herramientas"

    ENDIF

    Y con esto habríamos concluido la transformación. Como se ha podido comprobar no es muy difícil. Sobre todo hay que recordar la continua utilización de la propiedad ShowWindow y tener cuidado de que al no existir el objeto _SCREEN tenemos que referenciar a los formularios por el nombre del objeto y en el caso de los formularios In Top Level, debemos crear el objeto nosotros. Asimismo, debemos cambiar la forma de llamar al menú y a las barras de herramientas.

    No todas las aplicaciones son susceptibles de ser cambiadas a SDI. Por ejemplo, en una de gestión es absurdo que las ventanas sean independientes ya que todas tienen relación. Lo que sí es algo a considerar seriamente es eliminar definitivamente de nuestras aplicaciones la ventana de VFP porque el arranque es mucho más limpio y también más rápido.

    Rubén iglesias es Director del Centro Informático del País Vasco. Imparte cursos de FoxPro y de otras aplicaciones. Es miembro fundador y Presidente del GUF-E. Se puede contactar con él por e-mail en jj.cipv@sharente.es o en CIS 100561,2165 (Compuserve).