Page 1 of 2
ON CHANGE in tGet
Posted: Wed Jul 25, 2007 12:32 am
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
Posted: Wed Jul 25, 2007 12:58 am
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
VALID
Posted: Wed Jul 25, 2007 1:09 am
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 ....
Posted: Wed Jul 25, 2007 1:43 am
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
Valid / On Change
Posted: Wed Jul 25, 2007 4:33 pm
by TimStone
Thanks.
Posted: Thu Jul 26, 2007 11:05 am
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
Posted: Thu Jul 26, 2007 12:19 pm
by Enrico Maria Giordano
Posted: Thu Jul 26, 2007 12:58 pm
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
Posted: Thu Jul 26, 2007 1:17 pm
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
Posted: Thu Jul 26, 2007 2:34 pm
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
Posted: Thu Jul 26, 2007 2:44 pm
by Enrico Maria Giordano
Please remember that "Get:Original is meaningful only while the GET has input focus".
EMG
Posted: Thu Jul 26, 2007 4:11 pm
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
Continuing
Posted: Thu Jul 26, 2007 4:39 pm
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
Posted: Thu Jul 26, 2007 4:51 pm
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
Posted: Thu Jul 26, 2007 6:28 pm
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