Bug Report: Power Table configureCell()

There’s a bug in the configureCell() extension function on the Power Table component in Vision.

I tested on 8.1 and 7.9, both of which have the bug.

When selecting a row from a power table, configureCell() does not execute for all cells. Instead, the cells it executes on depend on the index of the selected row. There appears to be a logical bug in how the cells are looped over.

To reproduce the bug:

  1. Create a Power Table and populate it with 5 values in one column of data. The bug is present regardless of the number of columns or rows, but it’s easier to test with less data.
  2. Set the Power Table’s configureCell() function to:
def configureCell(...):
    print rowIndex, self.selectedRow
  1. Run the component and select various rows. In the debugging console you’ll see that the rows being processed by configureCell() are not consistent and depend on the row selected in the UI.

No, configureCell is called any time the cell needs to be displayed or refreshed. Scrolling, selecting, and data updates can all trigger this call, and it will only be called as needed. Cells out of sight due to scrolling may not be called at all.

Rethink whatever you are trying to do in configureCell that doesn’t fit the display paradigm. Certainly do not attempt to change any state in the table there.

Not a bug (in Ignition).

2 Likes

Thanks for the insight, however, what you are describing doesn’t reflect the actual behavior of the component.

It’s also not true that configureCell() “will only be called as needed”. If you actually test it, you’ll see that it executes when it isn’t necessary and the execution behavior is inconsistent depending on the row you select and which row was previously selected.

Yeah, well, it’s Swing underneath. The repaint operation is the primary driver, and “dirty” display rectangles can merge/overlap in odd ways. So, it should read “called as needed as determined by Swing”. If you are really curious, you can construct and log a fake java exception to see all of the call chains. Have fun.

Still not a bug (in Ignition). Attempting to do anything other that supplying display attributes for the requested cell is a recipe for grief.

1 Like

Really think a bug would be around that long? Possible, not likely though. Just because it doesn't act like you want, doesn't make it a bug.

Bite your tongue! This one lasted from FactoryPMI days through v7.9.14/v8.0.6 :

1 Like

That’s why I said possible

The function is not running for the rows that are actually displayed, instead, it runs for all rows between the row you select and the row previously selected. This is a bug.
I think @pturmel’s explanation helps narrow down what’s happening. There appears to be a logical bug in determining which rows are displayed and therefore which need to be updated.

If you truly think it’s a bug, contact IA support and they will issue you a ticket and then you can show them.

https://support.inductiveautomation.com/hc/en-us

I guess the real question is why do you care if it is called more than “necessary” ?

Good question. On large tables, it can cause serious performance issues. We’ve ran into this problem multiple times over the years with Ignition.

That usually means you are accessing stuff in configureCell that isn’t local to the component. Like system.* calls that go to the gateway. There should be custom properties on your table that pull in all ancillary data you need for display, so the configureCell event itself doesn’t have to go get it. (It is already there.)

If your performance craters when you run a remote client over a satellite connection or worldwide VPN, you’ve probably made this kind of mistake.

That’s good advice.
With the extra executions, we’ve seen performance issues on large tables even when executing simple logic that doesn’t rely on anything external to the table.

If you have examples, post them here. Or ask support for help if it isn’t something you can share.

As Phil said, this is not an Ignition bug. You can easily demonstrate the same behavior in a standalone Swing project with a JideTable or JTable you create yourself; TableCellRenderer makes no guarantees about when it will be called, and the behavior of painting and repainting is non-trivial.
It is absolutely true that on very large tables, even the minimal overhead of calling into Jython is going to add up. You can minimize that as much as possible by using custom properties well, as Phil recommended, but there is a limit. In theory, I would expect a fully custom Java component (authored through the module SDK) to perform at the same rendering task than the power table, because it wouldn’t have the additional Jython overhead - but obviously that’s a tall order to set up.

To workaround this bug in Swing, I update the table data when selectedRow changes.

Power_Table.propertyChange():

if event.propertyName == 'selectedRow':
	event.source.data = event.source.data

It isn’t pretty, but it works.

Some tips for superior performance on events that get called (a lot) by Swing:

  • Move all use of class and def to a project script module.
  • Make all ancillary data needed available in custom properties. Preferably using asynchronous bindings (Tag bindings and Query bindings) or property bindings. If a script is needed to collect ancillary data, use system.util.invokeAsynchronous() to do the time-consuming part off the GUI thread.
  • Avoid loops. If a lookup will be needed, post-process the corresponding ancillary data into a Python dictionary, and cache it in the component’s Swing “client properties”. The fast path in the event would use d=self.getClientProperty(...) then d.get(someKey) to perform the lookup.
  • Move as much code as practical into a project script module.
1 Like

OMG! No! That makes configureCell get called even more.

1 Like

:+1: :+1:

I’ve surrendered to the pain

Does anything exist in the manual, or elsewhere, that explains this in more detail?

1 Like