【问题标题】:JavaFX table column won't resize to prefWidthJavaFX 表列不会调整为 prefWidth
【发布时间】:2022-01-19 00:40:00
【问题描述】:

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

【问题讨论】:

    标签: java javafx


    【解决方案1】:

    这是因为您在表视图中包含了 CONSTRAINED_RESIZE_POLICY。

    java 文档说::

    确保所有可见叶列的宽度的简单策略 这个表格的总和等于表格本身的宽度。

    当用户使用此策略调整列宽时,表格 自动调整右侧列的宽度。什么时候 用户增加一列宽度,表格减小宽度 最右边的列,直到它达到其最小宽度。然后它 减小最右边第二列的宽度,直到达到 最小宽度等等。当所有右侧列到达 最小大小,用户不能增加任何调整大小的列的大小 更多。

    话虽如此,如果您故意包含 CONSTRAINED_RESIZE_POLICY,那么您可能需要添加更多自定义逻辑来满足自定义宽度以及策略。

    更新:

    如果您想在 GridPane 中实现类似“percentWidth”功能的功能,您可以尝试以下方法。

    想法是:

    • 创建具有新属性“percentWidth”的自定义 TableColumn
    • 创建一个自定义 TableView,它有一个对其 widthProperty 的侦听器,并根据 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);
            }
        }
    }
    

    【讨论】:

    • 谢谢,成功了!有没有办法让单元格拉伸到表格的宽度,但保留它们相对于首选宽度的比率?
    • 我认为您可以考虑为 TableColumn 实现自定义 percentWidth 功能和自定义 TableView 来调整列宽。我用所需的详细信息更新了答案。
    • 当作为新问题提出时,通常最好遵循此类问题,这些问题涉及到原始问题。
    【解决方案2】:

    使用UNCONSTRAINED_RESIZE_POLICY 而不是CONSTRAINED_RESIZE_POLICY 作为TableView 的列策略。

    【讨论】:

      猜你喜欢
      • 2015-09-04
      • 1970-01-01
      • 2016-01-12
      • 2014-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-04
      • 2020-11-12
      相关资源
      最近更新 更多