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 Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

BeforeRowColChange firing multiple times

Status
Not open for further replies.

TamarGranor

Programmer
Jan 26, 2005
2,483
US
I have a fairly simple grid, set up essentially as a picklist:

AllowCellSelection = .F.
Highlight = .F.
HighlightRow = .F.
HighlightStyle = 2

Various other settings (DeleteMark and RecordMark both .F.) in the PropSheet as well.

On the same page (of a pageframe), I have data-entry controls for the records that are shown in the grid. I have code in BeforeRowColChange and AfterRowColChange to deal with what happens when the user clicks on a different row than the one she's currently editing. The form is configured so that it knows whether the user has made any changes to the record currently being edited.

I'm finding that sometimes, but not always, BeforeRowColChange fires two or more times in succession and some (maybe all) of those times results in a "REcord out of range" error, which appears in such a way as to make me think the grid's been wiped out.

The code called by BeforeRowColChange does, under some circumstances, ZAP the cursor that's the RecordSource of the grid and repopulate it. It should never result in fewer records than we had before (at least, not yet--still some work to do here), and since I'm using ZAP and INSERT INTO to repopulate the cursor, shouldn't rip the cursor out from under the grid.

So what I'm looking for is reasons BeforeRowColChange will fire repeatedly. (I've already tried adding a flag to make sure it executes the core code only once, and it didn't solve the problem.)

TIA,
Tamar

 
I've seen intermittent reports of BeforeRowColChange being called multiple times over the years.

I don't have anything to add, but wanted you to know I've seen this reported before. You're not crazy. :)

I wonder, though, about the wisdom of doing something in a grid method that diddles with the record source that gives the grid its grid-ness. It just feels like bad juju to me. I wouldn't generally do that. (Never say never!)
 
>doing something in a grid method that diddles with the record source

Well, I wouldn't doubt that it makes sense, it surely adheres to the rule of encapsulation to let a grid work with it's own recordsource, doesn't it?
And ZAP+INSERT is a known good way of avoiding grid reconstruction.

Talking of seldom issues I have yesterday had a lock message opening a dbf saying "attempting to lock...press ESC to cancel" and that was with SET EXCLUSIVE OFF, SET TABLEVALIDATE TO 0, SET REPROCESS TO 0, USE...SHARED, so no locking, not even automatic locking should occur. And the table was not in exclusive use, because when I pressed ESC the table opened. But in an EXE any USE failed.

I could then "repair" the DBF by adding a record with browse and CTRL+Y and Deleted that new record. After that a USE worked as USUal.

In regard to your grid, what gave me flaky behaviour was scrolling, If you have grid lines on make sure the rightmost gridline also is still visible. And of course vertical scrolling may be more important than horizontal, but I would check whether double events occur in case the grid has to scroll from old to new record.

It often helps to look what users are doing, eg pressing PgDwn instead of clicking may also cause other event order or repeated events.

In some cases I set a property to seconds() as a flag it recently happened, especially with refreshing.

>Record out of range
In regard to that you surely know new yet buffered records have a negative recno and that won't be found after ZAP and INSERTING. It could also be you have all negative recnos of the INSERTED records, if the workarea you ZAP and reINSERT into is buffered, then GOTO positive recnos will fail.

Bye, Olaf.



 
Don't know if this is your case, but I made a quick test.

This code always generates the error when the row / column is chenged by a mouse click or when pagedown / up is pressed, but not errors when arrow keys are pressed.
Code:
PUBLIC ofrm
ofrm = CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
	ADD OBJECT grd as grid with recordsource = "cc"
	PROCEDURE load
		CREATE CURSOR cc (aa I,bb C(25))
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (lni * 10 + 1,"ooga")
			INSERT INTO cc VALUES (lni * 10 + 2,"chaka")
			INSERT INTO cc VALUES (lni * 10 + 3,"hooga")
			INSERT INTO cc VALUES (lni * 10 + 4,"hooga")
		NEXT
		GO TOP
	ENDPROC
	PROCEDURE grd.beforerowcolchange
		LPARAMETERS nColIndex
		LOCAL lnR
		lnR = RECNO()
		ZAP IN cc
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (lni * 10 + 1,"ooga")
			INSERT INTO cc VALUES (lni * 10 + 2,"chaka")
			INSERT INTO cc VALUES (lni * 10 + 3,"hooga")
			INSERT INTO cc VALUES (lni * 10 + 4,"hooga")
		NEXT
		GO m.lnR IN cc
	ENDPROC
ENDDEFINE

I found that (in this case, at least), the LostFocus event of the grid textboxes somehow messed up things.
So I added a grid refresh in the textboxes lostfocus, and the number of errors decreased (also predictable).
Finally I put the grid refresh inside a TRY CATCH structure.

This version seems alright :
Code:
PUBLIC ofrm
ofrm = CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
	ADD OBJECT grd as grid with recordsource = "cc"
	PROCEDURE load
		CREATE CURSOR cc (aa I,bb C(25))
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (lni * 10 + 1,"ooga")
			INSERT INTO cc VALUES (lni * 10 + 2,"chaka")
			INSERT INTO cc VALUES (lni * 10 + 3,"hooga")
			INSERT INTO cc VALUES (lni * 10 + 4,"hooga")
		NEXT
		GO TOP
	ENDPROC
	PROCEDURE init
		This.grd.column1.removeobject("text1")
		This.grd.column1.addobject("text1","mytextbox")
		This.grd.column1.text1.visible = .T.
		This.grd.column2.removeobject("text1")
		This.grd.column2.addobject("text1","mytextbox")
		This.grd.column2.text1.visible = .T.
	ENDPROC
	PROCEDURE grd.beforerowcolchange
		LPARAMETERS nColIndex
		LOCAL lnR
		lnR = RECNO()
		ZAP IN cc
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (lni * 10 + 1,"ooga")
			INSERT INTO cc VALUES (lni * 10 + 2,"chaka")
			INSERT INTO cc VALUES (lni * 10 + 3,"hooga")
			INSERT INTO cc VALUES (lni * 10 + 4,"hooga")
		NEXT
		GO m.lnR IN cc
	ENDPROC
ENDDEFINE

DEFINE CLASS mytextbox as TextBox
	PROCEDURE lostfocus
		TRY
			ThisForm.grd.refresh
		CATCH
		ENDTRY
	ENDPROC
ENDDEFINE


Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
I forgot the AllowCellSelection = .F.
I guess, in this case, the columns are destroyed.
Another possibility is the classic solution : before zap set grid's recordsource to "", and restore it after repopulating the cursor.

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
Thanks, all. I seem to have fixed it by resetting the grid RecordSource before repopulating the cursor and then setting it back. Not sure why I'd need them when using safe select, but it works.

Tamar
 
Or not. Thought I'd nailed it, but still there, as is the issue of BRCC sometimes firing repeatedly (recursively?).

I'll keep digging.

Tamar
 
So, I moved all the action to the grid's Click method (instead of BRCC and ARCC) and seems to be fixed, for real, as is another bug having to do with correctly populating the data input controls when the user clicks on a different record in the grid.

Now I just have to figure out how to get the right things to fire on keyboard movement. (Not asking for help on that just yet.)

Tamar
 
You're right about the recursive calling.
I'm almost sure that the form paint interfere with grid beforerowcolchange (indirect recursivity)

Just for fun.
If you press downarrow once, you will see in the debugout window an infinite call of BRCC.
But if move the mouse over the grid, the number of calls increase rapidly. That happens because of the paint event (the paint event is called when mouse is moved in/out/over the grid).
If you press downarrow second time, an error "Index does not match the table. Delete the index file" appears.

Now, if you uncomment either the DOEVENTS, either This.Refresh, the loop stops, but the cursor is stuck in the current row.

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

DEFINE CLASS myform as Form
	ADD OBJECT grd as mygrid WITH recordsource = 'cc'
	lNot = .F.
	PROCEDURE load
		CREATE CURSOR cc (aa I,bb C(25))
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (lni * 10 + 1,"ooga")
			INSERT INTO cc VALUES (lni * 10 + 2,"chaka")
			INSERT INTO cc VALUES (lni * 10 + 3,"hooga")
			INSERT INTO cc VALUES (lni * 10 + 4,"hooga")
		NEXT
		GO TOP
	ENDPROC
	PROCEDURE paint
		DEBUGOUT 'paint'
	ENDPROC 
ENDDEFINE

DEFINE CLASS myGrid as Grid
	allowcellselection = .F.
	ADD OBJECT column1 as column
	ADD OBJECT column2 as column
	PROCEDURE afterrowcolchange
		LPARAMETERS nColIndex
		DEBUGOUT "after",recno('cc')
		ThisForm.lNot = .F.
	ENDPROC
	PROCEDURE beforerowcolchange
		LPARAMETERS nColIndex
		DEBUGOUT "before 1"
*		DOEVENTS force
		IF ThisForm.lNot
			NODEFAULT
*			This.Refresh
			RETURN
		ENDIF
		DEBUGOUT "before 2"
		LOCAL lnR
		lnR = RECNO()
		This.RecordSourceType = 4
		This.RecordSource = ""
		ZAP IN cc
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (lni * 10 + 1,"ooga")
			INSERT INTO cc VALUES (lni * 10 + 2,"chaka")
			INSERT INTO cc VALUES (lni * 10 + 3,"hooga")
			INSERT INTO cc VALUES (lni * 10 + 4,"hooga")
		NEXT
		GO m.lnR IN cc
		THIS.Refresh
		This.RecordSourceType = 1
		This.RecordSource = "cc"
		ThisForm.lNot = .T.
	ENDPROC
ENDDEFINE

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
I guess you already said you have a work around. You may want to try ( in BRCC and ARCC)
if SameRow and SameCol
Tries = Tries + 1 && Have a small Label on the form to see how many times it fires.
return
endif
Tries = 0
SameRow = CurrentRow
SameCol = CorrentCol

rest of the code...

I do not know if it is too basic.


 
Especially the first example of Vilhelm-Ion always blanking the grid leads me to think it has to do with the coupled event afterrowcolchange.

Perhaps you could repopulate the cursor elsewhere, as it of course removes all rows there are in the ZAP moment and while you put the records back, the typical trigger of the beforerowcolchange is a row change and by zapping and repopulating you cause many row changes, though not in the grid control. But the active grid row is bound to the current record.

What would perhaps work is starting a run once timer with the code to repopulate the grid cursor. That is a timer set to a very low interval of a few ms, disabling or better releasing with it's first timer event. That helps in some situations to not interfere with other events.

Code:
PUBLIC ofrm
ofrm = CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
	AllowOutput=.F.
	ADD OBJECT grd as grid with recordsource = "cc"
	PROCEDURE load
		CREATE CURSOR cc (aa I,bb C(25))
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (lni * 10 + 1,"ooga")
			INSERT INTO cc VALUES (lni * 10 + 2,"chaka")
			INSERT INTO cc VALUES (lni * 10 + 3,"hooga")
			INSERT INTO cc VALUES (lni * 10 + 4,"hooga")
		NEXT
		GO TOP
	ENDPROC
	PROCEDURE grd.beforerowcolchange
		LPARAMETERS nColIndex
		If NOT PemStatus(Thisform,"timer1",5)
			Thisform.AddObject("timer1","runoncetimer")
		Endif
	EndProc
ENDDEFINE 

Define Class runoncetimer as Timer
	Interval=5
	Procedure Timer()
		This.Enabled =.F.
		LOCAL lnR
		lnR = RECNO()
		ZAP IN cc
		FOR lni = 1 TO 10
			INSERT INTO cc VALUES (lni * 10 + 1,"ooga")
			INSERT INTO cc VALUES (lni * 10 + 2,"chaka")
			INSERT INTO cc VALUES (lni * 10 + 3,"hooga")
			INSERT INTO cc VALUES (lni * 10 + 4,"hooga")
		Next
		If m.lnR<>Recno()
			GO m.lnR IN cc
		Endif
		Thisform.Refresh()
		
		This.Parent.RemoveObject(This.Name)
	Endproc
EndDefine
This almost works. If you are in recno 2 and move up to recno 1 the grid will get emptied. It's not blank, there still are grid lines, but it's as if you are at EOF instead of recno 1 or the cursor is empty. I tried to avoid GO 1 if you already are at record 1, but that also doesn't work out.

And how about updating exiting records instead of zap/inserts?

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top