Ventanas sin barra de títulos en Visual FoxPro - ¿Cómo funcionan?

24/04/2020

 

Autor: Camf

 

Hoy vamos a comentar sobre las ventanas de Visual FoxPro y que sucede cuando las utilizamos sin la barra de títulos.

Mis observaciones se hicieron trabajando con Windows 10 en los objetos Form de Visual FoxPro 9

 

Objetos Form en Vfp

  • Screen es la ventana principal de Vfp y actúa de la misma manera que un formulario de nivel superior
  • En los formularios tenemos tres tipos de ventanas dependiendo del valor de la propiedad ShowWindow:
    Form.ShowWindow[ = nExpr]                

    Propiedad ShowWindow

    Descripción

    0

    En pantalla (valor predeterminado). Se trata de un formulario secundario que está colocado en la ventana principal de Visual FoxPro.

    1

    En formulario de nivel superior. Se trata de un formulario secundario del formulario de nivel superior activo, que puede ser la ventana principal de Visual FoxPro u otro formulario de nivel superior. Use esta opción si desea colocar el formulario secundario dentro del formulario de nivel superior activo.

    Si nExpr está establecido en 1 cuando el formulario de nivel superior es la ventana principal de Visual FoxPro, Visual FoxPro restablecerá automáticamente nExpr en 0.

    2

    Como un formulario de nivel superior. Se trata de un formulario de nivel superior en el que se pueden colocar formularios secundarios. Observe que un formulario de nivel superior es siempre no modal, independientemente de lo establecido en la propiedad WindowTypeNo hace caso al valor de la propiedad Desktop y entiende siempre un valor de .T.. El formulario puede estar en cualquier parte del escritorio de Windows.

Observaciones:

Un formulario secundario es un formulario que se encuentra dentro de otro. Los formularios secundarios no se pueden mover fuera de los límites de su formulario primario; cuando se minimizan, aparecen en la parte inferior del formulario primario. Si se minimiza un formulario primario, también se modificarán los secundarios.

Un formulario de nivel superior es un formulario independiente no modal, que sirve para crear una aplicación SDI (interfaz de un solo documento, single document interface) o para utilizarse como el primario de otros formularios secundarios. Los formularios de nivel superior funcionan al mismo nivel que otras aplicaciones de Windows y pueden aparecer por delante o por detrás de ellas. Los formularios de nivel superior aparecen en la barra de tareas de Windows.

La propiedad Desktop determina el comportamiento de un formulario secundario. Si la propiedad Desktop está establecida en el valor verdadero (.T.), el formulario secundario no estará limitado a los bordes de su formulario primario y podrá desplazarse a cualquier sitio dentro del escritorio de Windows. El formulario secundario no aparece en la barra de tareas de Windows.

 

¿Como utilizamos una ventana sin barra de títulos?

Dependiendo del valor de la propiedad TitleBar:

  • TitleBar = 0 -> Sin barra de títulos
  • TitleBar = 1 -> Con barra de títulos

 

¿Como maximizamos nuestras ventanas si no tenemos una barra de títulos?

Todo depende del valor de la propiedad WindowState.

Especifica si una ventana de formulario se muestra maximizada, minimizada o normal en tiempo de ejecución. Está disponible en tiempo de diseño y en tiempo de ejecución.

0 - Normal

1 - Minimizada (reducida a un icono). Si se minimiza la ventana principal de Visual FoxPro al salir de Visual FoxPro, no se mostrará esta ventana antes de salir de la aplicación. Si su aplicación muestra un cuadro de diálogo antes de salir, no olvide establecer _SCREEN.WindowState en 0 antes de mostrar el diálogo en pantalla.

2 - Maximizada (aumentada hasta llenar la pantalla).

Ejemplo:

Suponga que en una ventana sin barra de títulos tenemos un botón para esta función. Cada vez que lo pulsamos maximiza o restaura la ventana a su estado inicial.

El siguiente código es totalmente válido:

     With This
       .WindowState = IIF(.WindowState = 0, 2, 0)
     EndWith

 

Configuraciones de la propiedad BorderStyle para un objeto Form

Valor

Descripción

Ancho en píxeles

0

Sin borde

0

1

Borde de línea sencilla

2

2

Borde de línea doble

4

3

(Valor predeterminado) De tamaño ajustable

8

Cuando utilizamos la propiedad TitleBar = 1 en Windows 10 no se aprecian diferencias visuales utilizando los diferentes valores de BorderStyle.

No ocurre lo mismo cuando lo utilizamos con TitleBar = 0 (sin barra de títulos) donde si diferenciamos claramente el borde según el valor asignado.

 

Problemas

Las anomalías que se pueden apreciar, debido a un problema de Visual FoxPro, al maximizar una ventana sin barra de títulos se aplican a los siguientes objetos Form:

  • La ventana principal
  • Los formularios de nivel superior -> ShowWindow=2
  • En formulario de nivel superior -> ShowWindow=1 cuando Desktop = .T.
  • En formulario en pantalla -> ShowWindow=0 cuando Desktop = .T.

Ahora las anomalías:

1.- La ventana ocupa la totalidad (Width) del alto de la pantalla con la consecuencia de que invade la zona de la barra de tareas de Windows, quedando esta fuera de nuestra visión.

2.- En el maximizado se incluye el borde que no es visible por lo que explico en el punto nº3

3.- Cuando utilizamos la ventana principal o un formulario con ShowWindow=2 ocurre además un desbordamiento de pantalla, no apreciable a simple vista si tenemos un BorderStyle = 3. El desbordamiento total siempre es de 8 píxeles en cada lado. Me refiero a que las dimensiones totales de la ventana son mas grandes que las de nuestra pantalla, con lo cual la botonera de la barra de títulos, que es la zona donde mas se aprecia, se queda muy pegada al borde superior de la pantalla.

El maximizado tiene la característica de que también nos incluye el borde. Ese es el motivo por el cual en BorderStyle = 3 (8 píxeles) no apreciamos desbordamiento, pero en realidad el borde ha quedado invisible para nosotros. Una forma de verlo a primera vista es cuanto trabajamos con un sistema multi-pantallas, donde se ve claramente el desbordamiento en la pantalla colindante.

    1. BorderStyle = 3 -> desbordamiento no apreciable -> 8 píxeles del borde que queda oculto.
    2. BorderStyle = 2 -> desbordamiento apreciable -> 4 píxeles + 4 píxeles del borde.
    3. BorderStyle = 1 -> desbordamiento apreciable -> 6 píxeles + 2 pieles del borde.
    4. BorderStyle = 0 -> máximo desbordamiento apreciable -> 8 píxeles + 0 píxeles del borde.

Siempre que se haga la corrección total de 8 píxeles por cada lado, al maximizar veremos el borde que previamente hemos indicado en la propiedad BorderStyle.

Para que se entienda mejor, voy a redimensionar una ventana maximizada sin barra de títulos con el siguiente código:

     With this
       .Titlebar = 0
       .BorderStyle = 0
       .WindowState = 2
       * Tenemos ya la ventana sin barra de título maximizada pero con desbordamiento
       * Ahora con el siguiente código vamos a corregir el desbordamiento
       .Top = .Top + 8
       .Width = Width - 16
       .Left = Left + 8
       .Height = Height - 16
     EndWith

Ahora ya tenemos en su sitio la ventana, pero seguimos con la barra de Windows oculta, y además ahora estamos en WindowState = 0.

Tenga en cuenta que si a una ventana en WindowState = 2 (maximizada), le cambiamos cualquier valor de dimensiones o posición, pasará automáticamente a WindowState = 0. Tal y como he modificado las dimensiones y coordenadas ha quedado la ventana en WindowState = 0.

Ahora las dimensiones son estas, dependiendo del estado.

  • Estado Normal WindoState = 0 -> Ventana con dimensiones corregidas
  • Estado Maximizado = 2 -> Las dimensiones y posiciones con el desbordamiento de pantalla.

Trabajando en Windows 10 y con TitleBar = 1, independientemente del BorderStyle que utilicemos, no veremos la diferencia en la ventana. Con BorderStyle = 3 tenemos un borde que nos permite ajustar la ventana. Con TitleBar = 0 si que observamos las diferencias en los bordes dependiendo del valor de BorderStyle.

4.- Cuando utilizamos un formulario con ShowWindow = 1 ó 0 y Desktop = .T.

No presenta desbordamiento utilizando cualquier valor de la propiedad BorderStyle. Cuando maximizamos la ventana se nos muestra el borde que estamos utilizando. presenta la anomalía del punto nº 1

5.- Cuando utilizamos un formulario con ShowWindow=1 y Desktop = .F.

Al maximizar una ventana no cambiara su BorderStyle.

Como podemos ver, Visual FoxPro nos esta poniendo las cosas difíciles si intentamos trabajar en una ventana sin barra de títulos.

 

¿Cómo podemos solucionar esto?

¿Qué es simular un maximizado?

Es redimensionar una ventana con un valor de su propiedad WindowState = 0 al mismo tamaño que cuanto su propiedad WindowState = 2

Simular el maximizado no es un inconveniente. Las herramientas que menciono en el artículo Herramientas que no utilizan la barra de títulos de Visual FoxPro simulan el maximizado excepto FoxFace.

Voy a poner un ejemplo fácil que el lector puede comprobar.

Voy a mirar las propiedades siguientes en mi ventana principal Visual FoxPro con el valor WindowState = 0 (Normal) y WindowState = 2 (Maximizada), pero teniendo en cuenta que yo tengo dos pantallas, voy a anotar los valores que obtengo en las dos:

Primero situamos en la pantalla principal la ventana de Vfp y anotamos valores y posteriormente desplazamos la ventana a la siguiente pantalla y repetimos el proceso.

WindowState = 0 (Normal)

WindowState = 2 (Maximizada)

BorderStyle -> valores para un objeto Form

  • 0 Sin borde
  • 1 Borde de línea sencilla
  • 2 Borde de línea doble
  • 3 (Valor predeterminado) De tamaño ajustable

Figura 2

Propiedad

Monitor principal

Segundo Monitor

WindowState

0 - Nor

2- Max

0 - Nor

2- Max

BorderStyle

3

3

3

3

Left

196

0

2143

1920

Top

325

76

333

76

Height

527

940

527

940

Width

1395

1920

1395

1920

 

En esta tabla ya podemos sacar unas conclusiones, que tal vez antes no sabíamos sobre este tema que yo considero tan interesante:

  • BorderStyle -> Su valor no cambia independientemente del valor de WindowState y aunque su valor sea 3 tamaño ajustable no se deja ajustar si la ventana está maximizada WindowState = 2 (Maximizada)
  • Left -> Podemos ver en el segundo monitor cuando WindowState = 2 (Maximizada) que coincide con el valor Width de la primera pantalla, es decir, donde termina la primera pantalla comenzaría la segunda.
  • Top - > El valor cambia cuando WindowState = 0 (Normal) de una pantalla a otra, puesto que cuando arrastré la ventana al segundo monitor no coincidía el valor de Top. Cuando maximizamos observamos en los dos monitores un valor de 76 y no de 0. Esto es debido a que no se tiene en cuenta la altura de la barra de título, el menú y la barra de herramientas. Si le damos un valor a Top de 0 podemos comprobar como desaparece la barra de títulos, el menú y la barra de herramientas de nuestra pantalla. Ahora desacoplamos la barra de herramientas obtenemos un valor de 43 al maximizar la ventana.
  • Height y Width vemos que mantiene los mismos valores en los dos monitores, puesto que son de la misma resolución.

Ahora, con la ventana en estado normal (WindowState = 0 (Normal)), vamos a proceder de la siguiente manera para simular el maximizado:

Como no todos los lectores disponen de dos monitores, vamos a asignar los valores que hemos obtenido en la tabla anterior, cuando WindowState = 2 (Maximizada)en el monitor principal, es decir:

  • BorderStyle = 3
  • Left = 0
  • Top = 76
  • Height = 940
  • Width = 1920

Ya está todo en mi caso pero veo que no he conseguido redimensionar la pantalla al estado de maximizada con los mismos valores. Recuerde que previamente, había desacoplado la barra de herramientas para ver como cambiaba el valor que me indicaba la propiedad Top. Acople de nuevo la barra de herramientas y listo.

Ya tenemos nuestra simulación de maximizado, pero ahora, si miramos nuestra propiedad WindowState comprobamos que su valor es de WindowState = 0 (Normal) y en realidad vemos nuestra pantalla maximizada.

Y para finalizar la explicación, haga clic sobre el botón central de la barra de títulos, maximizar-restaurar ventana y vera como no consigue resultados a simple vista. Esto se debe a que ahora tenemos las mismas medidas en WindowState 0 y 2. Pero no se mueva, todavía no hemos acabado.

Fíjese que el titulo y los botones de la barra de títulos tienen un leve desplazamiento. En WindowState = 0 (Normal) están un poco mas altos. Fíjese también en las tres ventanas de la barra de tareas y vera un movimiento de derecha a izquierda según el valor de WindowState, ¿curioso no?. Por esto entiendo un leve desbordamiento de pantalla.

También puede ver como puede mover la ventana cuando la arrastra desde la barra de título.

¿Nos ha quedado claro lo que es simular un maximizado?

 

Problema al desactivar el TitleBar

Pruebe desde la ventana propiedades de Vfp lo siguiente: TitleBar = 0 (Desactivado) y verá como desactivamos la barra de títulos de la ventana principal _Screen de Visual FoxPro.

Ahora WindowState = 2 (Maximizada) y observamos como se maximiza pero la ventana tapa la barra de Windows. Esto también se aplica a los formularios de nivel superior.

Por este motivo necesitamos recurrir a la simulación de maximizado, descontando del valor de la propiedad Height la altura de la barra de tareas, al maximizar la ventana.

 

¿Cómo diseñamos nuestra simulación de maximizado?

Hasta ahora hemos visto las ventajas e inconvenientes de utilizar una ventana de Vfp sin barra de títulos de sistema (ya sabe que no me refiero a barras de título personalizadas).

En mi caso utilizo una clase para toda la funcionalidad y para el ejemplo se va a llamar _simulates

Propiedades que necesitamos utilizar:

  • TitleBar = 0 (Desactivado)
  • WindowState
  • BorderStyle -> 0 al maximizar
  • Left
  • Top
  • Height
  • Width
  • MultiScreen -> Crearemos una propiedad o variable con un valor lógico para saber si nuestra ventana va a ser multi-pantalla o no
  • FwindowState -> Reemplazara a WindowState para nuestro control

 

Crear un sistema de memoria

Necesitamos almacenar las posiciones de la pantalla, el alto y el ancho y el tipo de borde

En el evento init

WITH THIS
 .ADDPROPERTY("FwindowState", 0)
 .ADDPROPERTY("FormLeft", 0)
 .ADDPROPERTY("FormTop", 0)
 .ADDPROPERTY("FormHeight", 0)
 .ADDPROPERTY("FormWidth", 0)
 .ADDPROPERTY("FormBorder", 0)
 .SetParamForm()
ENDWITH

Con el diseñador de clases abrimos nuestra clase _simulates y le añadimos la propiedad MultiScreen

Método que maneja la memoria -> SetParamForm

Desde el diseñador de clases creamos el método SetParamForm

Introducimos el siguiente código:

WITH THISFORM
  THIS.FormBorder   = .BORDERSTYLE
  THIS.FormLeft     = .LEFT
  THIS.FormTop      = .TOP
  THIS.FormHeight   = .HEIGHT
  THIS.FormWidth    = .WIDTH
  THIS.FwindowState = 0
ENDWITH

Mas cosas a tener en cuenta

  • Si nuestra ventana es la principal _Screen o en un formulario de nivel superior
  • Si vamos a utilizar el menú -> El de Vfp, no uno personalizado. Sólo en la ventana _Screen
  • Si vamos a utilizar la barra de tareas -> La de Vfp. Sólo en la ventana _Screen.
  • No he previsto en el código el uso de la barra de herramientas

Puede que me falte alguna cosa a tener en cuenta, pero la base ya la tenemos.

El código del método que se encarga de manejar todo

Esta es la llamada que hacemos cuando queremos simular el maximizado.

WITH ThisForm
            
    IF .SHOWWINDOW # 2 AND .Name # "Screen"
        .WindowState = IIF(.WindowState = 0, 2, 0)
    ELSE

        *- Tomamos las medidas que hemos guardado previamente en propiedades
        IF This.FWindowState = 2 
            .BORDERSTYLE = THIS.FormBorder
            .LEFT   = THIS.FormLeft
            .TOP    = THIS.FormTop
            .HEIGHT = THIS.FormHeight
            .WIDTH  = THIS.FormWidth
            This.FWindowState = 0

        ELSE

            *- Guardamos parámetros
            THIS.SetParamForm() 
            .BorderStyle = 0
   
            *- Variables locales para redimensionar las pantallas
            LOCAL lnHeightSysMenu, lnTopSysMenu, lnLeftMultiScreen, lnTopMultiScreen, lnHeightStatusBar 
            lnHeightSysMenu   = 0
            lnTopSysMenu      = 0
            lnLeftMultiScreen = 0
            lnTopMultiScreen  = 0
            lnHeightStatusBar = 0
   
            *- Si tenemos selecionadas varias pantallas
            IF This.MultiScreen 
                .WindowState = IIF(.WindowState = 0, 2, 0)
            ENDIF 
   
          *- Si usamos los menús de Vfp
            IF !SET("SYSMENU") = "OFF"	AND .Name = "Screen" 
                 lnHeightSysMenu  = 20
                 *- Si no tenemos selecionadas varias pantallas
                 IF !This.MultiScreen 
                     lnTopSysMenu = 20
                 ENDIF
            ENDIF
   
            *- Si tenemos activado STATUS BAR en la ventana principal
            IF SET("STATUS BAR") = "ON" AND .Name = "Screen" 
                lnHeightStatusBar = 25
            ENDIF
            *- Si tenemos selecionadas varias pantallas
            IF This.MultiScreen 
                lnLeftMultiScreen = .LEFT + 8
                lnTopMultiScreen  = .TOP  + 8
            ENDIF
   
            *- Situamos  las coordenadas
            .LEFT   = 0 + lnLeftMultiScreen 
            .TOP    = 0 + lnTopMultiScreen + lnTopSysMenu 
            .WIDTH  = Sysmetric(1) 
            .HEIGHT = Sysmetric(2) - (Sysmetric(2) - Sysmetric(22) - Sysmetric(9)) - lnHeightStatusBar - lnHeightSysMenu 
 
            This.FWindowState = 2
        ENDIF
    ENDIF 
ENDWITH

Ahora vamos a analizar el código

IF .SHOWWINDOW # 2 AND .Name # "Screen"

SHOWWINDOW -> 2 Como un formulario de nivel superior. Se trata de un formulario de nivel superior en el que se pueden colocar formularios secundarios. Observe que un formulario de nivel superior es siempre no modal, independientemente de lo establecido en la propiedad WindowType.

Name -> "Screen" Es la ventana principal

Cuando no trabajamos con un formulario de nivel superior y No trabajamos con la ventana principal. Aquí si utilizamos WindowState

.WindowState = IIF(.WindowState = 0, 2, 0)

Si trabajamos en multi-pantallas también utilizo WindowState como puede ver en la siguiente línea

           IF This.MultiScreen
                  .WindowState = IIF(.WindowState = 0, 2, 0)
           ENDIF 

Y el por qué lo utilizo es lo que voy a explicar:

Al utilizar en la segunda, tercera pantalla etc. .WindowState = IIF(.WindowState = 0, 2, 0) ya tengo una referencia .Left de cualesquiera de las pantallas y eso es lo que necesitamos. Recuerde que en la figura 2 al maximizar la ventana el valor de .Left = 1920 y eso es lo que he hecho ahora mismo. Luego mas abajo vemos el siguiente código:

           IF This.MultiScreen
               lnLeftMultiScreen = .LEFT + 8
               lnTopMultiScreen  = .TOP  + 8
           ENDIF

Le sumo al Left actual 8 y al Top 8. Es un valor al que he llegado después de muchas pruebas, pues al utilizar WindowState para maximizar obtenemos un desplazamiento como el que indico. Este desplazamiento coincide exactamente con lo que ya dije al principio, el desbordamiento de pantalla.

Para el resto de los casos interprete el código.

Debido a estas reflexiones he creado la clase OnApp_class.prg que se encarga precisamente de estas cuestiones y se ha incorporado a FoxRibbon Camf v 0.45 en la clase _TitleBar de la biblioteca FoxRibbon.

  

Vea también

 


 

Referencias

Autor: Camf

 

 

 



error: Contenido protegido