Resize JavaFX TableColumn to fit cell contents

I am looking for a way to resize a TableColumn in a TableView so that all content is visible in each cell (i.e. without truncation).

I noticed that double-clicking on the column separator automatically sets the column to the contents of its cells. Is there a way to initiate this programmatically?

+8
javafx tableview
source share
3 answers

Digging through the javafx source, I found that the actual method called when the TableView column separator is clicked,

/* * 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); } 

He is declared in

 com.sun.javafx.scene.control.skin.TableViewSkinBase 

method signature

 protected abstract void resizeColumnToFitContent(TC tc, int maxRows) 

Since it is protected, you cannot call it, for example. tableView.getSkin (), but you can always extend the TableViewSkin override only for the resizeColumnToFitContent parameter and make it public.

+8
source share

As @Tomasz's suggestion, I decide 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(); } } } }); } } 
+8
source share

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 if TableView.UNCONSTRAINED_RESIZE_POLICY is not suitable for you.

Here is a useful link.

0
source share

All Articles