ON CHANGE in tGet

User avatar
TimStone
Posts: 2536
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA
Contact:

ON CHANGE in tGet

Post by TimStone »

Maybe old age is getting me.

I thought the ON CHANGE activated when the total value of a get was modified, not for each character entered. I realize a VALID tests the total value, but I want to run a function only if the total value changes, not everytime the field is displayed.

Currently, ON CHANGE will activate with every keystroke, as demonstrated in the following example. Is this a correct behavior ?

// Test On Change in get
#INCLUDE "fivewin.CH"

PROCEDURE main

LOCAL oDlg
LOCAL oTestGet := SPACE(10)

DEFINE DIALOG oDlg SIZE 500, 300

@ 3, 10 GET oTestGet PICTURE "@!" ON CHANGE ( MsgAlert( "Changed" ) )

ACTIVATE DIALOG oDlg

RETURN NIL
Tim Stone
http://www.MasterLinkSoftware.com
timstone@masterlinksoftware.com
Using: FWH 19.06 with Harbour 3.2.0 / Microsoft Visual Studio Community 2019
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Tim,

Yes, that is the correct behavior for bChange. It is used to do special processing while the data is being input. You can use it for custom pictures, etc.

As you said, use the VALID clause. To use bValid just store the "before" value in a var and then test it with the after value in bValid. bValid won't be eval'd unless the user enters the field. If you are using a database, you can check the get var against the field contents to see if it has been changed instead of creating a "before" var.

James
User avatar
TimStone
Posts: 2536
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA
Contact:

VALID

Post by TimStone »

James,

Using tData, I'm editing oDbf:var1 for example, and if I now change the content in the dialog, how can I validate against the original database unless I store a new var on loading the record ?

Tim

ie>

REDEFINE GET oGt1 VAR oDbf:var1 ID 201 OF oDlg ;
VALID testvalue( )

Where testvalue( ) only executes if the originally saved value of oDbf:var1 is changed in this control ?

I know I can read the value at load and store it to a variable that executes if there is a change, but I wanted to avoid the extra code if I can read the data ....
Tim Stone
http://www.MasterLinkSoftware.com
timstone@masterlinksoftware.com
Using: FWH 19.06 with Harbour 3.2.0 / Microsoft Visual Studio Community 2019
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Tim,

>Using tData, I'm editing oDbf:var1 for example, and if I now change the content in the dialog, how can I validate against the original database unless I store a new var on loading the record ?

Try this:

REDEFINE GET oGt1 VAR oDbf:var1 ID 201 OF oDlg ;
VALID if( oDbf:var1 <> (oDbf:cAlias)->var1, msgInfo( "Changed"),)

The upside is that you don't have any extra code, the downside is that this requires a disc read. But it will only do a disc read if the user enters the field.

Another approach is to create a subclass of TData or TCustomer or whatever you are using, and add another buffer array. In the load() method copy the data to this array also. Then you can test every field against the original without another disk read and without any more code (the same code is reused everywhere your database class is used).

Code: Select all

class TXData from TData
   data aOriginal init {}
   method load
endclass

method load()
   super:load()
   acopy(::aBuffer, ::aOriginal)
return nil
[Note: I always recommend using a subclass of TData for each application, even if it starts out empty. Then you use this class in your app. When you later want to add a generic feature to the database class, you can just add it to this one subclass, and the entire application will inherit it without any other code changes.]

James
User avatar
TimStone
Posts: 2536
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA
Contact:

Valid / On Change

Post by TimStone »

Thanks.
Tim Stone
http://www.MasterLinkSoftware.com
timstone@masterlinksoftware.com
Using: FWH 19.06 with Harbour 3.2.0 / Microsoft Visual Studio Community 2019
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Tim,

There was something nagging me in the back of mind about this topic and it finally came to me.

In the old Clipper Get there was a var oGet:original which contained the original data. Unfortunately, in xHarbour this isn't working--it always returns nil. Too bad.

However, there is a simple workaround and that is to use oGet:cargo. It does require that you force this to be loaded in your code, but by doing this you can avoid an extra disk read or using an extra var. Below is a working sample.

Regards,
James

Code: Select all

#include "fivewin.ch"

function main()
   local oDlg,oGet,oGet2,cVar:="Test     ",cVar2:="xxx       "

   define dialog oDlg

   @ 1,1 get oGet var cVar of oDlg ;
      valid if( oGet:cargo <> oGet:varGet(), (msgInfo("Changed"),.t.), (msgInfo("Not changed"),.t.) );

      oGet:cargo:= oGet:varGet()

   @ 2,1 get oGet2 var cVar2 of oDlg

   activate dialog oDlg centered

return nil
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Enrico,

>Did you try

>oGet:oGet:Original

Yes, that is what I was referring to. It has never worked in Harbour or xHarbour as far as I know.

James
User avatar
Enrico Maria Giordano
Posts: 7355
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Contact:

Post by Enrico Maria Giordano »

Works fine for me:

Code: Select all

#include "Fivewin.ch"


FUNCTION MAIN()

    LOCAL oDlg

    LOCAL oGet, cVar := PADR( "Test", 20 )

    DEFINE DIALOG oDlg 

    @ 1, 1 GET oGet VAR cVar

    oGet:bLostFocus = { || MsgInfo( oGet:oGet:Original ) }

    @ 3, 1 BUTTON "&Close";
           ACTION oDlg:End()

    ACTIVATE DIALOG oDlg;
             CENTER

    RETURN NIL
EMG
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Enrico,

Hmm, that does seem to work, but this doesn't. It returns nil.

James

Code: Select all

#include "Fivewin.ch"

FUNCTION MAIN()

    LOCAL oDlg

    LOCAL oGet, cVar := PADR( "Test", 20 )

    DEFINE DIALOG oDlg

    @ 1, 1 GET oGet VAR cVar valid (msgInfo( oGet:oGet:original ),.t.)

   // oGet:bLostFocus = { || MsgInfo( oGet:oGet:Original ) }

    @ 3, 1 BUTTON "&Close";
           ACTION oDlg:End()

    ACTIVATE DIALOG oDlg;
             CENTER

    RETURN NIL
User avatar
Enrico Maria Giordano
Posts: 7355
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Contact:

Post by Enrico Maria Giordano »

Please remember that "Get:Original is meaningful only while the GET has input focus".

EMG
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Enrico,

>Please remember that "Get:Original is meaningful only while the GET has input focus".

Are you saying that it doesn't have input focus when bValid is executed? I would think it has to have.

James
User avatar
TimStone
Posts: 2536
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA
Contact:

Continuing

Post by TimStone »

For the purpose of discussion, I would suppose this modification would work:

#include "Fivewin.ch"

FUNCTION MAIN()

LOCAL oDlg

LOCAL oGet, cVar := PADR( "Test", 20 )

DEFINE DIALOG oDlg

@ 1, 1 GET oGet VAR cVar valid (IIF( cVar <> oGet:oGet:origianl, msgInfo( "Data changed"), ), .t. )

// oGet:bLostFocus = { || MsgInfo( oGet:oGet:Original ) }

@ 3, 1 BUTTON "&Close";
ACTION oDlg:End()

ACTIVATE DIALOG oDlg;
CENTER

RETURN NIL
Tim Stone
http://www.MasterLinkSoftware.com
timstone@masterlinksoftware.com
Using: FWH 19.06 with Harbour 3.2.0 / Microsoft Visual Studio Community 2019
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Tim,

>For the purpose of discussion, I would suppose this modification would work:

No, from a VALID oGet:oGet:original returns nil. It does return the proper value from bLostFocus. This seems to be a bug to me.

James
User avatar
Enrico Maria Giordano
Posts: 7355
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia
Contact:

Post by Enrico Maria Giordano »

James Bott wrote:Are you saying that it doesn't have input focus when bValid is executed?
Yes. Just check oGet:oGet:HasFocus. It is .T. in bLostFocus and .F. in bValid.

EMG
Post Reply