TableView.setEditable(true) Is Required

Lee CarverLee Carver
8 min read

I’m hoping this post will solve a late-night dilemma for some engineer that is trying to bring up their first JavaFX TableView control that uses checkboxes.

In the end, getting the checkboxes of a CheckBoxTreeTableItem to respond to user clicks in a TableView requires calling the setEditable(true) method on the TableView Instance.

  TableView tableView = new TableView();
  tableView.setEditable(true);

I didn’t find this described explicitly in any of the online JavaFX documentation or the highly repetitive blog pages on the use of CheckBoxTreeTableItem. Fortunately, one of the examples includes this call as a seemingly stray bit of code. In fact, it turned out to be essential.

Summary

The Depan application relies heavily on a data model that represents a list of graph nodes. Each node list is a subset of the nodes from a particular graph. Being able to manipulate lots of node lists is one of Depan’s strengths. The ability to manage and aggregate large sets of node lists provides considerable analytical power.

The development of the node list UI followed a simple evolutionary path. The initial node list viewer borrowed some code from the project viewer. That code was based on TreeView. The addition of checkboxes transformed the original TreeCell elements into CheckBoxTreeCell elements. The final development step was placing the TreeView into a TableView. In this final step, the CheckBoxTreeCell transforms into a CheckBoxTreeTableCell.

After some refactoring work, the new UI was rendering beautifully. But the checkboxes were unresponsive. Only the tree expand and collapse arrows worked. The checkbox and its label were rendered but lacked the intended user interaction.

TableView checkboxes with editable mode in the initial false state.

Flailing around yielded results. One blog on using the CheckBoxTreeTableCell had a call to TreeView.setEditable(true) in the control flow leading to the table’s rendering. Although the line is not well documented, this method to activate editable mode on the TableView is essential for CheckBoxTreeTableCell to operate.

TableView checkboxes with editable mode set to true.

The Story Begins

One of the essential tasks for system analysis is the partitioning of large node lists into smaller lists. A common goal for refactoring analysis is to find a collection of node lists that cover and partition a larger set of nodes. The definition of sublists from a large group of nodes often involves manual steps, even with effective automation.

The number of nodes in a complete system graph can be very large. UI presentations are lengthy. The content can be pages and pages lengthy, even with trees to cluster and group nodes that have membership relationships.

Maintaining the intended selection on a large number of scattered nodes can be error-prone. Even with multi-section multi-selection UIs, it can be hard to grow a large selection. A single mistake (not holding the shift key) can instantly undo much careful work. For this reason, the user's selection is maintained as a checkbox, not as the cursor selection state.

The UI With TreeView

The initial node list viewer borrowed some code from the project viewer. The project viewer was based on an internal TreeView instance. The node list viewer follows a similar structure.

For TreeView instances, the rendering of visible items is handled by TreeCell instances that are managed by the TreeView. With the basic TreeCell class, the updateItem() method needs to be overridden. This method sets the text and graphic that are rendered in the cell. It also allows the application to add context menus to cells. Starting with TreeCell as the base class works fine, but there are no checkboxes.

To add checkboxes, the cells need to extend CheckBoxTreeCell. This change in the base type meant releasing some control over the rendering. The updateItem() method from CheckBoxTreeCell handles the basic rendering of the data. Part of this is setting up the checkbox as the graphic for the cell, and the item’s label as the text.

Supporting this change in behavior required a new StringConverter type to render the tree item’s label. The assignments of text and graph for the cell needed to be removed, since this behavior was now supplied by CheckBoxTreeCell. In early revisions, setting the graphic to null was effectively erasing the checkbox. The cell rendering can’t be completely delegated to the CheckBoxTreeCell class since the updateItem() method also adds context menus.

Trees Into Table

Trees with checkboxes are great. However, the context is limited to the tree item’s label. With a TableView, additional columns can provide supplementary information. There is also a column header with options for useful context menu entries (e.g. sort-by capabilities). This transition was more substantial than migrating to tree items with checkboxes.

Both the container and the cell definitions changed their base types. The TreeView container becomes a TableView container. The connection from the TableView to the TableCell is managed by a new entity, of type TreeTableColumn. The CheckBoxTreeCell class transitions to extend the CheckBoxTreeTableCell class.

Where the migration for CheckBoxTreeCell required little more than a new StringConverter implementation, the migration to CheckBoxTreeTableCell required more pieces:

  • The CheckBoxTreeCell adds a selection state factory for the cell, as a Callback<Integer, ObservableValue>.

  • The cell factory, and any injected values, migrate from TreeView into the TreeTableColumn.

  • The TreeTableColumn needs some additional configuration, primarily a value factory for cells.

Unresponsive CheckBoxes

With these changes, the table view for node lists renders nicely. The label shows, the checkbox shows, and the triangle for tree expansion opens and closes.

But there is no way for the user to check the checkbox.

The first inclination is to assume some error in the selection state factory. Although this is easy to get wrong, that is not the source of the problem.

To enable user interaction with the checkboxes, the TableView needs to be in editable mode. This requires calling TableView.edit(true) during the table view’s initialization stages. If you know where to look, it is that simple.

RTFM

The documentation for this interaction is subtle, at best. An after-the-fact review from Google search shows a few tidbits of information. The first one is vague, the second one feels misleading. The description of the TableView editable behavior is precise but it remains challenging to understand.

TreeView

Firstly, cell editing most commonly requires a different user interface than when a cell is not being edited. This is the responsibility of the Cell implementation being used. For TreeView, this is the responsibility of the cell factory. It is your choice whether the cell is permanently in an editing state (e.g. this is common for CheckBox cells), or to switch to a different UI when editing begins (e.g. when a double-click is received on a cell).

This side comment about editing mode for a TreeView is repeated in the TableView JavaDoc. It certainly does not seem essential.

BooleanProperty - editable Specifies whether this TreeView is editable - only if the TreeView and the TreeCells within it are both editable will a TreeCell be able to go into their editing state.

An interesting note about the behavior, but not very constructive. Apparently, TreeView and TreeCell components are normally initialized as editable. Everything behaved as expected without changes to this property.

CheckBoxTreeTableCell

Note that the CheckBoxTreeCell renders the CheckBox 'live', meaning that the CheckBox is always interactive and can be directly toggled by the user. This means that it is not necessary that the cell enter its editing state (usually by the user double-clicking on the cell). A side-effect of this is that the usual editing callbacks (such as on edit commit) will not be called. If you want to be notified of changes, it is recommended to directly observe the boolean properties that are manipulated by the CheckBox.

This paragraph provides a lot of details about the programmatic behavior of the checkbox. With all these details on the accessing the checkbox state, it is a surprise that there are so few details about the user interactions.

TableView

Firstly, cell editing most commonly requires a different user interface than when a cell is not being edited. This is the responsibility of the Cell implementation being used. For TableView, it is highly recommended that editing be per-TableColumn, rather than per row, as more often than not you want users to edit each column value differently, and this approach allows for editors specific to each column. It is your choice whether the cell is permanently in an editing state (e.g. this is common for CheckBox cells), or to switch to a different UI when editing begins (e.g. when a double-click is received on a cell).

This repeats the notes on cell editing notes from ListView, but the consequences are unclear. Checkboxes work fine in ListView without explicit manipulation of the editable state.

BooleanProperty editable

Specifies whether this TableView is editable - only if the TableView, the TableColumn (if applicable) and the TableCells within it are both editable will a TableCell be able to go into their editing state.

Given the nearly 60 methods that TableView implements, slipping past the consequences of one method's interactions with the nested structures seems a very easy omission.

Apparently, all the other containing controls were initially created in the editable mode. Only the TableView is initially created with the editable mode turned off. All the other components in this adventure, the various CheckBox*Cell classes, the TreeTableColumn class, and the ListView class are all configured to be initially editable. Once this peculiar behavior is corrected for TableView, the checkboxes in the table view have the desired behavior.

0
Subscribe to my newsletter

Read articles from Lee Carver directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Lee Carver
Lee Carver

Experienced Software Engineer. User interfaces, distributed services, software tools. Software development and operation at scale in multiple application domains.