-
Notifications
You must be signed in to change notification settings - Fork 0
Home
This page provides more detailed information about the TableViewColumnResizer utility. For a quick start and basic usage, please refer to the main README.md file in the repository.
This utility addresses the limitations of standard JavaFX TableView column resize policies (CONSTRAINED_RESIZE_POLICY and UNCONSTRAINED_RESIZE_POLICY). It aims to:
-
Fill available width: Automatically resize visible columns proportionally to use the entire available horizontal space in the
TableView. -
Respect Constraints: Honor the
minWidthandmaxWidthset on individual columns. - Handle Scrollbar: Correctly subtract the width of the vertical scrollbar when it is visible from the available space.
-
Allow Overflow: Permit a horizontal scrollbar to appear naturally if the sum of minimum column widths exceeds the calculated available space (requires
UNCONSTRAINED_RESIZE_POLICY).
- JavaFX: Developed and tested with JavaFX 21 (likely compatible with other recent versions).
-
Column Resize Policy: The
TableViewmust useTableView.UNCONSTRAINED_RESIZE_POLICY. The staticinstallmethod sets this automatically for convenience.
The primary way to use the resizer is via the static install method:
java
import framework.tableview.TableViewColumnResizer; // Adjust import if necessary
import javafx.scene.control.TableView;
**--- In your initialization code --- **
TableView<MyDataType> tableView = /* ... your TableView instance ... */;
// ... configure your TableView and columns ...
-
Install the automatic resizing behavior
TableViewColumnResizer.install(tableView); -
Optionally store the instance if you need access to forceResizeColumns()
TableViewColumnResizer<MyDataType> resizerInstance = TableViewColumnResizer.install(tableView);
if (resizerInstance != null) { -
Example: Force a resize after manually adding many items
Platform.runLater(resizerInstance::forceResizeColumns);
}
The resizer manages its listeners automatically based on the TableView's presence in the scene graph.
The resizer achieves its goal through a combination of event listening and calculation:
-
Event Listeners: It actively listens for changes that affect column layout:
-
TableView'swidthProperty: Recalculates column widths when the table width changes (debounced for performance). -
TableView'svisibleLeafColumns: Recalculates immediately if columns are added, removed, or their visibility changes. -
ScrollBar'svisibleProperty: Recalculates immediately when the vertical scrollbar appears or disappears. -
ScrollBar'swidthProperty: Recalculates immediately if the scrollbar's actual width changes. -
TableView'ssceneProperty: Attaches/detaches all listeners to prevent memory leaks when the TableView is added/removed from the UI.
-
-
Scrollbar Detection: It attempts to find the vertical
ScrollBarnode within theTableViewskin usinglookupAll.
This happens initially and potentially again if not found immediately. -
Available Width Calculation: The core calculation determines the space available for columns:
AvailableWidth = TableViewWidth - HorizontalPadding - EffectiveScrollbarWidth-
HorizontalPaddingincludesInsetsplus theHORIZONTAL_PADDING_BUFFER(default4.0) constant to compensate for internal spacing. -
EffectiveScrollbarWidthis determined by checking if the foundScrollBarinstance is currentlyisVisible. If yes, it prefers the actualgetWidth(), falls back togetPrefWidth(), and finally usesDEFAULT_SCROLLBAR_WIDTH_FALLBACK(default15.0) if both are invalid.
-
-
Width Distribution: The
availableWidthis distributed among thevisibleLeafColumns:-
Expansion (> PrefWidth): Extra space is distributed proportionally based on each column's "grow potential" (
maxWidth - prefWidth). Columns withmaxWidth = Double.MAX_VALUEreceive a share based on their current preferred width relative to other infinite-width columns. Remaining space after clamping is redistributed if possible. -
Shrinking (< PrefWidth, >= MinWidth): The needed deficit is removed proportionally based on each column's "shrink potential" (
prefWidth - minWidth). -
Minimum Width (< MinWidth): If space is insufficient even for minimum widths, columns are set to their
minWidth(requiresUNCONSTRAINED_RESIZE_POLICYon the TableView to allow the horizontal scrollbar). -
Exact Fit: If space matches
totalPrefWidth, current preferred widths are used (clamped).
-
Expansion (> PrefWidth): Extra space is distributed proportionally based on each column's "grow potential" (
-
Applying Widths: The calculated widths are applied by setting the
prefWidthproperty of each column. Changes are only applied if they exceed a small threshold (0.5px) to minimize unnecessary layout passes. -
Lifecycle Management: It automatically attaches/detaches its listeners when the
TableViewis added to/removed from a scene to prevent memory leaks.
Note on Initial Scrollbar Detection: The calculation accurately accounts for the vertical scrollbar. However, the visibility and final width of the scrollbar are determined by the JavaFX layout system based on the TableView's content and available height. Since the TableView is often populated with data after the initial scene display, the scrollbar might not be visible or have its final dimensions immediately when the resizer performs its first checks.
This resizer addresses this by using internal listeners (visibleProperty, widthProperty) attached to the scrollbar. These listeners ensure that the column widths are correctly recalculated as soon as the layout system updates the scrollbar's state after the table is populated or resized. While this process relies on the standard layout and event timing, the listener-based approach ensures the layout eventually reflects the correct scrollbar state for accurate column sizing.
-
HORIZONTAL_PADDING_BUFFER(static final double): Default value is4.0. Located inside theTableViewColumnResizer.javasource code. This buffer compensates for internalTableViewborders or spacing not covered bygetInsets(). If you experience a persistent, unwanted horizontal scrollbar appearing due to minimal overflow, you might need to slightly increase this value in the source code. Conversely, if there's consistently a tiny gap on the right, you could try decreasing it slightly.
- The class uses SLF4j for logging internal operations.
- Logging can be globally toggled using the static boolean
TableViewColumnResizer.isLoggingEnabled(defaults totrue). - Output depends on both
isLoggingEnabledbeingtrueAND the appropriate log level (DEBUG, INFO, WARN, ERROR) being enabled in your runtime SLF4j configuration (binding). - Requires
slf4j-api.jarand a suitable binding (e.g.,slf4j-simple.jar,logback-classic.jar) on the classpath at runtime to see output.
- The public instance method
forceResizeColumns()allows triggering the internal resize calculation manually. - Usage is generally not necessary because the internal listeners handle most scenarios automatically.
- It might be considered in complex edge cases, e.g., after extensive programmatic changes to table data and column visibility/properties within a single operation where you want to ensure the layout is updated immediately afterwards (potentially wrapped in
Platform.runLater).
-
TableViewOnly: Currently designed only forjavafx.scene.control.TableView, notTreeTableView. -
Leaf Columns: Resizing applies to the bottom-most visible columns (
getVisibleLeafColumns).
-
Columns don't fill width / Unwanted H-Scrollbar:
- Verify
TableViewpolicy isUNCONSTRAINED_RESIZE_POLICY(theinstallmethod should set this). - Check the value of
HORIZONTAL_PADDING_BUFFERin the source; it might need slight adjustment for your specific CSS/theme. - Enable DEBUG logging and check the calculated
AvailableWidth,EffectiveScrollbarWidth, and applied column widths.
- Verify
-
No Logging Output:
- Ensure
TableViewColumnResizer.isLoggingEnabledistrue. - Verify you have
slf4j-api.jarAND an SLF4j binding JAR (likeslf4j-simple.jar) in your project's classpath. - Check the configuration of your SLF4j binding to ensure the desired log levels (e.g., DEBUG) are enabled for the logger (e.g.,
izon.framework.tableview.TableViewColumnResizer).
- Ensure
This project is licensed under the MIT License. See the LICENSE file for the full license text.
Copyright (c) 2025 Henryk Daniel Zschuppan, Mecklenburg-Vorpommern, Germany
Please report any bugs or suggest features via the GitHub Issues page for this repository.