Un tema para debatir: Parametros a pasar al Codeblock

Un tema para debatir: Parametros a pasar al Codeblock

Postby RSalazarU » Fri Sep 30, 2011 3:57 pm

Amigos del foro, en especial al equipo de FiveWin:

Tenia el requerimiento de ocultar o mostrar determinados controles de un dialogo; esto se lo puede hacer desde del código contenido en bWhen

Ejemplo:
Code: Select all  Expand view

local oCtrl1, oCtrl2, oCtrl3, nVar
:
oCtrl1:=TGet():New(..)
oCtrl1:bWhen:={|| if(nVar=1,oCtr1l:Show(),oCtrl1:Hide()), nVar=1 }

oCtrl2:=TGet():New(..)
oCtrl2:bWhen:={|| if(nVar=2,oCtrl2:Show(),oCtrl2:Hide()), nVar=2 }

oCtrl3:=TGet():New(..)
oCtrl3:bWhen:={|| if(nVar=3,oCtrl3:Show(),oCtrl3:Hide()), nVar=3 }

 


Sin embargo si son muchos controles, se tiene declarar una variable para cada objeto y el código se vuelve muy complicado.

Yo lo solucioné de la siguiente manera:

Code: Select all  Expand view

:
OVERRIDE METHOD lWhen IN CLASS TWindow WITH _lWhen
OVERRIDE METHOD AEvalWhen IN CLASS TWindow WITH _AEvalWhen
:
//----------------------------------------------------------------//
//usado en: EXTEND CLASS TWindow
static function _lWhen

   LOCAL self := HB_QSelf()

Return If( self:bWhen != nil, Eval( self:bWhen, self ), .t. )

//----------------------------------------------------------------//
//usado en: EXTEND CLASS TWindow
static function _AEvalWhen

   LOCAL self := HB_QSelf()
   local n
   local aControls := Self:aControls

   if aControls != nil .and. ! Empty( aControls )
      for n = 1 to Len( aControls )
          if aControls[ n ] != nil .and. aControls[ n ]:bWhen != nil
             if Eval( aControls[ n ]:bWhen, aControls[ n ] )
                Self:aControls[ n ]:Enable()   // keep this as Self:
             else
                Self:aControls[ n ]:Disable()  // keep this as Self:
             endif
         endif
      next
   endif

return nil

 


En el código implementado se sobreescribe los metodos lWhen y AEvalWhen y en la implementacion se evalúa bWhen enviándole como parámetro el mismo objeto.

Y el código del dialogo queda así:

Code: Select all  Expand view

local nVar
:
TGet():New(....{|oCtrl| if(nVar=1,oCtrl:Show(),oCtrl:Hide()), nVar=1 }...)

TGet():New(....{|oCtrl| if(nVar=2,oCtrl:Show(),oCtrl:Hide()), nVar=2 }...)

TGet():New(....{|oCtrl| if(nVar=3,oCtrl:Show(),oCtrl:Hide()), nVar=3 }...)
:
 


Así el código queda mas claro y sencillo.

Esto se puede hacer en xharbour, pero seria ideal que fuera implementado directamente en la clase.

Ahora bien, entrando en el tema: ¿Que parámetros se debería pasar cuando se evalúa los distintos CODEBLOCK de las clases?

por ejemplo en la clase TButton() se tiene:

Code: Select all  Expand view

         Eval( ::bAction, Self )
 


tal vez seria posible mejorar si se lo cambiara por

Code: Select all  Expand view

         Eval( ::bAction, Self, ::oWnd )
 


En forma similar, talvez, se podría modificar varias clases donde se evalúa CODEBLOCKS con el paso de estos parametros que no afectan en nada.

Muchos CODEBLOCKS ya tiene sus parámetros definidos, que no deben ser modificados, para estos casos se debería pasar estos parámetros al final.


Buen tema para debatir verdad???


Atentamente,

Rolando.

Saludos desde Cochabamba, Bolivia.
RSalazarU
 
Posts: 211
Joined: Wed Jul 16, 2008 12:59 pm
Location: Cochabamba-Bolivia

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby Daniel Garcia-Gil » Fri Sep 30, 2011 4:22 pm

Saludos

es valida la opcion de enviar el Self al codeblock bWhen, no creo que exista inconvenientes para ser implementado para el proximo build de fivewin (anotada la sugerencia)

con respecto a Eval( ::bAction, Self, ::oWnd ) es innecesario pasar el objeto del padre, se puede acceder a este por medio del Self...

Code: Select all  Expand view
bAction = {| oSelf | Action( oSelf, oSelf:oWnd ) }
User avatar
Daniel Garcia-Gil
 
Posts: 2365
Joined: Wed Nov 02, 2005 11:46 pm
Location: Isla de Margarita

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby RSalazarU » Fri Sep 30, 2011 4:44 pm

Daniel:

Gracias por responder tan pronto.

la clase TButton() también tiene un Eval( ::bWhen)

Code: Select all  Expand view

//----------------------------------------------------------------------------//

METHOD Click() CLASS TButton

   if ! ::lProcessing

      ::lProcessing = .t.

      if ::bWhen != nil .and. ! Eval( ::bWhen, self ) //<----aca
         ::lProcessing = .f.
         return nil
      endif
:
:
 


Y las otras clases y CODEBLOCKs

Por ejemplo, para mejorar los reportes cuando tienen grupos:

Code: Select all  Expand view

:
          ::nHeaderHeight := ::oReport:oDevice:GetTextHeight(eval(::bHeader, Self),; //<----aca
                             ::oReport:aFont[eval(::bHeadFont)] )
:
          ::nFooterHeight := ::oReport:oDevice:GetTextHeight(eval(::bFooter, Self),; //<----aca
                             ::oReport:aFont[eval(::bFootFont)] )
:
 


Se que es mucho trabajo, revisar todo :| , es algo que se debe hacer poco a poco.

De nuevo, gracias por responder.

Atentamente,

Rolando.
RSalazarU
 
Posts: 211
Joined: Wed Jul 16, 2008 12:59 pm
Location: Cochabamba-Bolivia

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby hmpaquito » Fri Sep 30, 2011 5:11 pm

RSalazarU,

A proposito de este codigo
Code: Select all  Expand view

oCtrl1:=TGet():New(..)
oCtrl1:bWhen:={|| if(nVar=1,oCtr1l:Show(),oCtrl1:Hide()), nVar=1 }

oCtrl2:=TGet():New(..)
oCtrl2:bWhen:={|| if(nVar=2,oCtrl2:Show(),oCtrl2:Hide()), nVar=2 }

oCtrl3:=TGet():New(..)
oCtrl3:bWhen:={|| if(nVar=3,oCtrl3:Show(),oCtrl3:Hide()), nVar=3 }
 


Yo lo hubiera resuelto asi para que quedara mas claro:
Code: Select all  Expand view

#Define bWHEN_ (n, o) {|| If(nVar == n, o:Show(), o:Hide()), nVar == n} // El preprocesador siempre ha sido un poderoso gran amigo

oCtrl1:=TGet():New(..)
oCtrl1:bWhen:= bWHEN_(1, oCtrl1)

oCtrl2:=TGet():New(..)
oCtrl2:bWhen:= bWHEN_(2, oCtrl2)

oCtrl3:=TGet():New(..)
oCtrl3:bWhen:= bWHEN_(3, oCtrl3)
 


Pero aparte del tema que plantea, yo siempre he visto un inconveniente las ACCIONES en bloques del estilo del :bWhen. ¿ Debemos poder poner acciones en un :bWhen, además de la condicion ? ¿ No podria eso traer problemas en el futuro, en este caso parpadeos, porque el :bWhen es llamado sin tener en cuenta que en su interior puede albergar Actions ? No se si me explique... vamos lo que planteo es que quiza algunos codeblocks no pueden llevar acciones porque el codeblock es evaluado normalmente como un bloque que "unicamente" devuelve una expresion logica.

Esto mismo siempre ha ocurrido con el bloque :bValid, donde algunas veces ademas de devolver la condicion, ejecuta acciones; a mi modo de ver, por ejemplo para un objeto TGet tendria que existir un :bPrevalid, un :bValid (ya existente), y un :bPostValid de manera que el :bValid SOLO devuelve un condicionante y el :bPreValid y el :bPostValid ejecutan acciones. Quiza en principio puede parecer innecesario, pero IMHO, esto es un requisito para una programacion mas como capas, donde se aisle la capa logica de la capa formulario.

Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby RSalazarU » Fri Sep 30, 2011 6:22 pm

HMPaquito:

Gracias por el código del #define, lo voy a tomar en cuenta.

En cuanto a ¿ Debemos poder poner acciones en un :bWhen, además de la condicion ?, eso depende de cada uno; la ideas es tener mas recursos para facilitar el trabajo, sin mucho codigo.

Lo que se haga con ese recurso depende de cada uno, si quieres lo utilizas o no.

Como en el ejemplo que puse, es mas complicado procesar el primer codigo que el segundo y si quieres hacer algo "bonito" haciendo que aparezcan o desaparezcan algunos controles (según una determinada situación), entonces tienes que realizar ciertas acciones para ese propósito. La pregunta es ¿donde colocar el código para realizar esas acciones?


Atentamente,

Rolando.

Saludos desde Cochabamba, Bolivia.
RSalazarU
 
Posts: 211
Joined: Wed Jul 16, 2008 12:59 pm
Location: Cochabamba-Bolivia

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby hmpaquito » Sat Oct 01, 2011 8:11 am

Rolando,

Tiene vd. razón, la programación es también una cuestión de gustos. Pero no me negará vd. que también es una "disciplina" y por tanto es un área donde el "gusto" no puede ser el único factor que guia nuestros desarrollos, en pos de una mejora en la eficacia y eficiencia de nuestro trabajo.

Si yo escribo:

o:bWhen:= {|| If(nVar == 1, o:Show(), o:Hide()), .t. } probablemente vd. (y yo) veremos la asignación "pacíficamente",

pero si en cambio escribo:

o:bWhen:= {|| If(nVar == 1, DeleteHardDisk(), NIL), .T.} creo que vd. (y yo) nos llevariamos las manos a la cabeza y nos preguntariamos: 1º Es el bWhen el unico sitio donde se puede poner el DeleteHardDisk() o se puede poner en otro sitio mas seguro, y 2º si no queda mas remedio que ponerlo en el :bWhen, nos tenemos que repasar todos los lugares donde se utiliza el :bWhen() para asegurar que no haya un sitio donde nVar pueda ser 1 y no deba ejecutarse la llamada a :bWhen; además siempre nos cabe la duda de que fivetech cambie los fuentes, en el futuro, y añada un Eval(:bWhen).

Lo único que yo digo Rolando, lo comenté anteriormente, cuando le hablé del bPreValid, bValid y bPostValid, es que quizá habria que subdividir el bloque :bWhen en otros bloques que se adapten exactamente al momento/ accion que exactamente queremos evaluar.

Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby Carlos Mora » Sat Oct 01, 2011 9:39 am

Hola Paquito,

creo que la programación requiere de libertad para crear, las actitudes preventivas que no están en manos del programador me parece que pueden acarrear consecuencias negativas.
La responsabilidad de lo que se hace en el bWhen es del programador, no imagino una forma razonable de limitar algo en el codeblock.

Aprovecho la ocasión para recordaros que al implementar los cambios en los codeblocks hay que evitar el uso de palabras reservadas, en particular usar SELF como nombre de parámetro. Si estamos redefiniendo controles dentro de un método, el uso de self resulta ambiguo. Y si se pudiera cambiar en los defines actuales mejor, creo que no traería mayores inconvenientes, no deben haber muchos que uen el operador :: dentro de un codebock.

Un saludo
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby hmpaquito » Sat Oct 01, 2011 11:12 am

Don Carlos,

Debe ser que estoy duro para explicacion porque intente explicarlo en mis anteriores otros dos mensajes;

Un ejemplo: el VALID en el GET; el siguiente codigo:
Code: Select all  Expand view

@ x,y GET cCodigo ;
         VALID (;
                  cCodigo:= PadZero(cCodigo, 5),;                                     // PreValid
                  l:= !Empty(cCodigo) .and. Client-> (dbSeek(cCodigo)),;    // Valid
                  If(l, If(Left(cCodigo, 1) == "1", oControl:SetFocus(), NIL), nil);       // PostValid
                  l;                                                                
                    )
 


Tendria una sintaxis más clara, mantenible y con menos efectos colaterales si se escribiera asi:
Code: Select all  Expand view

@ x,y GET cCodigo ;    
   PREVALID   cCodigo:= PadZero(cCodigo, 5);                                // Nuevo bloque bPreValid
   VALID         !Empty(cCodigo) .and. Client-> (dbSeek(cCodigo));    // bValid
   POSTVALID If(Left(cCodigo, 1) == "1", oControl:SetFocus(), NIL)   // Nuevo bloque bPostValid: sólo ejecuta si valid Ok

 


De esta forma no tenemos que tener miedo de que cada vez que se ejecute el Eval(:bValid) el foco se vaya a oControl.

Quiza, creo que esto puede ser aplicable al bloque bWhen.
¿ Qué sino son los bloques bWhen y bValid ? La deteccion por parte del creador de dBase de unos eventos que conviene poder tratar por separado. ¿ Y quién me dice a mi que esos eventos no pueden, por ejemplo subdividirse, teniendo un principio y un fin y para ellos se crean otros bloques que gestionan esos momentos (eventos).


Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby Carlos Mora » Sat Oct 01, 2011 12:03 pm

Hola Paquito,

si te explicas bien, y eventualmente sería yo el que no está muy fino ;) Además me gusta debatir y generar ideas, creo que es el mejor camino. Al comparar tu experiencia con la del resto aparecerán matices que nos permiten mejores soluciones, verdad?

Entiendo lo que dices, te gustaría tener un codeblock separado, eso es claro.
Yo veo una solución alternativa, aunque todavía no tengo claro como adaptarla al comando. En realidad son 2 soluciones.
La primera es ver como meter un codeblock multilínea de los nuevos en el comando, ya que podríamos tener un codeblock del tipo

Code: Select all  Expand view
oGet:bValid:= {||
    cCodigo:= PadZero(cCodigo, 5)// PreValid
    // ojo, despues de esto Empty(cCodigo) es siempre .F.
    IF !Empty(cCodigo) .and. Client-> (dbSeek(cCodigo))
        IF Left(cCodigo, 1) == "1"
            oControl:SetFocus()
        ENDIF
        RETURN .T.
    ENDIF
    RETURN .F.
}


la limitación te la dá el formato de una sola línea del codeblock, con un multilínea haces todo mucho más claro y natural, aunque todavía no sabría como meterla en el comando REDEFINE GET

En estos casos las declaraciones más orientadas a objetos como la de las columnas del xBrowse me suelen resultar más cómodas, tipo

Code: Select all  Expand view

WITH OBJECT oBrw:AddColumn()
    :nWidth:= 60
    :cHeader:= 'Factorial'
    :bData:= {||
        LOCAL i, x:= 1
        FOR i:= 2 TO RecNo()
            x*=i
        NEXT
        RETURN x
        }      
END


ojo, esto es codigo para poner un ejemplo.
Pero, claro, esto no nos vale de momento para los gets. Y mientras lo voy pensando.... se me ocurre que se puede crear un comando con lo mejor de los dos mundos:

Normalmemnte hacemos

Code: Select all  Expand view
    REDEFINE GET oGet VAR cCodigo ID 150 OF oDlg VALID ...
 

sería fácil tener un comando

Code: Select all  Expand view
    REDEFINE OBJECT GET cCodigo ID 150 OF oDlg
        :bValid:= {||
            cCodigo:= PadZero(cCodigo, 5)// PreValid
            // ojo, despues de esto Empty(cCodigo) es siempre .F.
            IF !Empty(cCodigo) .and. Client-> (dbSeek(cCodigo))
                IF Left(cCodigo, 1) == "1"
                    oControl:SetFocus()
                ENDIF
                RETURN .T.
            ENDIF
            RETURN .F.
        }
    END
 

con solo añadir el WITH OBJECT al comando normal del GET :
Code: Select all  Expand view
    REDEFINE OBJECT GET [<oGet> VAR] <cVar> <etc...> => ;
    WITH OBJECT [<oGet>:=] TGet():New( <loquesea como está ahora está el comando GET> )

 

Es una forma que se me acaba de ocurrir, la tengo que pesar mejor pero me parece que nos dejaría con las dos opciones, comando y OO.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Un tema para debatir: Parametros a pasar al Codeblock

Postby hmpaquito » Sat Oct 01, 2011 5:06 pm

Carlos,

Yo lo que trataba de decir es que en el :bValid SÓLO vaya el código estricto de validación; es decir no vaya el bPrevalid ni el bPostValid, porque a mi entender el bPrevalid y el bPostValid no son en "sensu estricto" validacion, es decir, no forman parte de la condicion que determina si un control, durante su edicion, es o no valido; con eso se consigue que en cualquier evaluación de Eval(:bValid), que se puede producir en TWindow.prg o en TControl.prg o en nuestro propio codigo, no se produzcan efectos colaterales.

A mi también me gusta debatir sobre estos temas. Es la parte filosófica de la programatica.

Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm


Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 39 guests