Desktop Java

JavaFX Tip 22: Autosize (Tree) Table Columns

One of the first things mentioned as a “missing feature” in the JavaFX “Missing Features Survey” was the ability to auto-resize columns in tables / tree tables. It is correct that there is no public API for it, but when you pay close attention then you will notice that there must be code for doing this somewhere inside JavaFX, because the user can auto-resize a column by double clicking on the divider line between the column and the next column to the right.

But like most people I felt that this was not good enough for my code. I wanted an API for FlexGanttFX that would allow the user to auto resize one or all columns inside the Gantt charts. So I searched for the code that was hidden somewhere in the tree table  or tree table skin (can’t actually remember where) and reused it with some minor modifications in my classes.

The following is the result of this work. It targets the TreeTableView and not the TableView, but making it work for the standard table is straight-forward. Simply replace all TreeTableColumn occurrences with TableColumn. Please notice that resizing all rows can have a serious performance impact, so you might have to limit the number of rows that will be considered for the calculations via the maxRows parameter.

/**
	 * This method will resize all columns in the tree table view to ensure that
	 * the content of all cells will be completely visible. Note: this is a very
	 * expensive operation and should only be used when the number of rows is
	 * small.
	 *
	 * @see #resizeColumn(TreeTableColumn, int)
	 */
	public final void resizeColumns() {
		resizeColumns(-1);
	}

	/**
	 * This method will resize all columns in the tree table view to ensure that
	 * the content of all cells will be completely visible. Note: this is a very
	 * expensive operation and should only be used with a small number of rows.
	 *
	 * @param maxRows
	 *            the maximum number of rows that will be considered for the
	 *            width calculations
	 *
	 * @see #resizeColumn(TreeTableColumn, int)
	 */
	public final void resizeColumns(int maxRows) {
		for (TreeTableColumn<R, ?> column : getTreeTable().getColumns()) {
			resizeColumn(column, maxRows);
		}
	}

	/**
	 * This method will resize the given column in the tree table view to ensure
	 * that the content of the column cells will be completely visible. Note:
	 * this is a very expensive operation and should only be used when the
	 * number of rows is small.
	 *
	 * @see #resizeColumn(TreeTableColumn, int)
	 */
	public final void resizeColumn(TreeTableColumn<R, ?> column) {
		resizeColumn(column, -1);
	}

	/**
	 * This method will resize the given column in the tree table view to ensure
	 * that the content of the column cells will be completely visible. Note:
	 * this is a very expensive operation and should only be used when the
	 * number of rows is small.
	 *
	 * @see #resizeColumn(TreeTableColumn, int)
	 */
	public final void resizeColumn(TreeTableColumn<R, ?> tc, int maxRows) {
		final TreeTableColumn col = tc;

		List<?> items = getItems();
		if (items == null || items.isEmpty()) {
			return;
		}

		Callback cellFactory = tc.getCellFactory();
		if (cellFactory == null) {
			return;
		}

		TreeTableCell<R, ?> cell = (TreeTableCell<R, ?>) 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("deferToParentPrefWidth", Boolean.TRUE); //$NON-NLS-1$

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

		TreeTableRow<R> treeTableRow = new TreeTableRow<>();
		treeTableRow.updateTreeTableView(treeTableView);

		int rows = maxRows == -1 ? items.size()
				: Math.min(items.size(), maxRows);
		double maxWidth = 0;
		for (int row = 0; row < rows; row++) {
			treeTableRow.updateIndex(row);
			treeTableRow.updateTreeItem(treeTableView.getTreeItem(row));

			cell.updateTreeTableColumn(col);
			cell.updateTreeTableView(treeTableView);
			cell.updateTreeTableRow(treeTableRow);
			cell.updateIndex(row);

			if ((cell.getText() != null && !cell.getText().isEmpty())
					|| cell.getGraphic() != null) {
				getChildren().add(cell);
				cell.impl_processCSS(false);

				double w = cell.prefWidth(-1);

				maxWidth = Math.max(maxWidth, w);
				getChildren().remove(cell);
			}
		}

		// dispose of the cell to prevent it retaining listeners (see RT-31015)
		cell.updateIndex(-1);

		// RT-23486
		double widthMax = maxWidth + padding;
		if (treeTableView
				.getColumnResizePolicy() == TreeTableView.CONSTRAINED_RESIZE_POLICY) {
			widthMax = Math.max(widthMax, tc.getWidth());
		}

		tc.impl_setWidth(widthMax);
	}
Reference: JavaFX Tip 22: Autosize (Tree) Table Columns from our JCG partner Dirk Lemmermann at the Pixel Perfect blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button