JavaFX table 列不会调整为 prefWidth
JavaFX table column won't resize to prefWidth
我在 BorderPane
的中心有一个 TableView
,列的 prefWidth 值不同。在 SceneBuilder 中,列会根据 prefWidth 值正确调整大小,但是当我 运行 程序时,列都具有相同的宽度 (75.0)。这是 .fxml 文件:
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="1500.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ReportController">
<center>
<TableView fx:id="reportTableView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="date" prefWidth="60.0" text="Date" />
<TableColumn fx:id="company" prefWidth="75.0" text="Company" />
<TableColumn fx:id="number" prefWidth="40.0" text="Number" />
...
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</center>
<bottom>
<TitledPane text="Summary" BorderPane.alignment="CENTER">
<content>
<HBox alignment="CENTER">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Details:">
<font>
<Font size="20.0" />
</font>
</Text>
</children>
</HBox>
</content>
</TitledPane>
</bottom>
</BorderPane>
这是加载框架的代码:
try {
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("report.fxml"));
Parent parent = loader.load();
Stage stage = new Stage(StageStyle.DECORATED);
stage.setTitle("Tax Sheet Report");
stage.getIcons().add(new Image("icons/icon.png"));
stage.setScene(new Scene(parent));
stage.setMaximized( true );
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
使用 UNCONSTRAINED_RESIZE_POLICY
而不是 CONSTRAINED_RESIZE_POLICY
作为 TableView
的列策略。
这是因为您将 CONSTRAINED_RESIZE_POLICY 添加到了 table 视图中。
java 文档说::
Simple policy that ensures the width of all visible leaf columns in
this table sum up to equal the width of the table itself.
When the user resizes a column width with this policy, the table
automatically adjusts the width of the right hand side columns. When
the user increases a column width, the table decreases the width of
the rightmost column until it reaches its minimum width. Then it
decreases the width of the second rightmost column until it reaches
minimum width and so on. When all right hand side columns reach
minimum size, the user cannot increase the size of resized column any
more.
话虽如此,如果您故意包含 CONSTRAINED_RESIZE_POLICY,那么您可能需要添加更多自定义逻辑来满足自定义宽度以及策略。
更新:
如果您想在 GridPane 中实现类似于“percentWidth”的功能,您可以尝试以下方法。
想法是:
- 创建一个具有新 属性“percentWidth”
的自定义 TableColumn
- 创建一个对其 widthProperty 具有侦听器的自定义 TableView,并根据 percentWidth 调整列 prefWidth。
- 在 fxml 中导入这些控件并使用新控件更新 fxml。
CustomTableColumn.java
public class CustomTableColumn<S, T> extends TableColumn<S, T> {
private DoubleProperty percentWidth = new SimpleDoubleProperty();
public CustomTableColumn(String columnName) {
super(columnName);
}
public DoubleProperty percentWidth() {
return percentWidth;
}
public double getPercentWidth() {
return percentWidth.get();
}
public void setPercentWidth(double percentWidth) {
this.percentWidth.set(percentWidth);
}
}
CustomTableView.java
public class CustomTableView<S> extends TableView<S> {
public CustomTableView() {
widthProperty().addListener((obs, old, tableWidth) -> {
// Deduct 2px from the total table width for borders. Otherwise you will see a horizontal scroll bar.
double width = tableWidth.doubleValue() - 2;
getColumns().stream().filter(col -> col instanceof CustomTableColumn)
.map(col -> (CustomTableColumn) col)
.forEach(col -> col.setPrefWidth(width * (col.getPercentWidth() / 100)));
});
}
}
更新的 fxml 代码:
<CustomTableView fx:id="reportTableView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<CustomTableColumn fx:id="date" percentWidth="35" text="Date" />
<CustomTableColumn fx:id="company" percentWidth="40" text="Company" />
<CustomTableColumn fx:id="number" percentWidth="25" text="Number" />
...
</columns>
</CustomTableView>
请注意,所有列的总和 percentWidth 应等于 100 以获得更好的结果:)
此实现(非 fxml)的完整工作演示如下:(我更新了代码以修复 gif 中的水平滚动条)
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class PercentageTableColumnDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
persons.add(new Person("Harry", "John", "LS"));
persons.add(new Person("Mary", "King", "MS"));
CustomTableColumn<Person, String> fnCol = new CustomTableColumn<>("First Name");
fnCol.setPercentWidth(30);
fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
CustomTableColumn<Person, String> lnCol = new CustomTableColumn<>("Last Name");
lnCol.setPercentWidth(25);
lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty());
CustomTableColumn<Person, String> cityCol = new CustomTableColumn<>("City");
cityCol.setPercentWidth(45);
cityCol.setCellValueFactory(param -> param.getValue().cityProperty());
CustomTableView<Person> tableView = new CustomTableView<>();
tableView.getColumns().addAll(fnCol, lnCol, cityCol);
tableView.setItems(persons);
VBox root = new VBox();
root.getChildren().addAll(tableView);
VBox.setVgrow(tableView, Priority.ALWAYS);
Scene scene = new Scene(root, 500, 500);
stage.setScene(scene);
stage.setTitle("Table demo");
stage.show();
}
class CustomTableColumn<S, T> extends TableColumn<S, T> {
private DoubleProperty percentWidth = new SimpleDoubleProperty();
public CustomTableColumn(String columnName) {
super(columnName);
}
public DoubleProperty percentWidth() {
return percentWidth;
}
public double getPercentWidth() {
return percentWidth.get();
}
public void setPercentWidth(double percentWidth) {
this.percentWidth.set(percentWidth);
}
}
class CustomTableView<S> extends TableView<S> {
public CustomTableView() {
widthProperty().addListener((obs, old, tableWidth) -> {
// Deduct 2px from the total table width for borders. Otherwise you will see a horizontal scroll bar.
double width = tableWidth.doubleValue() - 2;
getColumns().stream().filter(col -> col instanceof CustomTableColumn)
.map(col -> (CustomTableColumn) col)
.forEach(col -> col.setPrefWidth(width * (col.getPercentWidth() / 100)));
});
}
}
class Person {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
private StringProperty city = new SimpleStringProperty();
public Person(String fn, String ln, String cty) {
setFirstName(fn);
setLastName(ln);
setCity(cty);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public String getCity() {
return city.get();
}
public StringProperty cityProperty() {
return city;
}
public void setCity(String city) {
this.city.set(city);
}
}
}
我在 BorderPane
的中心有一个 TableView
,列的 prefWidth 值不同。在 SceneBuilder 中,列会根据 prefWidth 值正确调整大小,但是当我 运行 程序时,列都具有相同的宽度 (75.0)。这是 .fxml 文件:
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="1500.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ReportController">
<center>
<TableView fx:id="reportTableView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="date" prefWidth="60.0" text="Date" />
<TableColumn fx:id="company" prefWidth="75.0" text="Company" />
<TableColumn fx:id="number" prefWidth="40.0" text="Number" />
...
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</center>
<bottom>
<TitledPane text="Summary" BorderPane.alignment="CENTER">
<content>
<HBox alignment="CENTER">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Details:">
<font>
<Font size="20.0" />
</font>
</Text>
</children>
</HBox>
</content>
</TitledPane>
</bottom>
</BorderPane>
这是加载框架的代码:
try {
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("report.fxml"));
Parent parent = loader.load();
Stage stage = new Stage(StageStyle.DECORATED);
stage.setTitle("Tax Sheet Report");
stage.getIcons().add(new Image("icons/icon.png"));
stage.setScene(new Scene(parent));
stage.setMaximized( true );
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
使用 UNCONSTRAINED_RESIZE_POLICY
而不是 CONSTRAINED_RESIZE_POLICY
作为 TableView
的列策略。
这是因为您将 CONSTRAINED_RESIZE_POLICY 添加到了 table 视图中。
java 文档说::
Simple policy that ensures the width of all visible leaf columns in this table sum up to equal the width of the table itself.
When the user resizes a column width with this policy, the table automatically adjusts the width of the right hand side columns. When the user increases a column width, the table decreases the width of the rightmost column until it reaches its minimum width. Then it decreases the width of the second rightmost column until it reaches minimum width and so on. When all right hand side columns reach minimum size, the user cannot increase the size of resized column any more.
话虽如此,如果您故意包含 CONSTRAINED_RESIZE_POLICY,那么您可能需要添加更多自定义逻辑来满足自定义宽度以及策略。
更新:
如果您想在 GridPane 中实现类似于“percentWidth”的功能,您可以尝试以下方法。
想法是:
- 创建一个具有新 属性“percentWidth” 的自定义 TableColumn
- 创建一个对其 widthProperty 具有侦听器的自定义 TableView,并根据 percentWidth 调整列 prefWidth。
- 在 fxml 中导入这些控件并使用新控件更新 fxml。
CustomTableColumn.java
public class CustomTableColumn<S, T> extends TableColumn<S, T> {
private DoubleProperty percentWidth = new SimpleDoubleProperty();
public CustomTableColumn(String columnName) {
super(columnName);
}
public DoubleProperty percentWidth() {
return percentWidth;
}
public double getPercentWidth() {
return percentWidth.get();
}
public void setPercentWidth(double percentWidth) {
this.percentWidth.set(percentWidth);
}
}
CustomTableView.java
public class CustomTableView<S> extends TableView<S> {
public CustomTableView() {
widthProperty().addListener((obs, old, tableWidth) -> {
// Deduct 2px from the total table width for borders. Otherwise you will see a horizontal scroll bar.
double width = tableWidth.doubleValue() - 2;
getColumns().stream().filter(col -> col instanceof CustomTableColumn)
.map(col -> (CustomTableColumn) col)
.forEach(col -> col.setPrefWidth(width * (col.getPercentWidth() / 100)));
});
}
}
更新的 fxml 代码:
<CustomTableView fx:id="reportTableView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<CustomTableColumn fx:id="date" percentWidth="35" text="Date" />
<CustomTableColumn fx:id="company" percentWidth="40" text="Company" />
<CustomTableColumn fx:id="number" percentWidth="25" text="Number" />
...
</columns>
</CustomTableView>
请注意,所有列的总和 percentWidth 应等于 100 以获得更好的结果:)
此实现(非 fxml)的完整工作演示如下:(我更新了代码以修复 gif 中的水平滚动条)
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class PercentageTableColumnDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
persons.add(new Person("Harry", "John", "LS"));
persons.add(new Person("Mary", "King", "MS"));
CustomTableColumn<Person, String> fnCol = new CustomTableColumn<>("First Name");
fnCol.setPercentWidth(30);
fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
CustomTableColumn<Person, String> lnCol = new CustomTableColumn<>("Last Name");
lnCol.setPercentWidth(25);
lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty());
CustomTableColumn<Person, String> cityCol = new CustomTableColumn<>("City");
cityCol.setPercentWidth(45);
cityCol.setCellValueFactory(param -> param.getValue().cityProperty());
CustomTableView<Person> tableView = new CustomTableView<>();
tableView.getColumns().addAll(fnCol, lnCol, cityCol);
tableView.setItems(persons);
VBox root = new VBox();
root.getChildren().addAll(tableView);
VBox.setVgrow(tableView, Priority.ALWAYS);
Scene scene = new Scene(root, 500, 500);
stage.setScene(scene);
stage.setTitle("Table demo");
stage.show();
}
class CustomTableColumn<S, T> extends TableColumn<S, T> {
private DoubleProperty percentWidth = new SimpleDoubleProperty();
public CustomTableColumn(String columnName) {
super(columnName);
}
public DoubleProperty percentWidth() {
return percentWidth;
}
public double getPercentWidth() {
return percentWidth.get();
}
public void setPercentWidth(double percentWidth) {
this.percentWidth.set(percentWidth);
}
}
class CustomTableView<S> extends TableView<S> {
public CustomTableView() {
widthProperty().addListener((obs, old, tableWidth) -> {
// Deduct 2px from the total table width for borders. Otherwise you will see a horizontal scroll bar.
double width = tableWidth.doubleValue() - 2;
getColumns().stream().filter(col -> col instanceof CustomTableColumn)
.map(col -> (CustomTableColumn) col)
.forEach(col -> col.setPrefWidth(width * (col.getPercentWidth() / 100)));
});
}
}
class Person {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
private StringProperty city = new SimpleStringProperty();
public Person(String fn, String ln, String cty) {
setFirstName(fn);
setLastName(ln);
setCity(cty);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public String getCity() {
return city.get();
}
public StringProperty cityProperty() {
return city;
}
public void setCity(String city) {
this.city.set(city);
}
}
}