I'm looking for a way to resize a TableColumn in a TableView so that all of the content is visible in each cell (i.e. no truncation).
I noticed that double clicking on the column divider's does auto fit the column to the contents of its cells. Is there a way to trigger this programmatically?
Digging through the javafx source, I found that the actual method called when you click TableView columns divider is
/*
* FIXME: Naive implementation ahead
* Attempts to resize column based on the pref width of all items contained
* in this column. This can be potentially very expensive if the number of
* rows is large.
*/
@Override protected void resizeColumnToFitContent(TableColumn<T, ?> tc, int maxRows) {
if (!tc.isResizable()) return;
// final TableColumn<T, ?> col = tc;
List<?> items = itemsProperty().get();
if (items == null || items.isEmpty()) return;
Callback/*<TableColumn<T, ?>, TableCell<T,?>>*/ cellFactory = tc.getCellFactory();
if (cellFactory == null) return;
TableCell<T,?> cell = (TableCell<T, ?>) cellFactory.call(tc);
if (cell == null) return;
// set this property to tell the TableCell we want to know its actual
// preferred width, not the width of the associated TableColumnBase
cell.getProperties().put(TableCellSkin.DEFER_TO_PARENT_PREF_WIDTH, Boolean.TRUE);
// determine cell padding
double padding = 10;
Node n = cell.getSkin() == null ? null : cell.getSkin().getNode();
if (n instanceof Region) {
Region r = (Region) n;
padding = r.snappedLeftInset() + r.snappedRightInset();
}
int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows);
double maxWidth = 0;
for (int row = 0; row < rows; row++) {
cell.updateTableColumn(tc);
cell.updateTableView(tableView);
cell.updateIndex(row);
if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) {
getChildren().add(cell);
cell.applyCss();
maxWidth = Math.max(maxWidth, cell.prefWidth(-1));
getChildren().remove(cell);
}
}
// dispose of the cell to prevent it retaining listeners (see RT-31015)
cell.updateIndex(-1);
// RT-36855 - take into account the column header text / graphic widths.
// Magic 10 is to allow for sort arrow to appear without text truncation.
TableColumnHeader header = getTableHeaderRow().getColumnHeaderFor(tc);
double headerTextWidth = Utils.computeTextWidth(header.label.getFont(), tc.getText(), -1);
Node graphic = header.label.getGraphic();
double headerGraphicWidth = graphic == null ? 0 : graphic.prefWidth(-1) + header.label.getGraphicTextGap();
double headerWidth = headerTextWidth + headerGraphicWidth + 10 + header.snappedLeftInset() + header.snappedRightInset();
maxWidth = Math.max(maxWidth, headerWidth);
// RT-23486
maxWidth += padding;
if(tableView.getColumnResizePolicy() == TableView.CONSTRAINED_RESIZE_POLICY) {
maxWidth = Math.max(maxWidth, tc.getWidth());
}
tc.impl_setWidth(maxWidth);
}
It's declared in
com.sun.javafx.scene.control.skin.TableViewSkinBase
method signature
protected abstract void resizeColumnToFitContent(TC tc, int maxRows)
Since it's protected, You cannot call it from e.g. tableView.getSkin(), but You can always extend the TableViewSkin overriding only resizeColumnToFitContent method and make it public.
As @Tomasz suggestion, I resolve by reflection:
import com.sun.javafx.scene.control.skin.TableViewSkin;
import javafx.scene.control.Skin;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class GUIUtils {
private static Method columnToFitMethod;
static {
try {
columnToFitMethod = TableViewSkin.class.getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
columnToFitMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void autoFitTable(TableView tableView) {
tableView.getItems().addListener(new ListChangeListener<Object>() {
@Override
public void onChanged(Change<?> c) {
for (Object column : tableView.getColumns()) {
try {
columnToFitMethod.invoke(tableView.getSkin(), column, -1);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
});
}
}
You can use tableView.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
You can also try switching between the two policies TableView.CONSTRAINED_RESIZE_POLICY
and TableView.UNCONSTRAINED_RESIZE_POLICY in case TableView.UNCONSTRAINED_RESIZE_POLICY alone doesn't fit your need.
Here's a useful link.
The current versions of JavaFX (e.g. 15-ea+1) resize table columns, if the prefWidth was never set (or is set to 80.0F, see TableColumnHeader enter link description here).