[8.0 Vision Client] Power Table - saving column order/sizing

Good Afternoon,

I'm attempting to save out column order and width of a power table for each user that uses it in the vision client. Initially I thought I could just use a power table's Column Sizing property ('.defaultColumnView' in Python), and while I'm able to save those changes while running in Designer, when I run in staging/published mode, the Column Sizing property doesn't update when changing the order or sizing of the columns, so this is no longer an option. Is there another property I can look into to save and edit a power table's column order and width?

This problem was addressed in 2014 on the topic linked below, but the answers provided aren't sufficient for saving data at run time since they still use '.defaultColumnView'

Is there any news?

Global default table changes are handled automatically in the designer with the defaultColumnView propertyChange event, but custom default table changes on a client by client basis would have to be handled with scripting. To do this, simply get the columnModel, and then get or set whatever you want:
Take for example, this test button script:

powerTable = event.source.parent.getComponent('Power Table') 
table = powerTable.table
columnModel = table.columnModel
for index, column in enumerate(columnModel.columns):
	print column.identifier + "'s width = ", column.width
	print column.identifier + "'s displayed Index = ", columnModel.getColumnIndex(column.identifier)

On this table:

Here is the output:

Float Column's width =  166
Float Column's displayed Index =  0
Int Column's width =  125
Int Column's displayed Index =  1
String Column's width =  138
String Column's displayed Index =  2
Boolean Column's width =  138
Boolean Column's displayed Index =  3
Date Column's width =  137
Date Column's displayed Index =  4

To change the width of a specific column such as the int column, the code is this:

intColumn = columnModel.getColumn(columnModel.getColumnIndex('Int Column'))
intColumn.preferredWidth = 200


To move the int column to a specific position such as position 0, the code is this:

intColumnIndex = columnModel.getColumnIndex('Int Column')
columnModel.moveColumn(intColumnIndex, 0)


If I wanted to set a table up to where it remembered each client's changes and subsequently restored them during the next session, I would use a column model listener on the power table's initialize extension function and write any changes to the database as they happen. Alternatively, one of the window's closed or closing event handlers could be used to save the data all at once at the end of the session.

Here is what a listener script on the initialize extension function would look like:

	from javax.swing.event import TableColumnModelListener
	class ColumnModelListener(TableColumnModelListener):
		def __init__(self):
		def columnSelectionChanged(self, event):
		def columnMoved(self, event):
			for column in event.source.columns:
				print column.identifier
				print event.source.getColumnIndex(column.identifier)
				#save this information to the database
		def columnAdded(self, event):
		def columnRemoved(self, event):
		def columnMarginChanged(self, event):
			for column in event.source.columns:
				print column.identifier
				print column.width
				#save this information to the database
	table = self.table
	#Set table column properties from the database here 
	#Then add the the listener to save any subsequent changes
	listener = ColumnModelListener()

Is there a way to set up something like column sizing?
in order to store in DB only one big string, instead of N rows of N columns?

I still do not fully understand the enormous amount of numbers and text that the sizin column has as it is changed and I do not achieve favorable results, I do not see that there is a document of that either.

So I look for what instead of saving on an table:
column name, index, width, id_user.

id_user, big string with everything you need

I suppose the easiest route to achieve this would be to use something like the parent window's internalFrameClosed event handler. Then, just simply throw all of the column information into a dictionary that you save to the database.


userName = system.security.getUsername()
powerTable = system.gui.getParentWindow(event).getComponentForPath('Root Container.Power Table')
table = powerTable.table
columnModel = table.columnModel
columnProperties = {str(column.identifier): {'location': columnModel.getColumnIndex(column.identifier), 'width': column.width} 
	for column in columnModel.columns}

#INSERT or UPDATE the following information:
print userName
print columnProperties

Then, when the user first opens the table use a script similar to this to change the table:

columnProperties = system.util.jsonDecode(yourStoredDatabaseString)
powerTable = event.source.parent.getComponent('Power Table') 
columnModel = powerTable.table.columnModel
def restoreSavedColumnSettings():
	columnsChanging = False
	for column in columnModel.columns:
		column.preferredWidth = columnProperties[column.identifier]['width']
		preferredLocation = columnProperties[column.identifier]['location']
		actualLocation = columnModel.getColumnIndex(column.identifier)
		if preferredLocation != actualLocation:
			columnModel.moveColumn(actualLocation, preferredLocation)
			columnsChanging = True
	return columnsChanging
restorationAttempts = 0
while restoreSavedColumnSettings() and restorationAttempts <= 5:
	restorationAttempts += 1

Edit: I set up a test window with a power table to test the above scripts, and I discovered that with multiple column moves, more than one iteration is sometimes required to restore the table using the original script. I modified the original script to automatically reattempt [up to 5 times], if the initial column changes do not result in the preferred configuration.

In case it's helpful, here is the test window:
testWindow.zip (44.6 KB)
The save button saves the column information as a string on a custom property, and the restore button restores the column settings using the custom string property.

hice unos cambios menores en el codigo,
pero no logro recuperar la columna que guardé en la base de datos, a través de un vision client tag configurado bidireccional, y como read/write..

boton guardar:

import json

id_user = event.source.parent.id_user

powerTable = event.source.parent.getComponent('Power Table')
table = powerTable.table
columnModel = table.columnModel
columnProperties = {
str(column.identifier): {
'location': columnModel.getColumnIndex(column.identifier),
'width': column.width
for column in columnModel.columns

columnPropertiesJson = json.dumps(columnProperties)

query = "UPDATE public.tbl_usuarios SET header_tareas_compartidas = ? WHERE id_user = ?"
params = [columnPropertiesJson, id_user]
system.db.runPrepUpdate(query, params)

powerTable.columnProperties = columnProperties

en internal frame activated, intenté recuperar la columna donde estoy guardado el header de esta manera:

datos_usuario = system.gui.getParentWindow(event).getComponentForPath('Root Container').DatosUsuario
if datos_usuario is not None:
header_tareas_compartidas = datos_usuario.getValueAt(0, "header_tareas_compartidas")
if header_tareas_compartidas is not None:
system.gui.getParentWindow(event).getComponentForPath('Root Container').header_usuario = header_tareas_compartidas

pero no logro que me funcione, el columnProperties de la tabla, apunto al dataset, donde tengo a través de un vision client tag la consulta guardada..

I don't see anything wrong with these save procedure modifications

...but here:

What is this user dataset? This is custom dataset component property that is bidirectionally bound to a client dataset tag? What is its purpose?

Assuming this dataset tag is how you are retrieving the data from the database, I set up a test with a client tag that contained the column data as a string in a dataset and simply read the tag directly. It worked as expected:

tagData = system.tag.readBlocking('[client]testTag')[0].value.getValueAt(0, 0)
columnProperties = system.util.jsonDecode(tagData)