Restyling FoxFace -- > FoxFace II

02/04/2020 Capítulo anterior: FoxFace

 

Autor del proyecto FoxFace: RetailSystems http://www.retailsystems.cz/foxfaceEn.htm

Al igual que FoxRibbon 0.14 de Guillermo Carrero, FoxFace me ha enganchado. Debido al Corona Virus, estamos tranquilamente desde el 15 de Marzo con el Pc en casa y sin salir, y la verdad que esto me sirve de pasatiempo y me desconecta del mundo exterior. Esta temporada le he dedicado tiempo a esta Web, y ahora quiero hacer el manual de FoxFace y compartir con los lectores la puesta en funcionamiento, ajustes, mejoras y conclusiones.

Aquí le explico como he mejorado la clase. No remito a nadie la clase terminada para descarga. Si usted sigue estas instrucciones, puede tener la clase con mi mejora.

 

Restyling FoxFace -- > FoxFace II

Estoy modificando la clase foxface.vcx para mejorarla en lo que esté en mi mano.

Lo primero que hice fue reestructurar los directorios a mi gusto. Posteriormente fue necesario tocar el código en las llamadas a las bases de datos, carpeta data.

FoxFace 2.0 Es la carpeta donde se encuentra el proyecto y que tiene las siguientes subcarpetas:

config.fwp -> Archivo de configuración.

config.ini -> Lo lee FoxFace al iniciar. En el esta el nº de skin, de 1 a 6, que vamos a utilizar. Cualquier valor diferente nos deja la ventana sin skin.

foxface.VBR y fosface.tlb -> Estos archivos los crea FoxFace. Se pueden borrar pero aparecen en la próxima ejecución de FoxFace.

Las carpetas de imágenes con skins no se necesitan, pues están en campos memo de la tabla foxface.dbf.

Carpeta Data

Para las bases de datos he creado la carpeta Data donde he alojado las bases de datos y tenemos que modificar en la clase FoxFace el método skin USE data\foxface.dbf IN 0 SHARED

errores.dbf -> Aquí se almacenan los errores en tiempo de ejecución.

foxface.dbf -> Tabla con los skins. En el formulario config.scx Combo1: USE data\foxface.dbf IN 0 y FoxFace.vcx

foxface.fpt -> Memo

Carpeta Docs

FoxFace changelog.pdf en checo. Vea Registro de cambios de FoxFace

Notas FoxFace.docx -> Mis notas personales

Carpeta Img

Carpeta donde almaceno las imágenes que utilizo

Carpeta Menus

Los menús que venían con FoxFace. Se han personalizado y dado funcionalidad

Carpeta Prog

main.prg

salir.prg -> Programa para salir de FoxFace desde la ventana principal en main.prg -> ON SHUTDOWN salir()

Carpeta Scx

config.scx -> Maneja el config.ini. Abre el archivo y le podemos indicar el nº de skin a utilizar. Luego lo guarda. Cuando iniciamos de nuevo FoxFace vemos los cambios.

formul1.scx -> Formulario de ejemplo.

menu.scx -> Formulario de mi autoría con un pequeño menú para probar FoxFace.

test.scx -> Formulario de ejemplo.

Carpeta Vcx

foxface.vcx -> la clase Vfp que estamos tratando

 

Inconvenientes de FoxFace al maximizar y en los botones Command

Los problemas mayores se presentaban al maximizar la ventana principal y los formularios de nivel superior:

  • la tercera parte superior de la barra de títulos sobrepasaba los límites de nuestra pantalla
  • tapaba la barra de Windows (barra inferior de la pantalla)

Lea primero Aplicaciones sin barra de títulos y se dará cuenta de lo que es un maximizado simulado.

El problema en skin de los botones Command se produce cuando la propiedad .ignorebuttons -> .F. que indica que aplique skin a los Commad. Les aplica bien el skin, pero a partir de aquí le es indiferente si queremos decirle al Command this.command1.enabled = .F., this.command1.visible = .F., etc., pues no va a alterar para nada el funcionamiento.

 

La librería Foxface.vcx

Contiene las siguientes clases:

Y aquí sus métodos y propiedades. La clase formimage está vacía.

clineresize

ctomovezone

ffmessagebox

formcontrol

foxbutton

foxface

Estoy trabajando en esta clase.

 

Modificaciones efectuadas en FoxFace

1. Elimino archivos y carpetas que no tienen que ver con el proyecto para trabajar sólo en el ejemplo FoxFace.

2. Carpeta raíz FoxFace 2.0 y nueva estructura de subcarpetas que ya ha visto al inicio.

3. Incorporo Config.fpw archivo de configuración:

SCREEN=off

*RESOURCE=off -> Cuando estoy en un proyecto lo utilizo y el asterisco equivale a ON

4. Nueva carpeta Img -> Para las imágenes que utilizo

5. En la carpeta Data Renombro chyby.dbf -> errores.dbf

Colocar código correspondiente en main.prg: IF NOT FILE ( "data\errores.DBF") y modifico lo relacionado con esta tabla.

6. Reescribo main.prg y personalizo a mi gusto.

7. Creo el programa salir.prg para salir de FoxFace desde la ventana principal, en main.prg -> ON SHUTDOWN salir()

8. En la carpeta Menus les doy funcionalidad a los menús y elimino idioma checo

9. Clase FoxFace

9.1 Nueva propiedad multiscreen que sirve para indicar si vamos a utilizar un solo monitor .F. o varios .T.

9.2 Propiedad libpath Indica el directorio donde se encuentra la librería Foxface.vcx. Renombro lib\foxface.vcx. -> vcx\foxface.vcx

9.3 Nueva propiedad dataskin Indica el directorio y nombre de la base de datos que contiene los skins que utiliza FoxFace. En mi caso data\foxface.dbf. En el método skin (9.7) se reemplazó USE data\foxface.dbf IN 0 SHARED -> USE (this.dataskin) IN 0 SHARED. Esto me permite en un momento dado utilizar una tabla con distinto nombre, pero con la misma finalidad.

9.4 En el init introduzco el siguiente código como recordatorio para cuando arrastramos la clase a nuestro formulario. Una vez en el formulario la clase se llama FoxFace1 o cualquier oro nombre que se nos ocurra. si miramos FoxFace1.init -> Ver código heredado solo tenemos que copiar el siguiente código y pegarlo en el FoxFace1.init y quitarle los * para activarlo. Así le indicamos como utilizar el archivo config.ini

Esto está en FoxFace1.init -> Ver código heredado.

Se pega en FoxFace1.init y se deja así:

*- Copie y pegue en el init de su nuevo objeto FoxFace
*lh=FOPEN("config.ini")
*this.skinid=val(FGETS(lh))
*FCLOSE(lh)
*DODEFAULT()
*----------------------------------------------------

*- Copie y pegue en el init de su nuevo objeto FoxFace
lh=FOPEN("config.ini")
this.skinid=val(FGETS(lh))
FCLOSE(lh)
DODEFAULT()

*----------------------------------------------------

Y listo, nuestra clase ya funciona según el skin que encuentra en config.ini

También puede funcionar si cambia this.skinid=val(FGETS(lh)) por this.skinid= x (siendo x un número de 1 a 6 y cualquier otro nº lo dejara sin skin). Puede ahorrarse todo el código y ponerlo directamente en la propiedad de FoxFace1.skinid.

Manualmente usted puede abrir cada formulario con un skin diferente, yo sólo le cuento las posibilidades.

9.5 En el método drawborders. Algo personal que no altera el funcionamiento, pero que a mí personalmente me gusta mas. Utilicé el comando WITH thisform -> Todo eran thisform. WITH ... ENDWITH ofrece una forma cómoda de especificar un conjunto de propiedades para un solo objeto. Tenga en cuenta que también puede ejecutar métodos desde una estructura WITH ... ENDWITH.

               *IF .WindowState= 0 AND .MaxButton= .T. && Eliminamos y sustituimos por FWindowState
                IF .maximg.FWindowState= 0 AND .MaxButton= .T.
                  .maximg.picture=SYS(2023)+"\maximg1."+.maximg.image
                  .maximg.stdimg=SYS(2023)+"\maximg1."+.maximg.image
                  .maximg.overimg=SYS(2023)+"\maximg2."+.maximg.image
                  .maximg.clickimg=SYS(2023)+"\maximg3."+.maximg.image
                  .maximg.disableimg=SYS(2023)+"\maximg4."+.maximg.image
                ENDIF 
               *IF .WindowState= 2 AND .MaxButton= .T. && Eliminamos y sustituimos por FWindowState
                IF .maximg.FWindowState = 2 AND .MaxButton= .T.
                   .maximg.picture=SYS(2023)+"\stdimg1."+.maximg.image
                   .maximg.stdimg=SYS(2023)+"\stdimg1."+.maximg.image
                   .maximg.overimg=SYS(2023)+"\stdimg2."+.maximg.image
                   .maximg.clickimg=SYS(2023)+"\stdimg3."+.maximg.image
                   .maximg.disableimg=SYS(2023)+"\stdimg4."+.maximg.image
                 ENDIF 

9.6 En el método setproperties he cambiado el siguiente código:

              *- Camf En un maximizado por simulación WindowState siempre es # 2 Maximizado
              *- Por lo tanto elimino las siguientes lineas y las remplazo por las de abajo
              *- Tengo pendiente decir lee estado de FwindowState que en un maximizado simulado equivale a WindowState

                *IF setOffset=1 AND thisform.WindowState<>2
                 IF setOffset=1
                   thisform.Width=this.parent.Width+lz+rz
                   thisform.Height=this.parent.Height+tz+bz
                 ENDIF 
                *IF setOffset=-1 AND thisform.WindowState<>2
                 IF setOffset=-1
                   thisform.Width=this.parent.Width-(lz+rz)
                   thisform.Height=this.parent.Height-(tz+bz)
                 ENDIF 

Lea aplicaciones sin barra de títulos y se dará cuenta del porque de este cambio ya que vamos a utilizar un maximizado simulado.

Nota: Aquí tengo que pulir un poco el código, pero precisamente estoy trabajando en el proyecto

9.7 En el método skin utilicé WITH thisform, sin alterar el funcionamiento. También hice la modificación que explico en el apartado 9.3

En el apartado ***Buttons se ha insertado la siguiente línea;

thisform.maximg.MultiScreen=this.MultiScreen && Camf ---------------------------------

Y lo que hace es cambiar el valor de la propiedad que he creado en el evento init de la clase formcontrol (.ADDPROPERTY("MultiScreen", .F.)), indicando si trabajamos en multipantalla.

9.8 El método skinbuttons no tiene modificaciones.

10. Clase clineresize -> Sin modificaciones

11. Clase ctopmovezone -> Sin modificaciones

12. Clase ffmessagebox -> Trabajando en ella. es como MessageBox del sistema pero adaptada a FoxFace

13. Clase formcontrol -> Maneja el uso de la botonera maximizar,restaurar, minimizar de la barra de títulos. Cómo ya sabemos, la barra de títulos es personalizada, y en la ventana donde se utiliza, tenemos la propiedad titlebar=0 desactivada. Aquí es donde creamos la simulación del maximizado. Tenga en cuenta que es posible utilizar con FoxFace, tanto en la ventana principal como en formularios la barra de títulos del sistema, donde no se necesita la simulación de maximizado.

13.1 En el método init vacío en origen, se han añadido las siguientes propiedades que van a memorizar posteriormente en el método setparamform las coordenadas de la ventana en estado normal, justo antes de simular el maximizado. A esto le llamo el sistema de memoria.

FwindowState se encarga de informar del WindowState actual simulado. Si ha leído el artículo Aplicaciones sin barra de títulos, ya sabe que el WindowState real es siempre 0 -> Normal en un sistema simulado. Por eso cuando nuestra ventana simula maximizado tenemos que informar de algún modo que esto está sucediendo, y para eso está FwindowState. Otra cosa que sucede al simular max. es que la propiedad BorderStyle cambia su valor a 0 y para ello FormBorder memoriza el valor antes de que se maximice la ventana. MultiScreen ha recibido la información (en el punto 9.7) del método skin de la clase FoxFace, y ya sabemos si estamos trabajando o no en multipantalla. El resto son las coordenadas que no necesitan explicación.

            *-- Camf -- he añadido este código
            WITH THIS
              .ADDPROPERTY("FwindowState", 0) && .WindowState toma su valor
              .ADDPROPERTY("FormLeft", 0)
              .ADDPROPERTY("FormTop", 0)
              .ADDPROPERTY("FormHeight", 0)
              .ADDPROPERTY("FormWidth", 0)
              .ADDPROPERTY("FormBorder", 0)
              .ADDPROPERTY("MultiScreen", .F.)
 
              .SetParamForm()
 
            ENDWITH

13.2 Aquí en el evento mouseup, en nuestro caso, tiene lugar la simulación de maximizado y la memoria setparamform viene en el punto siguiente, 13.3

             IF this.type=1
               This.FWindowState = 1
               thisform.WindowState= 1 
             ENDIF 
             WITH ThisForm
               IF this.type=2
                 IF .SHOWWINDOW # 2 AND .Name # "Screen" 
                   This.FWindowState = IIF(This.FWindowState = 0, 2, 0)
                   .WindowState = IIF(.WindowState = 0, 2, 0)
   
                 ELSE
                   *- Tomamos las medidas que hemos guardado previamente en propiedades
                   IF This.FWindowState = 2
                     This.FWindowState = 0	&& FWindowState siempre primero que el redimensionado 
                     .BORDERSTYLE = THIS.FormBorder
                     .LEFT   = THIS.FormLeft
                     .TOP    = THIS.FormTop
                     .HEIGHT = THIS.FormHeight
                     .WIDTH  = THIS.FormWidth
   
                   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 && 21
                       *- Si no tenemos seleccionadas varias pantallas
                       IF !This.MultiScreen 
                         lnTopSysMenu = 20 && 21
                       ENDIF
   
                     ENDIF
   
                     *- Si tenemos activado STATUS BAR en la ventana principal
                     IF SET("STATUS BAR") = "ON" AND .Name = "Screen" 
                       lnHeightStatusBar = 25
                     ENDIF
                     *- Si tenemos seleccionadas varias pantallas
                     IF This.MultiScreen 
                       lnLeftMultiScreen = .LEFT + 8
                       lnTopMultiScreen  = .TOP  + 8
                     ENDIF
   
                     *.LockScreen = .T.
                     *- Maximizado por simulación
                     *- Primero FWindowState 
                     This.FWindowState = 2
                     *- Situamos  las coordenadas
                     .LEFT   = 0 + lnLeftMultiScreen 
                     .TOP    = 0	+ lnTopMultiScreen + lnTopSysMenu 
                     * Redimensionamos alto y ancho 
                     .WIDTH  = Sysmetric(1) 
                     .HEIGHT = Sysmetric(2) - (Sysmetric(2) - Sysmetric(22) - Sysmetric(9)) - lnHeightStatusBar - lnHeightSysMenu 
                     *.LockScreen = .F.
   
                   ENDIF
                 ENDIF
               ENDIF 
               IF this.type=3
               
                 *- Camf - Salir de la ventana principal de Windows
                 IF .Name ="Screen" 
                   QUIT
                 ELSE
                   .Release
                 ENDIF
   
               ENDIF 
             ENDWITH 

13.3 el nuevo método setparamform. El sistema de memoria de nuestro maximizado por simulación.

             *-- CaMF -- Método y Código -- Almacena medidas de ventana antes de maximizar
             WITH THISFORM
               THIS.FormBorder   = .BORDERSTYLE
               THIS.FormLeft     = .LEFT
               THIS.FormTop      = .TOP
               THIS.FormHeight   = .HEIGHT
               THIS.FormWidth    = .WIDTH
               THIS.FwindowState = 0
             ENDWITH

14. Clase formimage -> Sin modificaciones

15. Clase foxbutton -> Sin modificaciones

16. Clase gpimage -> Sin modificaciones

Y aquí concluimos las modificaciones. Estoy seguro de que me quedan muchas cosas por pulir, pero ahora FoxFace es otra cosa.

 

Propiedades y métodos en la clase FoxFace

En azul las que se pueden modificar

Métodos

.drawbordes

.messagebox -> Método que se llama para obtener un MessageBox personalizado. Utiliza los mismos parámetros que MessageBox.

.setproperties

.skin

.skinbuttons

Propiedades

.dataskin - > Indica el directorio y nombre de la base de datos que contiene los skins que utiliza FoxFace. Nueva propiedad

.firstskin -> .T. es el valor predeterminado. De uso interno.

.ignorebuttons -> .F. Es el valor predeterminado. If .T. then buttons aren't skinned. .T. Ignora el skin en botones.

.isborderstyle -> 3 es el valor predeterminado. Toma la información de BorderStyle. Uso interno.

.istitlebar -> 0 es el valor por defecto. Desconozco funcionamiento.

.libpath El directorio donde se encuentra la librería Foxface.vcx cuando se descarga de sus sitio de origen es lib\foxface.vcx. Yo utilizo para las librerías un directorio Vcx, por lo tanto hay que tener en cuenta esto y mi valor actual es vcx\foxface.vcx

.lmaxx -> .F. Valor predeterminado.

.lmaxy -> .F. Valor predeterminado.

.msgbox -> Propiedad protegida

.multiscreen --> Indicar si vamos a utilizar un solo monitor .F. o varios .T.. Con la propiedad en .F. conseguimos una mejor y más rápida simulación de maximización de la ventana. Con .F. la ventana puede estar en cualquier monitor, excepto cuando maximizamos que lo hará siempre en la ventana principal. Nueva propiedad

 

.skinid -> 0 Valor que tengo asignado por defecto - De 1 a 6 son los skins que vienen por defecto con FoxFace. Lo habitual es configurar FoxFace para que esta información funcione a partir de config.ini. Lo que hacemos es sustituir el valor de skinid al leer config.ini. Una vez que ya tenemos esta información, tomamos los parámetros necesarios de la tabla foxface.dbf

.version - > 2.0 Versión que utilizamos de FoxFace. Propiedad protegida.

FoxFace

 

 

Parámetros:

La llamada la hacemos al evento Skin --> FoxFace.Skin( setOffset, isTitleBar )

setOffset as Integer

isTitleBar as Integer

Determina si se deben mover elementos para formar

Determina si el formulario debe tener bordes, pero desafortunadamente el método de máscara no puede use el valor establecido del parámetro TitleBar, ya que cambia a 0 después de cada escala

1 movimiento lejos del borde -> 1 alejarse del borde

0 - sin barra de título de FoxFace. Siempre utiliza las barras Vfp. Respeta TitleBar=0 o 1 pero cambia si: Ver conclusiones

Equivale a TitleBar = 0 pero sin borde en la pantalla

-1 volver al borde

1 - con TitleBar - Siempre barra FoxFace. No respeta TitleBar=0 o 1

0 dejar como están

2 - mantiene la configuración anterior. Es neutral. no cambia el estado de la barra de titulo. Sirve para cuando solo queremos manejar el setOffset

-1 Nos deja la pantalla sin bordes desplazables y sin barra de titulo

 

normalmente deja 0 solo cuando enciende o apaga la barra de título, así que use 1 o -1 para colocar los elementos en la ventana

 

-1 arrastra los objetos al exterior del borde

1 hacia dentro

Si primero La opción a utilizar por defecto es

_SCREEN.foxface1.skin(0, 1)

 

Esto es lo que utiliza la clase en el evento init

     IF thisform.TitleBar=1  && -> Barra de títulos activada
        this.skin(1,1)
     ELSE                    && ->  Barra de títulos desactivada
        this.skin(0,0)
     ENDIF 

En _Screen creamos el objeto FoxFace1 por ej.:

  • _SCREEN.NewObject("FoxFace1","FoxFace","lib\foxface.vcx") && Creamos el objeto

Elegimos si queremos o no barra de títulos :

  • _SCREEN.TitleBar = 1 && 0 Desactivado - 1 Activado

Y luego hacemos la siguiente llamada:

  • _SCREEN.foxface1.skin(setOffset, isTitleBar)

A continuación pulse sobre las imágenes para ampliar

 

El mismo resultado resultado:

_SCREEN.foxface1.skin(-1, 0)

_SCREEN.foxface1.skin(0, 0)

_SCREEN.foxface1.skin(1, 0)

 

_SCREEN.foxface1.skin(-1, 2)

_SCREEN.foxface1.skin(0, 2)

_SCREEN.foxface1.skin(0, 2)

Siempre barras de Vfp

_SCREEN.TitleBar = 1

Figura 3 - Barra de Vfp

_SCREEN.TitleBar = 0

Figura 4 - Sin barra Vfp

 

_SCREEN.foxface1.skin(-1, 1) -> independientemente del titlebar

_SCREEN.foxface1.skin(0, 1)

_SCREEN.foxface1.skin(1, 1)

Siempre sale la barra de FoxFace sin importar TitleBar= 1 o 0

_SCREEN.TitleBar = 1

Figura 5 - Barra de Vfp

_SCREEN.TitleBar = 0

Figura 6 - Sin barra Vfp

 

Conclusiones:

La opción a utilizar por defecto es _SCREEN.foxface1.skin(0, 1)

Luego ya utilizamos las otras opciones:

_SCREEN.TitleBar = 1

_SCREEN.foxface1.skin(0, 1)

_SCREEN.foxface1.skin(-1,0) - o - _SCREEN.foxface1.skin(0,0) - o - _SCREEN.foxface1.skin(1,0)

Esto ahora nos ha quitado la barra de título y nos ha dejado un borde no ajustable en la ventana. Amplíe la figura 4 y se nota un pequeño rectángulo en la parte superior en Windows 10 debido a que el borde es ajustable. Por lo que deducimos que isTitleBar=0 Equivale a TitleBar=0 dejando la ventana sin borde ajustable.

hasta donde hemos llegado setOffset no ha surtido ningún efecto

Figura 7


 

 

Capítulos

 

Vea también

 

 


 

No olvide de hacer una donación a RetailSystems, para que pueda continuar mejorando este proyecto.

 

Referencias

Autor del proyecto FoxFace: RetailSystems http://www.retailsystems.cz/foxfaceEn.htm

Restyling a FoxFace II -- >: Camf.

 


 

 

 



error: Contenido protegido