TableViewwe configure the
columnResizePolicy. For this exercise we will use a list of hotel rooms. This is our initial table with the
useAsMaxchoice for the
contentWidthresize type. This would effectively result in a hard-coded, unresizable column, based on the required content width plus any configured padding. This would be a good policy for the # column:
TableView, the Number column will gradually expand to keep up with our 25% width requirement, while the Type column gets the remaining extra space.
TableViewitself is resized.
TableViewis resized to be very small. The the Number column would not have space to show all of its content, so we guard against that by specifying that it should never grow below the space it needs to show its content, plus some padding, for good measure:
requestResizefunction after you have manipulated the items:
remainingWidth()for one or more column. In that case, these columns will divide the extra space between them.
SmartResizePolicy makes sure that the column with the biggest reduction potential will give away its space first. The reduction potential is the difference between the current width of the column and its defined minimum width.
ListViewis rather boring (because it calls
toString()and renders it as text) you can modify it so that every cell is a custom
Nodeof your choosing. By calling
cellCache(), TornadoFX provides a convenient way to override what kind of
Nodeis returned for each item in your list (Figure 13.6).
cellFormatfunction lets you configure the
graphicproperty of the cell whenever it comes into view on the screen. The cells themselves are reused, but whenever the
ListViewasks the cell to update its content, the
cellFormatfunction is called. In our example we only assign to
graphic, but if you just want to change the string representation you should assign it to
text. It is completely legitimate to assign it to both
graphic. The values will automatically be cleared by the
cellFormatfunction when a certain list cell is not showing an active item.
graphicproperty every time the list cell is asked to update can be expensive. It might be fine for many use cases, but for heavy node graphs, or node graphs where you utilize binding towards the UI components inside the cell, you should cache the resulting node so the Node graph will only be created once per node. This is done using the
cachewrapper in the above example.
assignIfNullhelper, which will assign a value to any given property if the property doesn't already contain a value. This will make sure that you avoid creating new nodes if
updateItemis called on a cell that already has a graphic property assigned.
ListCellFragmentis a special fragment which can help you manage
ListViewcells. It extends
Fragment, and includes some extra
ListViewspecific fields and helpers. You never instantiate these fragments manually, instead you instruct the
ListViewto create them as needed. There is a one-to-one correlation between
ListCellFragmentinstances. Only one
ListCellFragmentinstance will over its lifecycle be used to represent different items.
ListCell, essentially the way you would do in vanilla JavaFX. The
updateItemfunction will be called when the
ListCellshould represent a new item, no item, or just an update to the same item. When you use a
ListCellFragment, you do not need to implement something akin to
updateItem, but the
itemPropertyinside it will update to represent the new item automatically. You can listen to changes to the
itemProperty, or better yet, bind it directly to a
ViewModel. That way your UI can bind directly to the
ViewModeland no longer need to care about changes to the underlying item.
cellFormatexample using a
ListCellFragment. We need a
ViewModelwhich we will call
PersonModel(Please see the
Editing Models and Validationchapter for a full explanation of the
ViewModel) For now, just imagine that the
ViewModelacts as a proxy for an underlying
Person, and that the
Personcan be changed while the observable values in the
ViewModelremain the same. When we have created our
PersonCellFragment, we need to configure the
ListViewto use it:
birthdayproperties are bound directly to the labels inside the fields. The age string in the last label needs to be constructed using a
stringBindingto make sure it updates when the item changes.
cellFormatexample, this approach makes it possible to leverage everything the Fragment class has to offer. It also forces you to define the cell node graph outside of the builder hierarchy, which improves refactoring possibilities and enables code reuse.
ListCellFragmentalso have some other helper properties. They include the
cellPropertywhich will update whenever the underlying cell changes and the
editingProperty, which will tell you if this the underlying list cell is in editing mode. There are also editing helper functions called
ListCellFragmentmakes it trivial to utilize the existing editing capabilites of the
ListView. A complete example can be seen in the TodoMVC demo application.