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!

Inserting / deleting rows in a grid.

Status
Not open for further replies.

AndrewMozley

Programmer
Oct 15, 2005
621
GB
I have a grid on a form in which the user may enter and edit data.

If he scrolls down beyond the last line and there is data in that last record I append a record to the RecordSource so that a another row may be edited in the grid. That works fine.

I now wish to provide a facility to let the user insert and delete rows in the grid (not necessarily at the end of the grid); this would be implemented by inserting / deleting records in the Recordsource. Am considering what keystroke should be offered to allow this. Is there any standard which other people have adopted? I had been considering Alt-Ins and Alt-Delete, but do not wish to clash with any other standard keyboard functionality.

Thanks. Andrew

 
No, Alt+INS and Alt+DEL do not clash with anything, neither in Foxpro nor Windows (as far as I know). They are both trappable combinations. The keycodes are 162 and 163 respectively.

In VFP, Ctrl+Y does an insert in a browse window, and Ctrl+T toggles the deletion marker. If your users are accustomed to using a browse window, you might like to stick with those, but personally I think Alt+INS and Alt+DEL would be more intuitive.

One other suggestion: Whatever keystrokes you use, consider also giving the users the option of using a context menu, especially if you already use context menus for other editing-related tasks, such as cut, copy, paste, etc.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thank you, Mike

I have implemented that and it works. However, I see that the KeyPress() event which can pick up the Keystroke is in the textbox of a column, so thisform.mygrid.Column4.Text1.Keypress().

It is not a big thing, but is there any way I can detect the keystroke anywhere on the grid - apart from including the code in the Keypress event of every column on the grid?

 
You might use the Form.Keypress event, if you set Form.Keypreview = .T. it always runs. Within that Keypress you might check thisform.activecontrol, if you'd like to limit where the key works and where not.

Bye, Olaf.
 
In general, if the textbox can receive keystrokes, it will be the keypress of the textbox that will fire. But if the grid or the column is read-only, or if the grid's AllowCellSelect is .F., then it will be the grid's keypress that fires.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks Olaf. I have experimented with this.

Yes, I see that if I have Form.Keypreview = .T., then form.Keypress() fires, and I can take action. However it then seems that the KeyPress events of the controls of the form do not fire, so I can no longer (for example) enter data into a textbox.

In the form.KeyPress() event, I include the code RETURN DODEFAULT(nKeyCode, nShiftAltCtrl), but that does not seem to pass the input key to the textbox. Have I misunderstood?

Andrew
 
That shouldn't happen, KeyPreview causes what its name advertises, the form gets a preview, but the control should also get its own keypress event. What may disturb the event order is LOCATing other records, setting focus to some other controls, etc. That of course changes everything, so you can't do anything in the form keypress, if you still want the control keypress. This double handling of events also is hard to debug, as single stepping in the debugger you have yet other windows getting focus and changing events thereby.

One not so obvious solution is creating a timer in the form.keypress, which does what you'd like to do delayed, ie with 30ms Interval, then releasing itself. This will then happen after both keypresses.

But before going that route, what are you doing in the form.keypress?

Bye, Olaf.
 
Olaf.

I think the problem may have happened when I put a SET STEP ON instruction in both KeyPress events. When I remove SET STEP from form.Keypress(), I do get through to the Keypress() of the textbox.

The code had been :

Code:
testform.KeyPress()
LPARAMETERS nKeyCode, nShiftAltCtrl
LOCAL lValue
WITH Thisform
   lValue = LASTKEY()
   *  Detect Alt-Insert
   SET STEP ON 
   IF nKeyCode = 162
      .InsertLine()
      ENDIF
   ENDWITH
RETURN DODEFAULT(nKeyCode, nShiftAltCtrl)

Thanks again.
 
When the form has keypreview=.F., ALT+key, are ignored by the textbox but are processed by the form
When the form has keypreview=.T., ALT+key, are completely ignored both by the textbox and the form

A more detailed study, here
If you stay with ALT+Ins, you must deal (only) with form's keypress() + Activecontrol (but avoid Keypreview = .T.)
ActiveControl must be tested with Type("ThisForm.ActiveControl") <> "U"

If you drop the ALT+key, an alternative to Keypreview, is Bindevents() + AEVENTS(,0)

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
A short test
Code:
PUBLIC ofrm
ofrm = CREATEOBJECT("MyForm")
ofrm.show()

DEFINE CLASS MyForm as Form
	ADD OBJECT txt as textbox
	ADD OBJECT grd as grid WITH recordsource = "cc", top = 50
	PROCEDURE load
		CREATE CURSOR cc (ii I,cc C(10),dd D)
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (m.lni, SYS(2015), DATE()-10*m.lni)
		NEXT
		GO TOP
	ENDPROC
	PROCEDURE Init
		FOR EACH loCol IN This.grd.Columns
			BINDEVENT(loCol.text1,"keypress",This,"myKeypress")
		NEXT
		BINDEVENT(This,"keypress",This,"myKeypress")
	ENDPROC 
	PROCEDURE myKeypress
		LPARAMETERS nKeyCode, nShiftAltCtrl
		LOCAL laBind[1],loObj
		AEVENTS(laBind,0)
		loObj = laBind[1]
		DO CASE
		CASE TYPE("loObj.Parent") <> "U"
			MESSAGEBOX(loObj.Name + CHR(13) + loObj.Parent.Name + CHR(13) + TRANSFORM(m.nKeyCode),'Textbox')
		CASE TYPE("loObj.ActiveControl") <>"U"
			IF loObj.ActiveControl.BaseClass = "Grid"
				MESSAGEBOX(loObj.ActiveControl.Name + CHR(13) + loObj.ActiveControl.Parent.Name + CHR(13) + TRANSFORM(loObj.ActiveControl.ActiveRow) + CHR(13) + TRANSFORM(m.nKeyCode),'Form, textbox')
			ELSE
				MESSAGEBOX(loObj.ActiveControl.Name + CHR(13) + loObj.ActiveControl.Parent.Name + CHR(13) + TRANSFORM(m.nKeyCode),'Form, object')
			ENDIF
		OTHERWISE
			MESSAGEBOX("Form only")
		ENDCASE
	ENDPROC
	PROCEDURE keypress
		LPARAMETERS nKeyCode, nShiftAltCtrl
		MESSAGEBOX(TRANSFORM(nKeyCode) + CHR(13) + TRANSFORM(nShiftAltCtrl),'Form')
	ENDPROC 
ENDDEFINE

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
>When the form has keypreview=.F., ALT+key, are ignored by the textbox but are processed by the form
Well, I didn't know about that.

I tested and can also confirm, another sepcial behaviour complicating things.

I can see a reason for this in ALT being the key modifier for access keys you can set in control captions with the \< prefix, also ALT alone triggers the sysmenu. ALT key combinations therefore are not a good choice for shortcut or hotkeys, even though the OS doesn't have them reserved. Simply because of the function of activating the menu with ALT.

So a simple solution to let the form.keypress handle ALT+key is simply reset Keypreview to .F.
Maybe switch to CTRL+INS and CTRL+DEL to avoid ALT, then you would need KeyPreview .T. again.

Bye, Olaf


 
Aren't CTRL+INS and CTRL+DEL reserved in the old IBM/CUA interface standard? (Or was that SHIFT+INS and SHIFT+DEL?)

I can't test this on my Macbook keyboard because it doesn't have INS (or CTRL, really), but these keystrokes used to be so deep in Windows' bone marrow they'd work even in apps that hadn't implemented CTRL-V/CTRL-C, etc.

Probably best to do what other modern apps do. Give the users buttons labeled "+" and "-". [pipe]
 
I also discovered it by chance, didn't read anywhere.
Interesting, the WM_KEYDOWN message also ignores the ALT key.
I guess all three alternatives proposed are better (context menu, another key combination, command buttons)

Code:
PUBLIC ofrm
ofrm = CREATEOBJECT("MyForm")
ofrm.show()

DEFINE CLASS MyForm as Form
	ADD OBJECT txt as textbox
	ADD OBJECT cmd as commandbutton WITH top = 50,caption ='\<click'
	PROCEDURE Init
		BINDEVENT(This.HWnd,0x0100,This,"detectkeydown") && intercept keydown
*		BINDEVENT(_vfp.HWnd,0x0100,This,"detectkeydown") && intercept keydown
	ENDPROC
	PROCEDURE detectkeydown
		LPARAMETERS p1,p2,p3,p4
		* p1 = ThisForm.hwnd
		* p2 - The message; 256 = 0x100 in this case
		* p3 = Virtual-key code
		* p4 % 65536 - the number of times the keystroke is autorepeated as a result of the user holding down the key. The repeat count is always 1 for a WM_KEYUP message
		* FLOOR(p4 / 65536) % 256 - The scan code. The value depends on the OEM.
		* BITTEST(p4, 24) - ndicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is .t. if it is an extended key; otherwise, it is .f.
		IF TYPE("This.ActiveControl") = "U"
			lcObj = "ThisForm"
		ELSE
			lcObj = This.ActiveControl.Name
		ENDIF
		ACTIVATE SCREEN
		? lcObj,"Virtual-key code",p3,"The scan code",FLOOR(p4 / 65536) % 256,IIF(BITTEST(p4, 24),"Extended key","Normal key"),"pressed (times)",p4 % 65536
	ENDPROC
ENDDEFINE

I altered the code from here See
Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top