Ventajas de adicionar propiedades a _SCREEN

1,894 views
Skip to first unread message

Jose Luis Barros

unread,
Feb 12, 2013, 12:45:41 PM2/12/13
to publice...@googlegroups.com
He leído en algunos artículos que es una buena práctica agregar propiedades a _SCREEN para que tengan alcance públic. En particular, objetos que se usan en cualquier parte de la aplicación. Se suelen llamar "servicios" de la aplicación.

Yo siempre he tenido la duda de qué tan práctico es esto. La única ventaja que le veo es que la propiedad aparece en IntelliSense, pero en mi caso, ni eso, porque suelo copiar el estado actual del ambiente de desarrollo antes de ejecutar la aplicación, crear todos los servicios en _SCREEN y al finalizar la aplicación, si estoy en ambiente de desarrollo, vuelvo a dejar mi ambiente como estaba antes de ejecutar la aplicación. Es decir, las propiedades que agrego a _SCREEN al iniciar la aplicación, las borro una vez finalizada. Entonces, no las tengo disponibles al editar mi código. Lo hago así, porque suelo tener varias aplicaciones a la vez en desarrollo y así evito posibles errores al hacer referencias a objetos que en realidad no son de la aplicación que estoy revisando.

Siendo así, me pregunto ¿Cuál es la ventaja de crear propiedades en SCREEN? Me parece más engorroso tener que escribir _SCREEN.goMiObjeto.Algo que simplemente goMiObjeto.Algo y declarar goMiObjeto cómo variable pública. ¿Ustedes que opinan?

Gracias de antemano por sus respuestas

Luis Maria Guayan

unread,
Feb 12, 2013, 12:54:43 PM2/12/13
to publice...@googlegroups.com
Yo particularmente creo un objeto Aplicación que llamo oApp y a este objeto si le creo una referencia a _Screen

Ej:
_Screen.oApp.oUser.cName

Luego con solo eliminar el objeto y la referencia a oApp, VFP y _Screen quedan con la configuración correspondiente según mi entorno.

Mis PRG de inicio crean el objeto oApp con :


*-- Creo objeto App
IF VARTYPE(_SCREEN.oApp) = "O"
  _SCREEN.REMOVEOBJECT('oApp')
ENDIF
_SCREEN.NEWOBJECT('oApp','App',FORCEEXT(lcApp,'vcx'))
IF VARTYPE(_SCREEN.oApp) <> "O"
  MESSAGEBOX('No se pudo crear la aplicación [App]',16,'Aviso')
  loLogo = .NULL.
  RETURN
ENDIF

y al final de mi aplicación:

*-- Elimino objeto App
IF VARTYPE(_SCREEN.oApp) = "O"
  _SCREEN.REMOVEOBJECT('oApp')
ENDIF


Luis María Guayán
Tucumán, Argentina
_________________________
http://www.PortalFox.com
Nada corre como un zorro
_________________________

Jose Luis Barros

unread,
Feb 12, 2013, 3:14:31 PM2/12/13
to publice...@googlegroups.com
Gracias Luis María.

Yo hago algo muy parecido. Suelo tener un procedimiento que carga "servicios" al iniciar la aplicación (son muchos más pero sólo muestro estos como ejemplos)":

_SCREEN.ADDPROPERTY("goUser",CREATEOBJECT("Users"))
_SCREEN.goUser.SetUserID()

_SCREEN.ADDPROPERTY("goApp",CREATEOBJECT("App"))
_SCREEN.goApp.Version = 2
_SCREEN.goApp.EmpName = 'XYZ'

Y así sucesivamente con todos los servicios que necesito a nivel global

Al finalizar la aplicación tengo otro método que remueve estos servicios:

IF PemStatus(_SCREEN,"goUser",5)
    _SCREEN.goUser=.NULL.
    REMOVEPROPERTY(_SCREEN, 'goUser')
ENDIF

IF PemStatus(_SCREEN,"goApp",5)
    _SCREEN.goApp=.NULL.
    REMOVEPROPERTY(_SCREEN, 'goApp')
ENDIF

El punto es que no le veo la ventaja a hacer esto usando _SCREEN, En vez de usar objetos públicos. 

Si usara objetos públicos el procedimiento inicial sería:

PUBLIC goUser, goApp

goUser = NEWOBJECT('oUser','Users',FORCEEXT(lcUser,'vcx')) 
goUser.SetUserID()

goApp = NEWOBJECT('oApp','App',FORCEEXT(lcApp,'vcx')) 
goApp.Version = 2
goApp.EmpName = 'XYZ'

Y al finalizar la aplicación simplemente hago un release:

RELEASE goApp, goUser

Me parece que es menos código y hace lo mismo. ¿O existe alguna ventaja adicional usando _SCREEN?

No es que esto vaya a mejorar mi código o a cambiar algo drásticamente. Es simplemente una inquietud de estilo, creo yo.

Fernando D. Bozzo

unread,
Feb 13, 2013, 6:30:17 PM2/13/13
to publice...@googlegroups.com
Hola José Luis:

Realmente no hay ventajas en colgar cosas de _SCREEN, es más, si se cuelgan objetos hasta puede darte algún que otro problema que un objeto público no te dará.
Por ejemplo, es más eficiente --y encapsulado-- la liberación de objetos públicos en memoria (Garbage Collect) que de objetos colgados de _SCREEN, sobre todo cuando hay que manejar errores descontrolados y liberación de referencias de objetos.

El último error que recuerdo que tuve al usar _SCREEN para colgar objetos (con cierta complejidad), fue cuando hice la emulación de BINDEVENT para Visual FoxPro 6 (libreria de emulaciones LIB_VFP en PortalFox), donde inicialmente colgaba el objeto principal de _SCREEN, pero luego resultaba que ciertas referencias de objetos no se liberaban y terminaba en un error C0000005 aleatorio. Al independizar el objeto y hacerlo público, sin modificar más nada, se solucionó todo el problema, y esa implementación sigue en Producción hasta el día de hoy sin ningún error (unos 8 años seguidos)

Hasta ahora no encontré un solo caso que justifique colgar algo de _SCREEN, pero es solo mi experiencia personal.

Saludos.-

Jose Luis Barros

unread,
Feb 18, 2013, 12:04:14 PM2/18/13
to publice...@googlegroups.com
Gracias Fernando, efectivamente era lo que yo hace rato venía pensando. Incluso, yo también tuve problemas de memoria y el famoso error C0000005 que no había pensado que podía ser por el uso de _SCREEN. Bueno, creo que de eso se trata este foro. Aclarar dudas e ir mejorando cada día.

Luis Mata

unread,
Feb 18, 2013, 12:16:55 PM2/18/13
to publice...@googlegroups.com
La idea es tener variables globales, ya sea public o _screen o en todo caso thisform.propiedad.
 
Solo cuando el dato se va a compartir entre varios objetos, se puede hacer esto, perosonalmente no trabajo con variables publicas a menos que sea estrictamente necesario:
 
Ejm:
 
- Periodo de trabajo
- Tipo de Cambio
- Codigo de Sucursal
- Login y permisos de usuarios
y Otros
Si una variable la va a a utilizar un solo objeto cual es la gracia de tener que publicarlo es mas si lo tienes que heredar a otros objeto se lo pasas como parámetro y el otro lo hace suyo. Cuando antes trabajaba con variables publicas me paraba perdiendo en medio de todo el código. ahora que limite a publicar variables y usar en lugar de Public _screen y en los formularios usar propiedades y a pasar parámetros veo mi trabajo mas ordenado.
y Obviamente cada objeto utiliza sus propios datos de esta forma los ejecuto independientemente(Pasando parámetros de ser necesario) y no estoy con los errores “No se encontró variable tal” y tener que recordar donde rayos lo publique.
 
LM

Pablo Daniel Lissa

unread,
Feb 18, 2013, 1:43:46 PM2/18/13
to publice...@googlegroups.com, lm...@cclf.com.pe
Hola:

Como cuestión de gustos, me gusta más usar PUBLIC. Algo importante a tener en cuenta al trabajar con variables públicas es ser ordenado: nombrarlas adecuadamente, definirlas en lugares fácilmente localizables, etc. Parece una pavada (una "tontería" en Argentina, no sé si lo usan en otros países), pero, cuando hay varios programadores, se ve cualquier cosa. En este sentido, enlazarla a _Screen da una referencia visual rápida del sentido de la variable (que no es "la gran" ventaja, en realidad).

Hay veces en que este tipo de variables son inevitables, independientemente de como se implementen. A mí me gusta usar objetos, entonces, la referencia pública es solamente una, pero los datos que contiene, pueden ser varios.

Saludos.

Luis Mata

unread,
Feb 18, 2013, 2:34:58 PM2/18/13
to publice...@googlegroups.com
El que te muestra las variables _Screen al momento de codificar ya es gran cosa sobre Public, porque a este los tienes que estar recordando o memorizando.

Rita Cecila Restrepo De La Hoz

unread,
Feb 18, 2013, 2:50:57 PM2/18/13
to publice...@googlegroups.com
Hola Chicos, un pregunta de novata, yo en lo personal utilizo el public para definir las variables que van en cada objeto y poder trabajar con ellas posteriormente, la pregunta es, existe un comando o rutina para liberar esos public algo como dejarlo en blanco o vaciar los public, perdonen mi ignorancia, pero veo que mucho no utilizan el public, bueno eso es lo que entiendo leyendo sus mensajes.

Gracias.

Rita

José Luis Díaz

unread,
Feb 18, 2013, 2:59:39 PM2/18/13
to publice...@googlegroups.com
Mira en la ayuda RELEASE VARMEM

Saludos

Saludos


José Luis
Leticia, Amazonas, Colombia

From: Rita Cecila Restrepo De La Hoz <ritacecil...@gmail.com>
Date: Mon, 18 Feb 2013 14:50:57 -0500

Rita Cecila Restrepo De La Hoz

unread,
Feb 18, 2013, 3:05:35 PM2/18/13
to publice...@googlegroups.com
Gracias Jose Luis.

Jairo Miranda

unread,
Feb 26, 2013, 6:56:54 AM2/26/13
to publice...@googlegroups.com

EN un objeto timer – en la método timer tengo esto:

 

*clear

SET TALK off

Release xIdUsuario

Public xIdUsuario

xLogin     = Sys(0)

xPos       = At('#',xLogin,1)  

xIdUsuario = Alltrim(SubStr(xLogin,1,(xPos-1)))

Set Delete On

Select tMensajeria

Locate For Alltrim(IdUsuario) = xIdUsuario

If .NOT. Found()

      Wait Windows Alltrim(IdUsuario)+" No Tiene Ningún Mensaje, Presione el Boton Aceptar" NoWait

Else

   **************************************************************************************

      *Verifica si tiene mensajes

   If !Empty(tMensajeria.Mensaje)

       Wait Windows Alltrim(IdUsuario)+" Tiene un Nuevo Mensaje" NoWait

   Endif

 

   **************************************************************************************

Endif

 

Esto me permite verificar si en la tabla de mensajes alguien escribio un mensaje a mi cmputadora.

 

 

Pregunta:

 

Como agregar un Timer en el screen ¿?

 

 

 

JM

Luis Maria Guayan

unread,
Feb 26, 2013, 1:07:14 PM2/26/13
to publice...@googlegroups.com
_Screen.AddObject("oTimer", "Timer")



Luis María Guayán
Tucumán, Argentina
_________________________
http://www.PortalFox.com
Nada corre como un zorro
_________________________

Jairo Miranda

unread,
Feb 26, 2013, 8:03:14 AM2/26/13
to publice...@googlegroups.com

Buenas Tardes Luis M., gracias por el aporte. Esto fue lo que hice en el programa principal ..

 

 

Open database LOCFILE("Datos\Datos1.dbc") share

USE datos\tMensajeria IN 0

 

WITH _Screen

.AddObject("oTimer","Timer")

    .Otimer.Interval = 3000

    .otimer.Timer

      SET TALK off

      xLogin     = Sys(0)

      xPos       = At('#',xLogin,1)  

      xIdUsuario = Alltrim(SubStr(xLogin,1,(xPos-1)))

      Set Delete On

      Select tMensajeria

      Locate For Alltrim(IdUsuario) = xIdUsuario

      If .NOT. Found()

            Wait Windows Alltrim(IdUsuario)+" No Tiene Ningún Mensaje, Presione el Boton Aceptar" NoWait

      Else

         **************************************************************************************

          *Verifica si tiene mensajes

           If !Empty(tMensajeria.Mensaje)

               Wait Windows Alltrim(IdUsuario)+" Tiene un Nuevo Mensaje" NoWait

          Endif

      Endif

 

Endwith

 

No me funciono..

 

JM

image001.png

Luis Maria Guayan

unread,
Feb 26, 2013, 2:48:35 PM2/26/13
to publice...@googlegroups.com
Tienes dos formas de hacerlo:

1. Definiendo tu propio objeto Timer y tu código en el método Timer e instanciando este objeto desde _Screen
2. Creando un objeto Custom con un procedimiento con tu código, y utilizando BindEvent con el método Timer del Timer y el objeto y tu método

Ejemplo1:
_SCREEN.ADDOBJECT("oTimer", "MiTimer")
_SCREEN.oTimer.INTERVAL = 3000

DEFINE CLASS MiTimer AS TIMER
  PROCEDURE TIMER
    THIS.ENABLED =  .F.
    *- Aquí va el código que se ejecutará
    *- Ej
    WAIT "Mensaje Recibido a hs: " + TIME() WINDOWS NOWAIT
    THIS.ENABLED =  .T.
  ENDPROC
ENDDEFINE



Luis María Guayán
Tucumán, Argentina
_________________________
http://www.PortalFox.com
Nada corre como un zorro
_________________________

Jairo Miranda

unread,
Feb 26, 2013, 9:53:26 AM2/26/13
to publice...@googlegroups.com

Me fui por la primera opcion , definiendo la clase oTimer y coloque el código en el evento timer, en evento init coloque la apertura de la tabla , me esta dando error en la apertura de la tabla

 

La segunda opción me enrede..

 

Gracias

 

Luis Ma.

image001.png

Jairo Miranda

unread,
Feb 26, 2013, 10:29:24 AM2/26/13
to publice...@googlegroups.com

 

Funciono..

 

Cree un una clase timer    llamada oTimer

 

En el evento Timer coloque

 

***Recupero el area de trabajo.

IF SYS(103) != 'ON'

   SET TALK ON

ELSE   

   SET TALK OFF

ENDIF

 

IF !USED('tMensajeria')

   USE tMensajeria AGAIN SHARED IN 0

ELSE

  SELECT tMensajeria

ENDIF

 

      SET TALK off

      xLogin     = Sys(0)

      xPos       = At('#',xLogin,1)  

      xIdUsuario = Alltrim(SubStr(xLogin,1,(xPos-1)))

      Set Delete On

      Select tMensajeria

      Locate For Alltrim(IdUsuario) = xIdUsuario

      If .NOT. Found()

         *   Wait Windows Alltrim(IdUsuario)+" No Tiene Ningún Mensaje, Presione el Boton Aceptar" NoWait

      Else

         **************************************************************************************

          *Verifica si tiene mensajes

           If !Empty(tMensajeria.Mensaje)

               Wait Windows Alltrim(IdUsuario)+" Tiene un Nuevo Mensaje" NoWait

          Endif

      Endif

 

 

En el programa principal ..

 

Public MiTimer

  MiTimer = CREATEOBJECT("oTimer")

 

Y listo

 

Gracias Luis Ma..

image001.png
Reply all
Reply to author
Forward
0 new messages