Read-only table

1. Creating a read-only table

In the Amalgama Platform, table creation happens in two stages: first you configure the builder, then you call the create() method to instantiate the table.

The builder is returned by the static method Tables.readonly().

Read-only tables are constructed using the Table class.

Here is how we can create a simple table displaying cars with the required configuration:

List<Car> cars = new ArrayList<>();
Table<Car> table = Tables
  .readonly(cars) // required! List objects shown in the table
  .parent(parent) // required! Specifies the parent container where the table will be placed
  .create();

Here is what the optional configuration chain looks like. All other methods are optional and can be specified in any order.

  • checkbox() - adds a checkbox column for row selection. The column is placed in the first position

Table<Car> table = Tables
  .readonly(cars)
  .parent(parent)
  .checkbox() // rows can now be selected via checkboxes
  .create();
Checkbox column
  • rowHeader() - adds a special-purpose column positioned first. This column allows users to select an entire row with a single click. It becomes essential when every other column in the table is editable — without a dedicated selection column, clicking any cell would trigger editing, making row selection impossible.

Table<Car> table = Tables
  .readonly(cars)
  .parent(parent)
  .rowHeader()
  .create();
Row header column

If both checkbox() and rowHeader() are specified, rowHeader becomes the first column and checkbox becomes the second.

  • style(int style) - sets additional SWT styles for the table. You can pass one or more constants from the SWT class, combining them with the bitwise OR operator |. These styles are then passed to the parent TableViewer, where they are interpreted and determine exactly how the table will be rendered

This table creation code snippet is part of the example GitHub project. You can find the Car and Person class definitions in the example project source code at GitHub. See also the sample data population code.

2. Table class API overview

2.1. Selection handling

int selectedIndex = table.getFirstSelectedRowIndex();
if (selectedIndex != -1) {
    Car selectedCar = table.getItem(selectedIndex);
}
table.setSelectedRowIndex(3);  // selects the fourth row
table.setSelectionChangedConsumer(event -> {
    IStructuredSelection selection = (IStructuredSelection) event.getSelection();
    Car selectedCar = (Car) selection.getFirstElement();
    System.out.println("Selected: " + selectedCar);
});

2.2. Checkbox functionality

2.3. Double-Click handling

2.4. Context menu

table.addContextMenuHandler(args -> {
    Menu menu = args.menu();
    Car car = args.item();
    String columnName = args.columnName();

    MenuUtils.addCommandMenuItem(menu, "Show " + columnName, () -> {
        	MessageBox messageBox = new MessageBox(parent.getShell(), 1 << 1);
			messageBox.setMessage(columnName);
			messageBox.open();
    });
});
Context menu item
table.showDefaultContextMenu(false);
Context menu item

2.5. Sorting

table.setSortingAllowed(true);
Sorting

2.6. Filtering

  • setQuickFilterAllowed(boolean isQuickFilterAllowed) - allows users to filter the table by simply typing letters or digits, without needing to open a context menu. When a key is pressed, a small popup dialog appears, and as the user continues typing, the table dynamically shows only those rows where any visible column contains the entered substring (case-insensitive), false by default

table.setQuickFilterAllowed(true);
Quick filter

3. Adding columns

Table columns are created by calling the column() method.

3.1. Column with format

The format() method accepts a function that converts objects to strings, defaulting to toString(). Sometimes data can be null, you can use nullValueText() to specify what to display for empty values, empty string by default

table
  .column(Car::owner)
  .name("Owner")
  .width(100)
  .nullValueText("— no name —")        // text for null values
  .format(owner -> owner.getName())    // format depends on the value (owner) only
Format owner name column

Different format() signatures:

.format("Owner")        // all cells display the same static text string(Owner)
.format((car, owner) -> car.number() + " " + owner.getName()) // format depends on row(car) and value(owner)

3.2. Column with color

The backgroundColor() method controls the background color displayed in each cell of the column

table
  .column(Car::color)
  .name("Color")
  .width(100)
  .format("")                              // hide text
  .backgroundColor(car -> car.color()); // color depends on the row (car)
Decorated car color column

Different backgroundColor() signature:

.backgroundColor(Color.RED)              // all cells show the same color

3.3. Column with font and font color

The font() and fontColor() methods controls the font and font color displayed in each cell of the column

Font font1 = new Font(parent.getDisplay(), "Arial", 7, 0);
Font font2 = new Font(parent.getDisplay(), "Times New Roman", 14, 2);
table
  .column(Car::owner)
  .name("Owner")
  .width(100)
  .format(Person::getName)
  .font((car, owner) -> owner.getAge() > 50 ? font1 : font2)         // font depends on row(car) and value(owner)
  .fontColor(car -> car.number() % 2 == 0 ? Color.RED : Color.BLUE); // font color depends on row(car)
Owner column with font settings

Different font() signatures:

.font(font1)                                               // all cells show the same font
.font(car -> {})                                           // font depends on row(car)

Different fontColor() signatures:

.fontColor(Color.BLUE)                                     // all cells show the same font color
.fontColor((car, owner) -> {})                             // font color depends on row(car) and value(owner)

3.4. Column with histogram

The pseudoHistogramColor() method adds a histogram bars in a column to improve the visualization of numerical data.

table
  .column(car -> car.owner().getAge())
  .name("Owner age")
  .width(100)
  .pseudoHistogramColor((car, age) -> age % 2 == 0 ? Color.GREEN : Color.YELLOW); // assign pseudohistogram color with function defining color depending on number value
Owner’s age column with histogram

Different pseudoHistogramColor() signatures:

.pseudoHistogramColor(Color.YELLOW)  // all cells show the same color
.pseudoHistogramColor(car -> {})     // pseudoHistogram color depends on the value (car)

3.5. Column with icon

Enhance cells by adding dynamic icons using the Image class. You can make the icon conditional based on the cell’s value.

private final Image saveImage = new Image( Display.getDefault(), getClass().getClassLoader().getResourceAsStream( "icons/save_edit.png" ) );
private final Image homeImage = new Image( Display.getDefault(), getClass().getClassLoader().getResourceAsStream( "icons/home.png" ) );
//	...

table
  .column(Car::number)
  .name("Number")
  .width(100)
  .icon((car, number) -> number > 100 ? homeImage : saveImage);  // assign cell icon depending on car's number
Car number column with icons

Different icon() signatures:

.icon(homeImage)                                               // all cells show the same icon
.icon(car -> {})                                               // icon depends on the value (car)

3.6. Column with header tooltip

Sometimes require additional explanation. Use tooltip() to add a hint that appears on hover

table
	.column(Car::owner)
	.name("Owner")
	.width(150)
	.format(Person::getName)
	.tooltip("Additional information about the owner"); // tooltip for column header
Tooltip and nullValueText

3.7. Column with header icon

Add an icon to the column header using headerIcon(). This is useful for visual branding or indicating column type

private final Image homeImage = new Image( Display.getDefault(), getClass().getClassLoader().getResourceAsStream( "icons/home.png" ) );
//	...
table
	.column(Car::owner)
	.name("Owner")
	.width(150)
	.format(Person::getName)
	.headerIcon(homeImage);
Header icon

3.8. Moving columns (user reordering)

By default, columns have a fixed position. Set moveable(true) to allow users to reorder columns by dragging headers, false by default.

table
	.column(Car::owner)
	.name("First column")
	.width(100)
	.format(Person::getName)
	.moveable(true);

table
	.column(Car::owner)
	.name("Second column")
	.width(100)
	.format(Person::getName)
	.moveable(true);
Moveable column