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

AfterRowColChange and select Value from Grid

Status
Not open for further replies.

sashaDG

Programmer
Jun 20, 2022
112
BY
Hello, I have a question that I can't solve.
There is Grid, TextBox.In the TextBox, I can enter values, a search occurs in TextBox.InteractiveChange(everything works here).
After searching, a record in the grid is highlighted.

Created a function in grid.AfterRowColChange: by clicking on the cell n of the column and m of the row, the value is transferred to the TextBox.(Everything works)

Code:
ValueField = ThisForm.grid1.value
ColumnActive = ThisForm.grid1.ActiveColumn

GetFieldValue(ThisForm, ValueField)

FUNCTION GetFieldValue(myform, fieldGrid)
SelectCaption = 'myform.Grid1.column'+ALLTRIM(STR(columnactive))+'.header1.Caption'
	 DO CASE   
	 	CASE &SelectCaption == 'case1'
	 	 	myform.sNaim.value = (fieldGrid)
			InputN = (fieldGrid)
		CASE &SelectCaption == 'case2'
	 	 	myform.sKpost.value = (fieldGrid)
			InputKP = (fieldGrid)
		CASE &SelectCaption == 'case3'
	 	 	myform.sOdse.value = (fieldGrid)
			InputOdse = (fieldGrid)
		CASE &SelectCaption == 'case4'		
	 	 	myform.sOdse.value = (fieldGrid)
			InputOdse = (fieldGrid)														
 	ENDCASE 
ENDFUNC

Troubles occur when clicking on a field in the Grid, the value enters the TextBox (ProgrammaticChange is triggered). Then I change the value in the TextBox, InteractiveChange fires and the Grid changes. The best match is at the top and HIGHLIGHTED

Then I click on another line and AfterRowColChange is triggered AND the value that was in the top goes to the TextBox and I moved to the place that I clicked on

There was such an error when I cleared the TextBox and the Grid accepted the Source Table, then I transferred the focus (ThisForm.Grid1.column8.text1.Setfocus) and everything worked. I understand that this is a crutch, at that time I didn’t come up with anything better

It's strange, but if this sequence of actions is carried out twice, then the TextBox does not change the second time.
 
I don't know what I would expect from ThisForm.grid1.value

The grid is having columns and a recordsource and that has rows and the values then are in the column controls values. But you might have used a feature of the grid I'm not aware of.
I usually read fields from the recordsource, not from the grid as a control. Activating a cell in the grid means activating that record as the current record and then knowing the column controlsource Id know what field of the grid recordsource (the grid cursor) to read.

Chriss
 
I read the help and see this documented for the VALUE property:

VFP help said:
For the Grid control, the Value property is available only when the Grid control has focus.
So that's a restriction of only using the grid.value when the grid is focused. It doe neither tell what to expect from the value, not even when the grid has focus.

But in the end, as I stated, the controls are mainly there for the user, not for code, for code that wants to read data, read from the data, not from controls. There are rare circumstances I would differ from that. An obvious exception of the rule is when you act on THIS.VALUE in code in events closely related like change events. Especially since the control.value only gets stored once you pass the valid event.

Chriss
 
Chris said:
I usually read fields from the recordsource, not from the grid as a control.
Well, where can I read about it, I did not find it on the form. Maybe there are examples?
 
ThisForm1.Grid1.column4.text1.click() also suits me, but due to the fact that I created the grid in Design time and not programmatically, the source is the cursor (created from two tables). I don't know if Grid can be programmatically controlled. I know one thing, when I add a table to the RecordSource in the design time (that is, columns, headers, texts are visible), I can safely take the information that I need.
 
I don't get what you want to tell.
What's your problem with reading data from a recordource?

By the name alone it tells you the answer, the record source is the source of records displayed in a grid.
If I want something I usually go to the source, not to a secondary thing that got it from the source, too.

It's an alias, a name of a worrkarea. That exists independent from the grid.

If you click on the grid, the row you click on becomes the active record in the recordsource.
You do know this, do you?

So in AfterRowColChange you can always read out any field from the active record that you need to read. A field from the workarea the grid displays, not from grid.value or grid.columnX.text1.value or even something else that replaced text1.

Why would you want to read something from a control, if that control value originally comes from a table or cursor where it is much easier to read from?

Reading table.fieldname is just that, you don't need an article to learn this, you already used this, Sasha. So often, that I wonder what is so difficult to understand.

Once more, very general rule of thumb:

You want to know some data? Ask it from the table, even if there are controls showing it, you know where it came from, you set up the controls so they show the data from a table. The controls are for the user to get this data displayed and to change it. But your code isn't a user that looks at a control, your code is "looking" at the data directly, it doesn't need to read from a control. Make use of that.

Chriss
 
If you click on the grid, the row you click on becomes the active record in the recordsource.
You do know this, do you?
I didn't think before, do I need to use SEEK? There is no primary key in the table

You want to know some data? Ask it from the table, even if there are controls showing it, you know where it came from, you set up the controls so they show the data from a table. The controls are for the user to get this data displayed and to change it.
Yeah, im know
 
sashaDG said:
do I need to use SEEK? There is no primary key in the table
No, you don't need to do that, the grid does activate the record you click into.
The grid does that no matter what its recordsource is.

You are at the record that is clicked. So why SEEK, you'd only get to another record.

The grid activates the record, there is nothing to do anymore, that is already done.
You now just need to know what field you want to get from the active record/row. That shouldn't be that hard, the AfterRowColChange gives you the column that you activated.

So grid.Colunmns(nCol).controlsource will tell you that field. And you just need to read that.


Chriss
 
ThisForm.text3.value = ThisForm.grid1.Columns(ColumnActive).controlsource and i have NameTable.NameField, sorry but i dont know how read that, in google and forum i not found
 
Yes, the controlsource is NameTable.NameField
So how do you read the field?

Code:
lcField = grid.Columns(ColumnActive).controlsource
ThisForm.text3.value = &lcField
Or even better:
Code:
lcField = grid.Columns(ColumnActive).controlsource
ThisForm.text3.value = Eval(lcField)

Chriss
 
I would expect from you to know what you need to read from the table just by knowing the column index only.
There's actually not even the need to look into the controlsource.
And even less to the header caption. The header caption starts by being the field name, but you can change the header caption to something else.
Fo example the header caption is firstname, but you will want to display a caption "First Name", won't you? That wont give you the data.

The controlsource is what VFP technically uses to read what to display and to store back what theuser modifies.

You already know at designtime which column number means what field of the table, don't you? So why are you so helpless, you could even do it like this:
assume your grid shows firstname,lastname,position

Code:
LPARAMETERS nColindex
SELECT (THIS.recordsource)
Sometextbox.value = ICASE(nColIndex=1, firstname, nColindex=2, lastname, nColIndex=3, position, Sometextbox.value)

You simply "decode" the nColindex by your knowledge about the grid design you did already. You don''t even need to know how to determine this, you already know it as you design it.

Chriss
 
Thank you for your advice and your time. The problem remains the same
0111_z5iuys.png

Screenshot, when setfocus on grid.
The situation is this: I stand on the 4th column, leave the cursor, and get on another control. I return to the Grid, I stand on the 6th column, AfterRowColChange 4 and AfterRowColChange 6 work. Question: is it possible to somehow leave the cursor on the field in the Grid? And at the same time print in other controls?
 
Why did you put something into the Message event?

help said:
Included for backward compatibility. Use the StatusBarText Property instead

I don't get what your problem is with this events chain.

When you set the value of a control that does not move focus there. The event log also doesn't tell that any control outside the grid had focus. You just had ProgrammaticChange events in those controls, they happen when you change their value, that doesn't mean they got focus.

You already have what you want: The focus doesn't move from the grid, it moves from grid column4 to grid column6, that's the only focus change that happened by your log.

The only weird thing is the message event. Set controls StatusBarText and that will show a status bar text, don't use the message event. It does nothing regarding the focus, though.

Chriss
 
Why did you put something into the Message event?
Nothing

You already have what you want: The focus doesn't move from the grid, it moves from grid column4 to grid column6, that's the only focus change that happened by your log.
This is a screenshot when the cursor was on the textbox and moved to the grid

I have a question: I built a Grid on the cursor and in the design time I have neither Headers nor Columns nor Column.text1
I would like to add a code to the LostFocus(), but I don’t know how to get there
Or it is possible to leave the pointer in Grid?
 
sashaDG said:
This is a screenshot when the cursor was on the textbox and moved to the grid
Which textbox, which grid column?

You enter to the grid at column 4, there is the AfterRowColchange(4). Then due to the code there you trigger programmaticchange events to text3 and snaim textboxes. But that doesn't move focus to them.
Next events are for text1 of column4 and column6, all within the grid. It might not have been triggered manually by you, because the BeforRowColChange(4) happens very instantly after the AfterRowColchange(4), and indicates the next column change already, up to AfterRowColchange(6), of course.

It could be triggered by code you have in snaim.ProgrammticChange(), so you may have code there you forgot that does set focus to grid column 6? I don't know, the event log does not tell everything, as we don't see all code that is in all these events. But you see which events happen, so look into all of these to see why next things happen.

To program something in grid controls, simply set the columncount to what you need it to be at runtime. Then at runtime don't just set grid.recordsource to the cursor, that will reconstruct the grid, and you lose all you had there, you have to create at least an empty cursor that you bind to the grid, so the controls within aren't reconstructed. Then you also don't change the recordsource, you ZAP the grid cursor (which you don't need when it starts empty) and append the result you want to have in the grid.

The other alternative for grids not to reconstruct and thus lose controls, their settings and event code is to use views, a view REQUERY("viewalias") won't destroy the grid but keep everything in it as is and just change the view data content according to the view query and parameters you use in the view. It's the simplest way to feed a grid.

Chriss
 
One thing that could automatically move focus from grid column4 to column6 is that column4 can't get focussed - when it's disabled, for example. That could be, because the event log does not show the column4.text.GotFocus() event, it only shows that the column4 textbox valid and lostfocus happen. So that points out while you click on it and the AfterRowColChange event happens, the focus does not get there, really, and the next column that can receive the focus seems to be column6.

Chriss
 
Good afternoon Chris, thank you for your advice. I found a solution, when I do actions outside of the Grid, I write ThisForm.grid1.ActivateCell(1,1).
 
I don't know why you need this, setting a value of a control does not cause it to get focus, actually you'd need to call control.setfocus() to give focus by code or have a KEYBAORD command that moves focus by doing one or more {TAB}s, which is an indirect method to move focus. Also returning .t. from valid moves the focus to the next control in taborder and returning a numeric value moves tab by as many controls as the number. So look out for something like that, anything else does not move focus by code, the only other mechanism I also mentioned is unfocussable controls.

A control can deny to get focus by returning .F. from When, but that's the last thing I can contribute.

You have a solution, but wouldn't you like for focus to stay within the control that has focus? You can always do _screen.activecontrol.setfocus(). It won't help in situations the activecontrol is a grid, as the actual active control in a grid is in one of its columns, the grid only has focus as the parent of that active column's cell control. And if the cause that moves focus is happening after the code ends, that might still mean focus moves anywhere else. But most likely it helps. Also, I don't see how focusing cell(1,1) is a solution if you're concerned about column 6 getting focus after column 4 is clicked.

I wonder if you looked thoroughly, if you see no code in an event, there might be parent class code. The event log only tells about object names, not classes used but COVERAGE logging would tell you that. Code of a class hierarchy isn't shown all at once, you only see code of whichever object you're editing, inherited code isn't shown, as you can't edit it anyway, you have to edit the parent class to edit it. But there's a tool that lets you at least see it, a "View Parent Code" button. Whether there is parent class code is always indicated by that button being dis- or enabled. Just for sake of an example, I opened up a random class from the gdiplusx project:
parent_class_code_tltcd7.png

Clicking on it shows the list of parent classes and those having code in bold.

In a method that also is empty in all parent classes, this "View Parent Code" button is disabled:
noparentclasscode_vnsswn.png


A way to get a detailed log of not only the events that happen but code lines executed can shed a light on what you're missing. You can [tt]SET COVERAGE TO somefile.log[/tt] and then can see data about which line of which method or event of which class of which class library ran. Not the code itself, unfortunately, but that also helps to know where to look for code that influences the focus, in this case or has any other influence you don't know where it came from.

Last not least, setting a break point to single step through code with the debugger can help. It's tricky though, when focus is the topic, because the focus will also move from the debugger window and you may not be able to follow step by step even in the debugger therefore, too. There is a debugger setting to not single step through tier events, which is disturbing if a timer runs in an interval faster you can single step through code, which traps you into debugging timer event after timer event. But there is no setting to keep the debugger the active window, neither when you have the debugger window as child window of the VFP main window or as its own separate top level window. Nevertheless, using the debugger you see each line of code executing in general, no matter which classes and objects are involved, the only way the debugger does not show code is if an item isn't compiled with debug info, which can cause the trace window to show a message saying that code is out of sync. Then just once build the project with "recompile all files".

Chriss
 
And one more thing about event tracking: Event tracking can list events even if no coe is in it, it is base bahvior, that still runs. In some cases events are missing from the log, if they have no code.
But then also COVERAGE logging won't log anything, of course. So something could still be under the radar.
From your log it can't be seen if there is class code involved, assuming it's all native base classes the event log also only shows events, an it tells you clicked on column4 and focus ends on column6, but it dos not show focus moving away from the grid.

Chriss
 
And if the cause that moves focus is happening after the code ends, that might still mean focus moves anywhere else. But most likely it helps. Also, I don't see how focusing cell(1,1) is a solution if you're concerned about column 6 getting focus after column 4 is clicked.
Because I take values from some columns in the TextBox, but I don’t take values from the first column.

I did not create a custom class, "View Parent Code" is disabled for me everywhere.
As for COVERAGE, this is the first time I've seen it and I think it's very interesting.
Until I try it, because it works fine. Of course, I used debugging, but it did not help.

Thanks for your advice Chris. Have a nice day!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top