Power Table - Cells in Certain Columns Lose Focus/Cursor

I have a few power tables in which the arrow keys and enter work completely fine on some columns to navigate cells, but on certain columns the focus/cursor is lost. Any ideas on what may be causing this? In the attached picture, it happens on column 'I'.

More Info:

  • Using 7.9.4
  • For the attached picture it happens to be the last column, but this is not necessarily the case on other power tables with the same issue
  • I am using the OnCellEdited extension function to update data in a MSSQL table
  • All columns have the same Table Properties

import system
self.data = system.dataset.setValue(self.data, rowIndex, colIndex, newValue)

id = self.data.getValueAt(rowIndex, 'id')

query = "UPDATE BRBoardLocationStage1 SET %s=? WHERE ID=?" % (colName)
args = [newValue, id]

system.db.runPrepUpdate(query, args)

system.db.refresh(self,"data")

print ["Col: " + colName,
"Row: " + str(id),
"Old Value: " + str(oldValue),
"New Value: " + str(newValue)]

Any help with this would be greatly appreciated.

Any suggestions on this, have not been able to determine root cause for this issue.

Is probably the culprit - if the data "changes" out from underneath the current table model, it won't track your selection when the new data is rendered. You could try grabbing the current selection before running system.db.refresh, and then in a system.util.invokeLater-ed function, set the selection back to what it currently was.

1 Like

You were correct! That was the culprit! Thanks a lot for the help. Below is my code in case any one else has trouble with this. Note that this code is in the OnCellEdited() extension function of the power table.

I added a conditional statement in the system.util.invokeLater function so that the cursor stays on the same cell if it is in the last row of the viewDataset. I also set polling to OFF

It was also important to realize that the power table’s dataset and view dataset differed in size. The dataset is 9 x 14 while the viewDataset (what is not hidden in the power table) is 9 x 10. For this reason, my code has the (col-1) in the change selection method of getTable().
image

	import system
	def runThisLater():
		view_rows = self.viewDataset.getRowCount()	#get # of rows in the power table view		
		
		#set selected cell based on rowIndex
		#if not in the last row, move cursor to below edited cell
		#if in last row, move cursor to original edited cell position
		if row == (view_rows-1):
			self.getTable().changeSelection(row, col-1, 0, 0)	
		else:
			self.getTable().changeSelection(row+1, col-1, 0, 0)	
		return
				
	self.data = system.dataset.setValue(self.data, rowIndex, colIndex, newValue)	#assign self.data to underlying dataset
	id = self.data.getValueAt(rowIndex, 'id')	#get ID field value for given rowIndex
	row = rowIndex	#save rowIndex into variable row
	col = colIndex	#save colIndex into variable col
	
	#Run update query for given row/column edit
	query = "UPDATE BRBoardLocationStage1 SET %s=? WHERE ID=?" % (colName)
	args = [newValue, id]

	system.db.runPrepUpdate(query, args)
	system.db.refresh(self,"data")
	
	#print update query summary of changes
	print ["Field: " + colName,
			"ID: " + str(id),
			"Old Value: " + str(oldValue),
			"New Value: " + str(newValue)]
			
	#Delay the execution of function runThisLater() by 1 second.  This allows update update query and refresh enough time to render
	system.util.invokeLater(runThisLater, 1000)
1 Like

Hi Paul. How do I do this for powertable.data that is bi-directionally bound to a dataset tag. It seems the 10 second scan class is pushing focus on the table to the upper left cell of the power table, whether one of the cells has focus or not. I looked up all the methods and properties on the power table, and the list is a novel. I see several methods and properties that refer to “focus” in their names. Is their a direct way to keep the focus from coming out from underneath you when your doing data entry in the column of a table that’s bound to a tag? (The reason for the bi-directional binding is that I want other members of the team to be able to edit the values in the table from their clients and have those edits refresh on all clients.)

Would this be a good application for a bi-directionally bound transaction group governed by a change in the data? Seems like I had a scan class that only updated a tag on a change in value, but not sure that would work either.

For now, I think i’ll just create a scan class with a longer delay between updates…but would like to understand how to control this.

If the tag is a memory tag, the scan class should be a no-op. Only writes from other users would propagate. If an expression or query tag, then what you want simply won’t work. The user changes will keep getting smashed as you’ve seen. Note that datasets update all-or-nothing. You won’t be able to have one user working in one row/column while another user is working in a different row/column. (I can imagine some rather complex things to make that work, but it isn’t a simple bidirectional binding.)

Thx for engaging, Phil. You’re always a great help.

Yes,it is a gateway memory tag. All the “system of record” data is in MySQL, so I’m just trying to give users a way to do ad hoc analysis using system of record data as a base case. One table is bound to a Query Tag, which is pulling dynamic data from MySQL into that table. I have written scripts in a second data entry table to slice, wrangle, and output aggregate results to various numeric text fields using data from manually entered data and the dynamic data in the tag-bound table. Scripts are also needed to keep the entered data lined up dynamically as time ticks by with the dynamic data table, but this write-back to the data entry table from its separate bi-directionally bound memory dataset tag is too disruptive.

I’ve been playing around with some combination of derived and client memory tags. My intuition tells me there’s something there, but still haven’t figured that out yet.

How do I create a “No-Op” scan class in Ignition scan class vernacular? Will the No-Op scan class also stop the change in focus to the top_left cell of the table as well? Seems like a write to memory should quick and painless.

I would recommend not using dataset tags at all. Just query directly into a table for ‘data of record’. Possibly set to no polling to not disrupt the user (poll deliberately when needed with system.db.refresh). When saving, write directly to MySQL from the client, then you can use system.db.refresh to restart.

There’s not really any no-op scan class in v7.9. Its just that changes to a memory tag will propagate to bindings only when written to (other than binding startup in the client). Query and expression tags will execute and propagate on every scan. Don’t use them for editable UIs. Remember, datasets propagate as a complete entity–there’s no way to not refocus upon update from a binding. You can try to implement maintenance of focus with a scripting state machine that tracks user changes and refocuses after a data property change. Messy.

If the users need to be synchronized to each other in some way, you’ll probably have to script it all, with deliberate decisions at each possible conflict point. Probably bringing query bindings into custom dataset properties instead of directly into table data properties.

1 Like

Ok, I read you, I think. Thanks for your thoughtful answer Phil…apologies for the delay in my response.