Set tables Initial Selected Row from window custom property

I am trying to set my tables “initially selected row” based on a column value when the window is first opened. I have a custom property in my window with the variable for the column value comparison. How do i find the row based on the column value and should i do this in the “Initially Selected Row” expression or in a script on the table? Code below does not work when the window is first opened. I have this in the property change script of the table.

table = event.source.parent.getComponent('table')
data = table.data

for row in range(data.rowCount):
	if data.getValueAt(row, "ColName") == "value"
		table.initialRowSelection = row

You could try doing this with the Initially Selected Row property, but if this depends on matching values in the table, it seems this will already have been read before you set it. This means you will always see the row you selected the last time the screen was open. I would therefore just set the selected row directly.

The best place to put your code is in the visionWindowOpened event of the window itself. However, you have to be careful trying to run code that affects the UI, as this is all done on one thread. This means you have to put your code in a function and call it using invokeLater:[code]def setRow():
table = system.gui.getParentWindow(event).getComponentForPath(‘Root Container.Table’)
data = table.data
initial_selection = system.gui.getParentWindow(event).getComponentForPath(‘Root Container’).initial_selection

matchingRow = -1
for row in range(data.rowCount):
	if data.getValueAt(row, "ColName") == initial_selection:
		matchingRow = row
		break
table.setSelectedRow(matchingRow)

system.util.invokeLater(setRow)[/code]

1 Like

Hi,
Is there a specific reason that we can’t directly set the SelectedRow value to a specific number? I’m asking because the table I have has data in it I know that I just want the selected row to be set to 0 instead of -1 but even setting it from the visionWindowOpened event doesn’t do it. I guess I’m just curious why that is.

Actually I just tried the same setup but this time on the Internal Frame Activated even and it successfully sets the selected column to what I want when the window opens! perfect!:grin:

One of the quirks under the hood here that interferes is the sequence of events when the data binding delivers its result:

  1. Currently selected row is saved in a temporary,
  2. then set to -1,
  3. then the new dataset is applied,
  4. then the row is re-selected (by row number).

Steps 2, 3, and 4 each generate a propertyChange event. Ideally, one would examine the data and pick the right row number when the data property changes, but if you do so, step 4 will wipe out your change. The correct answer is to queue up the final row selection with an invokeLater, getting it to happen after step 4.

1 Like

@pturmel
Thanks for the detailed explanation, definitely makes more sense now. This issue wasn’t causing too much headache, I just wanted to try to get rid of small exceptions being thrown. good example is I have a page that has 4 tables, first table is grabbing schema and table name info from the DB and it has custom properties that grabs schema and table name depending on a row selected but when page would open with a -1 row selected you’d always see a the tables turn red for just a sec and that was driving me crazy, Now I can keep my sanity every time that page opens lol :laughing:

So is there any way not to have #2 happen? I have a couple tables that should really not change.The selected row should remain, even if the window changes briefly (like to go look at alarms for instance). When coming back to the main window, the two tables would ideally not have gone to -1. And it happens twice on every window open. I have logic under property change that filters for selected row and if it is ever -1, then set to zero which of course triggers another property change, but i can’t figure out where the second -1 comes from, or really the first one either TBH. Also happens if I do a project update.

No. It is internal to the component. If you need a persistent row selection, you will need to track that state externally and apply it whenever the dataset changes.

Two techniques I have used to persist information:

  1. Save the data in a client tag. I don’t like this as much because when importing or exporting components from a project to another project you have to remember to bring the tag. When you import client tags they overwrite all the existing client tags in your project so they have to be imported in a separate step or added by hand.

  2. Make a module level variable or dictionary that saves the data in a project script. I like this solution because it is very clean and you can make project script specific to your screen or template which is easy to remember to import. It is also very fast.

Here is an example using a dictionary but the module variable can be anything, I have use same technique for persisting selected row of a dataset or dropdown. Note the script path is “project.Services.utility”. Using the full path to reference the module variable is essential to getting this to work.

Also a good link to look at http://mudge4.rssing.com/chan-9724271/latest.php#item4

#save a list of tags associated with a UDT in a dictionary so the lookup only happens
# one time per client session per UDT path

#module level dictionary that persists entire client session
_browsTagDict = {}

def clearBrowseTagDict():
	project.Services.utility._browsTagDict = {}
	
def getUDTtags(udtPath):
	
	tagListIsAlreadyInDictionary = udtPath in project.Services.utility._browsTagDict
	if tagListIsAlreadyInDictionary:
		#note must use full path to _browseTagDict  to make this work
		tags = project.Services.utility._browsTagDict.get(udtPath)
		print 'pulledFrom cache ' + udtPath
		
	else:
		tags = system.tag.browseTags(udtPath,"*","UDT_INST",sort="ASC")
		project.Services.utility._browsTagDict.update({udtPath : tags})
		print 'saved to cache'
	
	return tags

Here is an example using the script module level persistence for selected row:

In a script “services.serviceViewerWindow”:

#used to persist the selection in the service viewwer window
_lastSelectionIndex = 0

def getSelectedRow():
	print 'read '  + str(_lastSelectionIndex)
	return project.Services.serviceViewerWindow._lastSelectionIndex
	
def setSelectedRow(rowIndex):
	project.Services.serviceViewerWindow._lastSelectionIndex = rowIndex
	print 'write '  + str(_lastSelectionIndex)
	

Then in the ‘visionWIndowOpened’ event of the window containing the powertable “selectionTable”

def setRow():
	print event.source

	lastSelectedIndex = project.Services.serviceViewerWindow.getSelectedRow()
	print 'last index: ' + str(lastSelectedIndex)
	system.gui.getParentWindow(event).getComponentForPath('Root Container.tableServiceList').selectedRow = lastSelectedIndex

delaySeconds = 1	
system.util.invokeLater(setRow,delaySeconds)type or paste code here

Then in the “property change” event of “selectedTable”:

#persist the selected row
if event.propertyName == 'selectedRow':
	selectedRow = event.source.selectedRow
	if selectedRow >= 0:
		project.Services.serviceViewerWindow.setSelectedRow(selectedRow)