JavaFX TableView列宽恢复失效:需保留CONSTRAINED_RESIZE_POLICY
解决JavaFX TableView在CONSTRAINED_RESIZE_POLICY下恢复列宽无效的问题
我之前也碰到过一模一样的问题——想用CONSTRAINED_RESIZE_POLICY让TableView随窗口自动缩放,同时又想恢复上次关闭时的列宽,结果设置prefWidth完全没效果。后来搞清楚了,这个约束策略的本质是根据列的prefWidth计算宽度比例,然后自动分配可用空间,但如果在设置prefWidth之前就已经启用了这个策略,它会直接覆盖你的设置,优先按比例分配空间。
下面是两种亲测有效的解决方案:
方案一:临时切换Resize Policy
最简单的办法就是先临时关闭约束策略,设置完列宽后再切回去。这样约束策略会基于你设置的prefWidth重新计算比例,完美兼顾自动缩放和列宽恢复:
if (allKnown) { ObservableList<TableColumn<T, ?>> columns = FXCollections.observableArrayList(); // 第一步:临时切换到无约束策略,让prefWidth设置生效 getTableView().setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY); TableColumn<T, ?> column; for (int i = 0; i < colIndex.length; i++) { column = getOriginalColumns().get(colIndex[i]); column.setPrefWidth(colWidths[i]); columns.add(column); } getTableView().getColumns().setAll(columns); // 第二步:切回约束策略,保留窗口缩放自动调整的能力 getTableView().setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); }
方案二:保存宽度比例而非绝对宽度(更推荐)
如果你的应用窗口大小可能变化,保存绝对宽度可能会导致恢复后的列宽在不同窗口尺寸下不协调。更灵活的方式是保存每个列宽度占总宽度的比例,恢复时根据当前TableView的宽度计算实际prefWidth:
保存比例的代码
// 关闭应用时保存列的索引和宽度比例 Properties properties = new Properties(); double totalWidth = getTableView().getWidth(); List<TableColumn<T, ?>> currentColumns = getTableView().getColumns(); // 保存列索引顺序 for (int i = 0; i < currentColumns.size(); i++) { properties.setProperty("col_index_" + i, String.valueOf(getOriginalColumns().indexOf(currentColumns.get(i)))); } // 保存列宽度比例 for (TableColumn<T, ?> col : currentColumns) { properties.setProperty("col_ratio_" + col.getId(), String.valueOf(col.getWidth() / totalWidth)); } // 写入Properties文件 try (OutputStream out = new FileOutputStream("table_config.properties")) { properties.store(out, "TableView column config"); } catch (IOException e) { e.printStackTrace(); }
恢复比例的代码
// 重启应用时恢复列顺序和宽度比例 Properties properties = new Properties(); try (InputStream in = new FileInputStream("table_config.properties")) { properties.load(in); } catch (IOException e) { e.printStackTrace(); } int columnCount = getOriginalColumns().size(); int[] colIndex = new int[columnCount]; double[] colRatios = new double[columnCount]; // 读取列索引 for (int i = 0; i < columnCount; i++) { colIndex[i] = Integer.parseInt(properties.getProperty("col_index_" + i)); } // 读取宽度比例 for (int i = 0; i < columnCount; i++) { TableColumn<T, ?> col = getOriginalColumns().get(colIndex[i]); colRatios[i] = Double.parseDouble(properties.getProperty("col_ratio_" + col.getId())); } if (columnCount > 0) { ObservableList<TableColumn<T, ?>> columns = FXCollections.observableArrayList(); getTableView().setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY); double totalWidth = getTableView().getWidth(); for (int i = 0; i < colIndex.length; i++) { TableColumn<T, ?> column = getOriginalColumns().get(colIndex[i]); // 根据当前总宽度和比例计算prefWidth column.setPrefWidth(totalWidth * colRatios[i]); columns.add(column); } getTableView().getColumns().setAll(columns); getTableView().setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); }
这样不管窗口多大,恢复后的列宽比例都是和上次关闭时一致的,同时CONSTRAINED_RESIZE_POLICY依然能让列随窗口自动调整。
内容的提问来源于stack exchange,提问作者Willem Kunkels
相关产品推荐
相关产品推荐

