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!

Selecting a row in a Grid with the enter key 1

Status
Not open for further replies.

SitesMasstec

Programmer
Sep 26, 2010
523
Brasil
Dear colleagues:


I have this in a Form with a Grid:
Grid3_he20g6.jpg


I am able to move through rows using the mouse and with arrow keys. To select a row I must Double Click that row. In the DblClick event on Grid1 object I have:

Code:
LOCAL cCode
cCode = itensest.wecodi 

IF NOT ISNULL(This)
  EsteCodigo=cCode
ELSE
  EsteCodigo=0
ENDIF 
thisform.Release

I would like to continue to have the option of using arrows keys to move up and down the rows (as it is possible now). But I would like my application to accept also the <enter> key to select a row, besides continuing to accept DblClick. Is it possible?


Thank you,
SitesMasstec
 
SitesMasstec said:
IF NOT ISNULL(This)
This will always be true, as THIS is the grid and the code is in the grid DblClick. So simplify your code:
Code:
EsteCodigo = itensest.wecodi 
ThisForm.Release()
In comparison your code is much ado about nothing.

I see why this happened, you completely disregarded Tamar's solution in thread184-1777630 to address the existence of a control, not just THIS. You should get more grip on what things mean. You donwgraded her code to something proving you haven't understood the most important bit of it.

To react to <ENTER> use the form.KeyPress event and don't forget to set form.KeyPreview = .T.
As you only have that grid on the form, an ENTER you receive will mean the selection of a row by keyboard.

To check for the <ENTER> key, check the parameters with [tt]IF nKeyCode=13 AND nShiftAltCtrl=0[/tt] and then again assign [tt]EsteCodigo = itensest.wecodi[/tt]

You seem to have created a public variable EsteCodigo, which is a bad choice. In the main form create a cursor as a copy of itensest with just one record in it:
Code:
SELECT * FROM itensest WHERE .F. INTO CURSOR crsMainform READWRITE
APPEND BLANK IN crsMainform
This could go into the main form Init(), so you have this record for the whole lifetime scope of the form.

Set the textbox controlsource in the main form to crsMainform.wecodi. From this moment on changing the value of wecodi in the crsMainfrom cursor will change the display. You may also bind other controls to other fields of crsMainform, create it just as needed, I make the assumption all fields of the itensest are of interest, but you might also add other fields or only pick some fields of itensest, in the most generalized case you can use CREATE CURSOR crsMainform and define any fields you need. You can use the one record in crsMainform to hold all the values you need for controls.

The way it is now you're using controls as variables with form scope, where you need a bigger scope for the two forms. For that bigger scope, a DBF or cursor is ideal when you share a datasession, your controls now become slaves of this cursor, not master variables. But don't ever go for public variables. So don't declare the public variable EsteCodigo in your main.prg

In your grid from above, use the same datasession as in the main form, then instead of assigning the selected itensest.wecodi to EsteCodigo use [tt]REPLACE wecodi WITH itensest.wecodi IN crsMainform[/tt] This is saving you some code, even though it is longer than the assignment to EsteCodigo. You a) don't declare EsteCodigo and b) don't need to set the main form.TextX.Value = EsteCodigo, the grid child form already has updated the crsMainForm data displayed. All you need to after the DO FORM is Thisform.Refresh() and the new value shows.

To be detailed, the grid forms Keypress code will be:
Code:
LPARAMETERS nKeyCode, nShiftAltCtrl
IF nKeyCode=13 AND nShiftAltCtrl=0
   REPLACE wecodi WITH itensest.wecodi IN crsMainform
   Thisform.Release()
ENDIF

So notice: Sharing a datasession is giving you a way to let forms interact through shared data, the ideal way to interact in such cases. This way you have the least entanglement of code and form structures, you may later change the control on the main form, put it in a page frame or whatever. If you keep it bound to crsMainform.wecodi, the code to set it needs no change, your grid form does not need to know how your main form is structured, you separate the concerns, which is one of the major goals of OOP programming, aim for the least entanglement and dependency of code.

On the other side, it is totally okay to entangle the grid form with the main form by sharing the datasession. Your popup form really just compares to a complex dropdown of a combo box on the main form, it really belongs to the main form. Since you need a whole new form anyway, it's just fair you at least share the datasession. The only dependency your grid form has with the main form is, the main form must create a cursor crsMainform having a field wecodi. This can still be reused for picking a wecodi anywhere else you need to just like now only depending on the public variable EsteCodigo it just depends on crsMainForm.wecodi to exist in the shared datasession.

One maybe not very big but noticeable difference of the smaller scope of sharing data is this: Assume you have two main forms open at the same time (assume that's possible), assume the user does something opening up the grid forms for both main forms for whatever reason, instead of picking one by one. Each selection of the child forms only influences the shared datasession of the corresponding main form and nothing bleeds over. Admitted, it would not happen with the public variable, too, as its value only is of importance in the short moment of the choice, the main form receives its value and since you can't click on two grids at the same time and only one grid will have focus to get the KeyPress event, the public variable will just have the current choice in that moment and after the main form then copies that into its control, the public variable can be overwritten again. But this nature of the public variable already shows its scope is much too big, you really only need a transfer of data. It's no excuse to use that public variable, you use a shared datasession for that matter.

Bye, Olaf.
 

Hello Olaf, it is working fine now, thank you.

But a doubt is in my head:

If I put this in Grid, DblClik event:

Code:
EsteCodigo=itensest.wecodi 
thisform.Release

Why shouldn't I put the code bellow in Grid, KeyPress event INSTEAD OF in Form, KeyPress event (as I did as you advised me and is working fine) ? (Well, I saw that the object Grid doesn't have the KeyPreview item...)

Code:
LPARAMETERS nKeyCode, nShiftAltCtrl

IF nKeyCode=13 AND nShiftAltCtrl=0 
   EsteCodigo=itensest.wecodi 
   thisform.Release
ENDIF


Thank you,
SitesMasstec
 
the object Grid doesn't have the KeyPreview

All object's that can receive focus have a KeyPress. But only the form has a KeyPreview. (Actually, a page and a toolbar can also have KeyPreview, but ignore that for the moment.)

What the KeyPreview does is determine whether the form or the active control receives the keypress first. If the form's KeyPreview is true, the form's KeyPress will fire first, followed by the control's. If KeyPreview is false, then only the control's KeyPress will fre.

If the form has no code in its KeyPress event, then the setting doesn't really matter. If it does, then you need to decide which of the two takes priority.

Hope this makes sense.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Yes, with Mikes explanation nothing speaks against putting the reaction to ENTER into the grid, it would also be good to only react to ENTER when the grid is the active control, but then this choice is simply for being future proof and fail-safe.

1. You may have further controls sometimes in the future and still would like ENTER to make the selection and end the whole form, even if the focus is on some other control.
2. You may later combine the choice of some row with also editing data while listing it. But when the grid is changed to allow the inner Textboxes to get the focus, the grid.keypress will most seldom be the event that gets triggered. And you don't want to program every keypress of every subcontrol within a grid, so using the form.keypress with the preview option is an easy way out of this.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top