Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

KeyPress Event on Grid.Column2.Text1

Status
Not open for further replies.

AndrewMozley

Programmer
Oct 15, 2005
623
GB
I would like to be able to detect certain keys when the user is entering data into a textbox in a grid.

This is so that I can perhaps insert extra rows into the underlying RecordSource of the grid; So I have included code in the KeyPress() event.

If however, I insert a normal character, such as ‘A’, the value in the underlying table is being duplicated on the screen and indeed in the underlying cursor. So a cell which had contained ‘Lands|cape’ then contains ‘LandsAAcape’

To try to track down the problem I have reduced the code of the text1.keypress() event to :

LPARAMETERS nKeyCode, nShiftAltCtrl
RETURN DODEFAULT(nKeyCode, nShiftAltCtrl)

(That is, I have omitted my code which took action to interpret certain characters). But the duplication of characters in the cell and in the underlying cursor persists.

By comparison, if I include such code in the KeyPress() event of a TextBox outside the grid, it all works fine.

Have I misunderstood the working of the DoDefault() call?

Thanks.
 
Why not simply leaf the Return Dodefault out?

If a special key is pressed, do the action and then Nodefault to suppress the normal keypress behaviour?

Code:
LPARAMETERS nKeyCode, nShiftAltCtrl
if nkeycode=13
	messagebox("Enter pressed")
	nodefault
endif
 
NODEFAULT prevents native behaviour,
calling DODEFAULT calls parent behaviour and if all levels of inheritance do that or you do DODEFAULT in the first level child class of a ntive class you call native behaviour double.

Despite what you say ("if I include such code in the KeyPress() event of a TextBox outside the grid, it all works fine.") I get the double entrance of letters in a native textbox outside of a grid, too, with that code. So either you have something in the inheritance chain or something in the form when form.keypreview is .t. reacting to the textbox outside of the grid.

In fact you seldom need to call DODEFAULT in events you inherit first level, as the native code/behaviour also runs without DODEFAULT, you can suppress it with NODEFAULT and you can execute a certain class level code by :: operatr, but in case of most events calling DEODEFAULT means executing native behaviour double.

Bye, Olaf.

 
You can suppress any inherited code executing in an event or method by putting anything in... NODEFAULT actually has the same impact as * in the snippet area.
If you have ANY code in the method/event and you WANT the inherited code to fire, you MUST include a DODEFAULT() Somewhere in there. This is one of those things you really need to know what the inherited code will do, because sometimes you need DODEFAULT() <then your code> and other times you need to <do your code> and then call DODEFAULT().

It's been a long while since I worked with my class libraries, and I had an amusing event with this just today, where I'm able to take advantage of the code I do have inherited, and managing driving data on one form from a CURSOR in a GRID, by actually <Do something in a CASE, call DODEFALT()> Change SELECT<ed> DBF and then DODEFAULT() again. This way it applies to both the real table, and the CURSOR that is driving it... I was impressed by the flexibility of the inherited code, by just pointing two different sources to it, and then DODEFAULT() after each.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
>NODEFAULT actually has the same impact as * in the snippet area.
Wrong. Not dead wrong but a star (even a space as I already said) just means no usercode is running, o cd written in VFP. It doesn't suppress native behaviour.
Simple to see at the current topic: Put a nodefault in keypress and put a comment in keypress and see the difference.

Bye, Olaf.
 
Olaf,
I see your point, but there's two issues at play, and I think it confuses many users.

The event has some "native behavior" as you mention, but there is no code, or viewable code. So in that case, yes a NODEFAULT stops the native "effect" on EVENTS (I'm not aware of any native execution for methods, since they are not part of the event model, but I could be wrong there).
But inherited code from sub-classes IS suppressed by presence of anything, so <Native> executes, then <Inhearited code> (if no other code), or <new code> + DODEFAUILT(fires Native + Inherited) or DODEFAULT (fires Native + Inhearited) + <new code>. So these orders, and "inhibiting" events can be very tricky if you don't "get" how they occur.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Yes, you have put the behaviour in better words than me now.

Actually there is a way to call the native behaviour/code directly, too, even if that code can't be seen.

If you do textbox::keypress(nKeyCode, nShiftAltCtrl) you also execute the native behaviour twice

You can make use of this to call the native behaviour before your code or in the middle of your code by combining that with NODEFAULT you prevent the code from running after your own code and you run it when you want it to run.

For example you can do this in Keypress:
Code:
LPARAMETERS nKeyCode, nShiftAltCtrl

Activate Screen
? "Textbox value before Keypress", This.value
textbox::keypress(nKeyCode, nShiftAltCtrl) 
? "Textbox value after Keypress", This.value
Nodefault

It doesn't matter where you put the nodefault here, as it just prevents the afterrun of the keypress native code after your code, so last line is sufficient and putting it earlier doesn't make it any different or less or more reliable. textbox:: means you call the native textbox code, not any class code of a vcx or prg, just the native C++ keypress code. The :: operator can of course also call some other class level VFP code, you specify your class name instead of textbox then.

What this will show is the value right at the beginning of the keypress event, which is still the value unmodified by the key pressed. Now you actually call the native behaviour with the :: operator and you get the value as it would otherwise only be after your code ran, so you can now "predict" the future - well, you call the native behaviour earlier. This way you could now react to what the native keypress changes in the textbox value and override it not instead of it running but additional of it running. You can now simply set the value property different and nodefault makes sure it's kept that way. If you remove the nodefault, the native keypress will run again and override your override again.

As said you can also use the :: operator to call your own classes, you could skip one class level, if you want or need. Eg if you have Textbox, myTextbox, DateTextbox, HolidayTextbox you could run code in a HolidayTextbox method or event not doing DODEFAULT(..) and instead doing myTextbox:somemethod(parameters) and this way skip just the level of DateTextbox, as if Holidaytextbox directly inherited from myTextbox and not from DateTextbox in this method. But NODEFAULT always and only prevents native code, not the previous parent level class code, that is prevented by not calling Dodefault nor calling it via :: operator. NODEFAULT only is about the native code suppression. In this way it's not the simple opposite of Dodefault(). You can also use the :: operator to call other methods, eg you could call textbox::programmaticchange() in keypress or whatever native behavior you would like to run you're not bound to only call the same event you're in along the inheritance chain.

Bye, Olaf.
 
I have some vague memory of mention of Scope Resolution Operator "::" though I myself have never used it...
It's an interesting though I have to say very "non-intuitive" expression (in my view).

But that's a cool effect.

I'm currently going insane trying to get 7 grids at a "master level" view to work properly, so I'll give that a bash another time.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Thank you all for your help.

I have found the use of DoDefault() a little confusing. In general, when I have subclassed a form class, if I need to include my own code in Load() or Init() I have usually included a DoDefault() instruction, usually as a part of the RETURN statement, so that I can execute whatever code was included in the class I am using.

This works fine; it works even if my form is based on the basic form class. In this case the DoDefault() at the end of the Init() method, this executes quite happily, although (when using the base form class), it does not appear to be necessary.

So I had got into the way of generally ending my own coding for such events – e.g. Valid(), When() &c - in the same way, and this had not usually caused a problem. However for the Keypress() event this has caused the Keypress to be added twice to the value of the object, and this was not what I wanted.

So I have followed the advice on this thread (from several persons!) not to include the Dodefault() instruction in my KeyPress() code; and if I wish to prevent the Key value being added to the value of the Textbox, I include a NODEFAULT instruction – that sometimes seems to be required.

Grateful for the time you have given to this.
 
Hi Andrew,

yes, that's it.

As a rule of thumb: When you write a first inheritance of the base class there is no need for Dodefault(), as the native base class behaviour runs anyway. In case of most events and methods nothing special happens, but in case of KeyPress you see the effect. So Dodefault() actually only makes sense on second and higher levels of inheritance, where you have actual VFP code in the lower level classes you want to run, too, even just as precaution, when there is no code yet but could be added later.

So Dodefault() in general is a good thing to do, you have to know what it does to decide when to do it, eg sometimes it's also good to run it first as in llReturnvalue = Dodefault() and then later decide whether returning that value or override it. Eg a base class may decide about allowing to create a form in init judging from a user privilege and you may have reasons to override a .F. with a .T. judging on a user account name, or whatever other reason.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top