我有一个充满嵌套列的TableView。在这些列上,我有2个上下文菜单选项 - “隐藏列”和“取消隐藏所有列”,它们可以切换列及其子项的可见性。
在初始化UI之后填充tableview,因此列的大小设置为默认宽度,该宽度小于最长单元格值的大小。这就是我想要发生的事情。我不希望列扩展到数千像素宽,因为一个特别长的条目。
我的问题是:当用户隐藏列并取消隐藏时,该列的宽度会延伸到可能适合最长单元格值的最小长度。这不是我想要发生的事情。我希望它在以这种方式切换可见性时理想地保持其原始宽度。
为了解决这个问题,我尝试在隐藏列之前将最大宽度设置为当前宽度,然后取消设置最大宽度并在取消隐藏后将预宽度设置为前一个最大宽度(从而将其从调整大小本身锁定)。这不起作用。
这是一个展示正在发生的事情的例子。
TestExample.java
package testexample;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Testexample extends Application {
private TableView table;
@Override
public void start(Stage primaryStage) {
//Create table
table = new TableView();
//Create table items
final ObservableList<DataContainer> data = FXCollections.observableArrayList(
new DataContainer("Alice", "Red", "Yellow"),
new DataContainer("Bob", "purple", "green"),
new DataContainer("Sir Jean-Jaques-Charles III", "Deep green-cyan turqoise", "Fluorescent pink")
);
//Create table columns
TableColumn nameColumn = new TableColumn("name");
TableColumn colorsColumn = new TableColumn("colors");
TableColumn color1Column = new TableColumn("color1");
TableColumn color2Column = new TableColumn("color2");
//Make it so columns can properly display the table items
nameColumn.setCellValueFactory( new PropertyValueFactory<>("name"));
color1Column.setCellValueFactory( new PropertyValueFactory<>("color1"));
color2Column.setCellValueFactory( new PropertyValueFactory<>("color2"));
//Set the header context menus
addHeaderContextMenus(nameColumn);
addHeaderContextMenus(colorsColumn);
addHeaderContextMenus(color1Column);
addHeaderContextMenus(color2Column);
//Add the columns to the table
table.getColumns().addAll(nameColumn, colorsColumn);
colorsColumn.getColumns().addAll(color1Column, color2Column);
//Put the table inside a container
StackPane root = new StackPane();
AnchorPane anchor = new AnchorPane();
root.getChildren().add(anchor);
anchor.getChildren().add(table);
//anchor the table to the AnchorPane
AnchorPane.setTopAnchor(table, 1.0);
AnchorPane.setBottomAnchor(table, 1.0);
AnchorPane.setLeftAnchor(table, 1.0);
AnchorPane.setRightAnchor(table, 1.0);
//show the stage
primaryStage.setTitle("Hello World!");
primaryStage.setScene(new Scene(root, 300, 300));
primaryStage.show();
//Add the data to the table (after everything is shown)
table.setItems(data);
}
//Start the application
public static void main(String[] args) {
launch(args);
}
//Add context menus to the headers.
private void addHeaderContextMenus(TableColumn column) {
//create the menu and attach the items
ContextMenu menu = new ContextMenu();
MenuItem hideItem = new MenuItem("hide");
MenuItem unhideAllItem = new MenuItem("unhide all");
menu.getItems().addAll(hideItem, unhideAllItem);
//Set behavior for hide/unhide
hideItem.setOnAction((event) -> {
hideColumn(column);
});
unhideAllItem.setOnAction((event) -> {
unhideAllColumns();
});
//attach the menu to the column (header)
column.setContextMenu(menu);
}
private void hideColumn(TableColumn column) {
column.setMaxWidth(column.getWidth());
column.setPrefWidth(column.getWidth());
column.setVisible(false);
}
private void unhideAllColumns() {
table.getColumns().forEach(column -> {
unhideColumnsRecursively((TableColumn)column);
});
}
private void unhideColumnsRecursively(TableColumn column) {
column.getColumns().forEach(childColumn -> {
unhideColumnsRecursively((TableColumn)childColumn);
});
if(column.visibleProperty().get() == false) {
column.setVisible(true);
double width = column.getWidth();
column.setMaxWidth(9999999); //arbitrarily large big number
column.setPrefWidth(width);
System.out.println("width to set to: " + width);
System.out.println("current prefwidth: " + column.getPrefWidth());
System.out.println("current actual width: " + column.getWidth());
}
}
}
DataContainer.java
package testexample;
import javafx.beans.property.SimpleStringProperty;
public class DataContainer {
private final SimpleStringProperty name = new SimpleStringProperty();
private final SimpleStringProperty color1 = new SimpleStringProperty();
private final SimpleStringProperty color2 = new SimpleStringProperty();
public DataContainer(String name, String color1, String color2) {
this.name.set(name);
this.color1.set(color1);
this.color2.set(color2);
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public String getColor1() {
return color1.get();
}
public void setColor1(String color1) {
this.color1.set(color1);
}
public String getColor2() {
return color2.get();
}
public void setColor2(String color2) {
this.color2.set(color2);
}
}
以下是隐藏/取消隐藏名称列时发生的情况:example (animated gif)
这是输出:
width to set to: 80.0
current prefwidth: 80.0
current actual width: 80.0
...这当然不是看似显示的东西,因为在隐藏后宽度明显长于80.0!所有列都会发生这种情况,包括“colors”父列(在这种情况下,color1和color2列都会扩展到最长单元格值字符串的宽度)。
另一个转折:如果用户确保在隐藏它之前隐藏的列重新调整,则代码实际上可以正常工作。 Example (animated gif)
那么,发生了什么?显然,应用程序在将可见性设置为true后扩展列以适应最长的数据。如何确保列保持以前的长度?为什么它只在用户调整该列的大小后才起作用(如果它在某个地方设置标志,我可以手动设置该标志?)