Ignition Power Table Border Follows Arrow Keys via configureCell

Stefan Weidner8 min read
HMI / SCADAOther ManufacturerTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

What draws the border you see while tabbing or arrowing?

Follow the event. A Tab or arrow key press goes to the inner Swing table that the Power Table wraps, not to the outer Vision component. The inner table moves its lead selection, updates the selection model, and repaints the cells whose state changed. For each repainted cell, the table's renderer runs, and the renderer calls the configureCell extension function. The thin highlight you see on the lead cell is the look-and-feel's default focus-cell border. Nothing in the Property Editor controls it.

Editing is a different path. When a cell enters edit mode, the cell editor component draws on top of the renderer. That is why you can style the border during editing but not during navigation: navigation never reaches the editor. To change the navigation highlight, work in the renderer path, which means configureCell.

Stage Component What you can change there
Key press (Tab, arrows) Inner table key bindings Nothing in script; this stage moves the selection
Selection update Inner table selection model Selection properties (selectedRow, selectedColumn) read in propertyChange
Repaint of affected cells Renderer configureCell return dict: background, border, and other style keys
Edit mode Cell editor Editor styling, which does not apply during navigation

Which two approaches produce a custom navigation border?

Approach A: key off the selected argument. configureCell receives a selected boolean for every cell it renders. That flag follows arrow and Tab movement, because each key press changes the selection and triggers a repaint of the old and new cells. Return a border entry when selected is true, and the thick border moves with the cursor.

Approach B: anchor the border to the clicked cell with custom properties. If the border must stay on the cell the operator originally clicked while the arrow keys move the selection elsewhere, selected is the wrong signal. It stops being true for the clicked cell as soon as the selection moves. Store the clicked row and column in custom properties on the Power Table. Write them from the onMouseClick extension function, and compare against them in configureCell.

Criterion A: selected argument B: clicked-cell custom properties
Border location Current selected cell; follows Tab and arrows Cell last clicked; stays put while arrowing
Scripts touched configureCell only configureCell, onMouseClick, propertyChange handler
Custom properties None Two integers, e.g. clickedRow, clickedColumn
Manual repaint required No; selection change repaints automatically Yes; self.repaint() after writing the properties
Clearing logic Automatic when selection clears Explicit reset to -1 when selection goes to -1
Depends on selection mode Yes. Row-only selection flags every cell in the row No. Compares row and column indices directly

Which approach should you use?

Use Approach A when the goal is a more visible cursor, meaning a thicker or colored version of the default focus highlight that tracks the keyboard. It needs one extension function and no state, and the table's own repaint logic keeps it correct.

Use Approach B only when you need an anchor, such as marking the cell an operator clicked as the reference point while they navigate to compare values. It adds state, and state needs explicit repaint and explicit clearing. Both approaches can run together. Approach B's final configureCell already combines the anchor border with the selected-cell background.

How do I make the border follow the arrow keys?

  1. Check the selection behavior first. If selected is true for every cell in a row, row selection is on without column selection, and the border will outline the entire row. Enable cell-level selection in the table's selection properties if you want a single-cell outline.
  2. Open the Power Table's Component Scripting, go to Extension Functions, and enable configureCell.
  3. Replace the body with the logic below. Keep the generated function signature; only the arguments selected and rowView are used here.
  4. Save, switch the Designer to Preview Mode, click a cell, and press the arrow keys and Tab.
#def configureCell(self, [...], colView):
	if selected:
		from javax.swing import BorderFactory
		borderColor = system.gui.color('red')
		border = BorderFactory.createMatteBorder(4, 4, 4, 4, borderColor)
		return {'background': self.selectionBackground, 'border': border}
	elif rowView % 2 == 0:
		return {'background': 'white'}
	else:
		return {'background': 'lightgrey'}

Notes on the mechanism:

  • BorderFactory.createMatteBorder(top, left, bottom, right, color) takes per-side thickness in pixels. 4, 4, 4, 4 gives a uniform 4 px frame. A matte border draws inside the cell bounds, so a thick border reduces the space left for text. Drop to 2 px if values start clipping in narrow columns.
  • Returning self.selectionBackground keeps the table's configured selection color. If you return a dict without a background for a selected cell, the cell can lose its selection shading.
  • The striping uses rowView, the view index, so alternating colors stay alternating after the operator sorts the table.
  • Importing BorderFactory inside the branch runs on every render of a selected cell. That cost is negligible, but you can move the import and border construction to module level in a project script if the table is large.

How do I keep the border on the clicked cell while arrowing?

  1. Add two custom properties to the Power Table: clickedRow and clickedColumn, both Integer. Set both to -1 so no cell matches before the first click.
  2. Enable the onMouseClick extension function, not the mouseClicked event handler. The inner table consumes the click. The component-level mouse event handler sits on the outer wrapper and does not fire for clicks inside the table's cells. The extension function receives the clicked cell's indices directly.
#def onMouseClick(self, [...], event):
	self.clickedRow = rowIndex
	self.clickedColumn = colIndex
	self.repaint()  # forces configureCell to re-run for the whole table
  1. Keep the self.repaint() call. Writing a custom property does not invalidate any cell, so without it the old anchor keeps its border and the new one does not get one until something else triggers a repaint.
  2. Clear the anchor when the selection clears. In the Power Table's propertyChange event handler:
if event.propertyName in ['selectedRow', 'selectedColumn'] and event.newValue == -1:
	event.source.clickedRow = -1
	event.source.clickedColumn = -1
	event.source.repaint()  # trigger configureCell
  1. Update configureCell to compare each cell against the stored anchor before checking selected:
#def configureCell(self, [...], colView):
	if rowIndex == self.clickedRow and colIndex == self.clickedColumn:
		from javax.swing import BorderFactory
		borderColor = system.gui.color('red')
		border = BorderFactory.createMatteBorder(4, 4, 4, 4, borderColor)
		if selected:
			return {'background': self.selectionBackground, 'border': border}
		else:
			return {'border': border}
	elif selected:
		return {'background': self.selectionBackground}
	elif rowView % 2 == 0:
		return {'background': 'white'}
	else:
		return {'background': 'lightgrey'}

Index discipline matters here. onMouseClick stores rowIndex and colIndex, and configureCell compares against rowIndex and colIndex, so both sides use the same index space. After a sort, the anchor stays on the same data row, even though that row now appears at a different screen position. If you mix rowIndex on one side with rowView on the other, the border lands on the wrong cell as soon as the operator sorts or reorders columns.

Why is the border missing, stuck, or on the wrong cells?

Symptom Cause Correction
Custom border appears only while editing a cell Styling applied to the cell editor, which only exists in edit mode Return a border from configureCell keyed on selected
Border outlines the whole row when arrowing Row-only selection; selected is true for every cell in the row Enable cell-level selection, or use Approach B's row and column comparison
Click does nothing; custom properties never change Logic placed in the mouseClicked event handler, which does not see clicks on the inner table Move it to the onMouseClick extension function
Anchor border lags one click behind or stays on the old cell No repaint after writing clickedRow/clickedColumn Call self.repaint() in onMouseClick
Anchor border persists after selection is cleared No reset logic Reset both properties to -1 in propertyChange and repaint
Anchor jumps to a different row after sorting Model index stored, view index compared (or the reverse) Use rowIndex/colIndex on both sides
Selected cell loses its highlight color Returned dict omits background for selected cells Include 'background': self.selectionBackground
Cell text clipped inside the border Matte border thickness consumes cell insets Reduce thickness or widen the column

How do I verify the border behavior?

  1. In Preview Mode (or a launched client), click any cell. For Approach A, that cell shows the red 4 px border and the selection background. For Approach B, it shows the same border and background.
  2. Press the right arrow, down arrow, and Tab several times. For Approach A, the border moves with each key press and the previous cell returns to its stripe color with no border. For Approach B, the clicked cell keeps its red border without the selection background, and the currently selected cell shows the selection background.
  3. Click a different cell (Approach B). The border moves to the new cell immediately. If it moves only after a later key press, the repaint() call is missing.
  4. Sort by a column header. The striping stays alternating because it uses rowView. The Approach B anchor follows its data row because it uses rowIndex.
  5. Clear the selection, for example by writing -1 to selectedRow from a test button. With Approach B, confirm that clickedRow and clickedColumn read -1 in the Property Editor and that no cell keeps the red border.

FAQ

How do I change the Ignition Power Table focus border color when using arrow keys?

Enable the configureCell extension function. When selected is true, return {'background': self.selectionBackground, 'border': border}, where border comes from BorderFactory.createMatteBorder(4, 4, 4, 4, system.gui.color('red')). The selected flag follows Tab and arrow navigation.

How do I keep a highlight on the clicked Power Table cell while arrowing to other cells?

Add Integer custom properties clickedRow and clickedColumn (default -1). Set them from the onMouseClick extension function, then call self.repaint(). In configureCell, return the border when rowIndex and colIndex match the stored values.

Why doesn't the Power Table mouseClicked event handler fire on cell clicks?

The click is consumed by the inner table, and the component-level event handler sits on the outer wrapper. Use the onMouseClick extension function, which receives the clicked row and column indices.

How do I force configureCell to re-run after changing a custom property?

Call repaint() on the Power Table: self.repaint() inside extension functions, or event.source.repaint() in event handlers. Changing a custom property does not invalidate any cell by itself.

How do I stop the selected-cell border from outlining the entire row?

The table is in row-only selection, so selected is true for every cell in the row. Enable cell-level selection in the table's selection properties, or compare explicit row and column indices stored in custom properties instead of relying on selected.

Back to blog