@UITableColumn(expandRatio = 0.25F)
@UILabel(position = 10, label = "Name")
public String getName() {
return contact.getName();
}
UI Components
Tables
The basics of table creation were already mentioned in the chapter binding of a table. This section details the definition of table structure, the ContainerPmo<T>
, the SimpleItemSupplier<PMO, MO>
and the TableFooter
.
Definition of the table structure with a row PMO
The structure of the table is defined in a PMO class, whose instances represent rows in the table. Thus, these classes are called "row PMOs".
Row PMO classes are standard PMOs, which do not represent sections and thus shouldn’t be annotated with @UISection
.
Here, the annotation UI element defines the column in the table. A column showing the name of a contact, for instance, can be setup as follows:
@UITableColumn
By design all properties of a PMO are presented in the table. With the annotation @UITableColumn
the column width can be set via the properties width
(in pixels) or expandRatio
.
If both properties are set, width has a higher priority than expandRatio .
|
ContainerPmo
A ContainerPmo
is a class that implements the interface ContainerPmo<T>
and is annotated with @UISection
. The main function of a ContainerPmo
is providing the PMOs to be rendered in the table.
The method List<T> getItems()
is called by the TableBinding
to add the elements to the table. It should always return the same instance of List<T>
. The SimpleItemSupplier
offers support for that.
By overwriting the default
method int getPageLength()
the number of lines shown can be controlled. By default 15 lines are shown. It is a common tactic to allow tables to 'grow' to a certain size and then limit the number of lines while also enabling the scrolling for the table. If 0
is returned the table grows dynamically with the content, without limit.
@Override
public int getPageLength() {
return Math.min(ContainerPmo.DEFAULT_PAGE_LENGTH, getItems().size());
}
The column structure of the table is determined by the class row PMO, which is returned by the method Class<? extends T> getItemPmoClass
. In the default implementation the class of the generic parameter T
is returned. For tables that should have the same rows but different columns, this method can be overwritten to use a subclass of T
.
If the table should support the adding of items, the default
method Optional<ButtonPmo> getAddItemButtonPmo
must be overwritten. How a ButtonPmo
is created is described in the chapter ButtonPmo.
SimpleItemSupplier
The SimpleItemSupplier<PMO, MO>
is used to only create a new List<PMO>
, if a row was changed.
The instancing is done with two parameters
-
modelObjectSupplier
of typeSupplier<List<MO>>
is called to access a list of the model objects -
mo2pmoMapping
of typeFunction<MO, PMO>
is called for the creation of a PMO for a model objects
public ContactTablePmo(List<Contact> contacts, Consumer<Contact> editAction, Consumer<Contact> deleteAction) {
items = new SimpleItemSupplier<>(() -> contacts,
p -> new ContactRowPmo(p, editAction, deleteAction));
}
SimpleTablePmo
Most commonly, the row PMO objects are converted from a list of model objects. In this case, the abstract class org.linkki.core.ui.table.SimpleTablePmo<MO, ROW>
may be extended. This abstract class defines a constructor that requires the list or the supplier for the list of model objects. Additionally the method createRow(MO)
needs to be implemented. This method simply get a model object and creates a row PMO for it. The same example as in the previous section may look like this:
@UISection
public class SimpleContactTablePmo extends SimpleTablePmo<Contact, ContactRowPmo> {
private final Consumer<Contact> editAction;
private final Consumer<Contact> deleteAction;
public SimpleContactTablePmo(List<Contact> Contacts, Consumer<Contact> editAction, Consumer<Contact> deleteAction) {
super(Contacts);
this.editAction = editAction;
this.deleteAction = deleteAction;
}
@Override
protected ContactRowPmo createRow(Contact Contact) {
return new ContactRowPmo(Contact, editAction, deleteAction);
}
}
TableFooterPmo
By overwriting the default
method getFooterPmo()
a footer row is generated. The implementation of the interface TableFooterPmo
must implement the method getFooterText(String column)
.
The parameter column
is the ID of the column for which the text should be displayed. An example for this would be a sum of all items from a column.
private final TableFooterPmo footer;
public CarTablePmo(List<Car> carStorage, Handler addCarAction) {
this.addCarAction = addCarAction;
this.items = new SimpleItemSupplier<>(() -> carStorage, CarRowPmo::new);
this.footer = c -> calculateTotalRetention(c, carStorage);
}
@Override
public Optional<TableFooterPmo> getFooterPmo() {
return Optional.of(footer);
}
private String calculateTotalRetention(String column, List<Car> cars) {
switch (column) {
case Car.PROPERTY_RETENTION:
return String.format("%,.2f", cars.stream()
.mapToDouble(Car::getRetention)
.sum());
case Car.PROPERTY_CAR_TYPE:
return "Total Retention:";
default:
return "";
}
}
ButtonPmo
Currently the ContainerPmo
provides a method getAddItemButtonPmo()
, by which a plus button can be added besides the name of the table. This part ofthe API is being refactored in the issue LIN-128.