Javafx 如何设置一个TableColumn以与TableView一起增长?

Javafx 如何设置一个TableColumn以与TableView一起增长?,javafx,Javafx,我有一个TableView,它会随着窗口大小的调整而适当地收缩/增长 但是,我希望其中一列也能自动增长。类似于HGrow属性在其他节点上的工作方式 TableColumn似乎没有任何类型的HGrow或类似属性来告诉该列使用所有可用空间 我确实尝试将PrefWidth属性设置为Double.MAX\u值,但导致列无限扩展 我的目标是让TableView适合窗口,如果调整窗口大小,而不是展开最后一个伪列(实际上根本不是列),它将展开首选列 这是我的MCVE: import javafx.applic

我有一个
TableView
,它会随着窗口大小的调整而适当地收缩/增长

但是,我希望其中一列也能自动增长。类似于
HGrow
属性在其他节点上的工作方式

TableColumn
似乎没有任何类型的
HGrow
或类似属性来告诉该列使用所有可用空间

我确实尝试将
PrefWidth
属性设置为
Double.MAX\u值
,但导致列无限扩展

我的目标是让
TableView
适合窗口,如果调整窗口大小,而不是展开最后一个伪列(实际上根本不是列),它将展开首选列

这是我的MCVE:

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableColumnGrow extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        // Simple Interface
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(10));

        TableView<Person> tableView = new TableView<>();
        TableColumn<Person, String> colFirstName = new TableColumn<>("First Name");
        TableColumn<Person, String> colLastName = new TableColumn<>("Last Name");

        colFirstName.setCellValueFactory(tf -> tf.getValue().firstNameProperty());
        colLastName.setCellValueFactory(tf -> tf.getValue().lastNameProperty());

        tableView.getColumns().addAll(colFirstName, colLastName);

        tableView.getItems().addAll(
                new Person("Martin", "Brody"),
                new Person("Matt", "Hooper"),
                new Person("Sam", "Quint")
        );

        root.getChildren().add(tableView);

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("TableColumnGrow Sample");
        primaryStage.show();

    }
}

class Person {
    private final StringProperty firstName = new SimpleStringProperty();
    private final StringProperty lastName = new SimpleStringProperty();

    public Person(String firstName, String lastName) {
        this.firstName.set(firstName);
        this.lastName.set(lastName);
    }

    public String getFirstName() {
        return firstName.get();
    }

    public void setFirstName(String firstName) {
        this.firstName.set(firstName);
    }

    public StringProperty firstNameProperty() {
        return firstName;
    }

    public String getLastName() {
        return lastName.get();
    }

    public void setLastName(String lastName) {
        this.lastName.set(lastName);
    }

    public StringProperty lastNameProperty() {
        return lastName;
    }
}
导入javafx.application.application;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
公共类TableColumnGrow扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
//简单接口
VBox根=新的VBox(10);
根部设置对齐(位置中心);
根。设置填充(新插图(10));
TableView TableView=新建TableView();
TableColumn colFirstName=新的TableColumn(“名字”);
TableColumn colLastName=新的TableColumn(“姓氏”);
colFirstName.setCellValueFactory(tf->tf.getValue().firstNameProperty());
colLastName.setCellValueFactory(tf->tf.getValue().lastNameProperty());
tableView.getColumns().addAll(colFirstName、colLastName);
tableView.getItems().addAll(
新人(“马丁”、“布罗迪”),
新人(“马特”、“胡珀”),
新人(“Sam”、“Quint”)
);
root.getChildren().add(tableView);
//上台
primaryStage.setScene(新场景(根));
primaryStage.setTitle(“TableColumnGrow样本”);
primaryStage.show();
}
}
班主任{
private final StringProperty firstName=新SimpleStringProperty();
private final StringProperty lastName=新的SimpleStringProperty();
公众人物(字符串名、字符串名){
this.firstName.set(firstName);
this.lastName.set(lastName);
}
公共字符串getFirstName(){
返回firstName.get();
}
public void setFirstName(字符串firstName){
this.firstName.set(firstName);
}
public StringProperty firstNameProperty(){
返回名字;
}
公共字符串getLastName(){
返回lastName.get();
}
public void setLastName(字符串lastName){
this.lastName.set(lastName);
}
公共StringProperty lastNameProperty(){
返回姓氏;
}
}

因此,我们的目标是删除红色列,而不是让“First Name”列占用额外的空间(而不将“Last Name”超出边界)

这是否可能,而不诉诸昂贵的宽度计算


编辑:虽然我的示例使用了
表视图中的第一列,但我希望它适用于我选择的任何列,无论
表视图有多少列。

如果您不想更改其他列的宽度,这可能是一种解决方案

在tableView和列声明之后包含此项

更新:抱歉,没有注意到问题的最后一行。(关于计算)。因此,如果不适合您,请放弃此解决方案。

TableColumn<?, ?> columnToResize = colFirstName;
tableView.widthProperty().addListener((obs, old, width) -> {
    double otherColsWidth = tableView.getColumns().stream().filter(tc -> tc != columnToResize).mapToDouble(tc -> tc.getWidth()).sum();
    double padding = tableView.getPadding().getLeft() + tableView.getPadding().getRight();
    columnToResize.setPrefWidth(width.doubleValue() - otherColsWidth - padding);
});
TableColumn columnToResize=colFirstName;
tableView.widthProperty().addListener((obs,旧,宽度)->{
double otherColsWidth=tableView.getColumns().stream().filter(tc->tc!=columnToResize).mapToDouble(tc->tc.getWidth()).sum();
双重填充=tableView.getPadding().getLeft()+tableView.getPadding().getRight();
columnToResize.setPrefWidth(width.doubleValue()-otherColsWidth-padding);
});
更新2:

如果您想在调整其他列的大小时更灵活地调整hgrow列的大小,下面是一个快速演示。请注意,调整hgrow列的大小本身没有特定的代码,因为这取决于您如何处理这种情况

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


public class TableColumnGrow extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(10));

        HGrowTableView<Person> tableView = new HGrowTableView<>();
        TableColumn<Person, String> colFirstName = new HGrowTableColumn<>("First Name");
        TableColumn<Person, String> colLastName = new HGrowTableColumn<>("Last Name");

        colFirstName.setCellValueFactory(tf -> tf.getValue().firstNameProperty());
        colLastName.setCellValueFactory(tf -> tf.getValue().lastNameProperty());

        tableView.setColumnToResize(colLastName);
        tableView.getColumns().addAll(colFirstName, colLastName);

        tableView.getItems().addAll(
                new Person("Martin", "Brody"),
                new Person("Matt", "Hooper"),
                new Person("Sam", "Quint")
        );
        root.getChildren().add(tableView);

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("TableColumnGrow Sample");
        primaryStage.show();

    }

    /**
     * Custom Table View
     *
     * @param <S>
     */
    class HGrowTableView<S> extends TableView<S> {
        TableColumn<?, ?> columnToResize;
        ChangeListener<Number> tableWidthListener = (obs, old, width) -> {
            double otherColsWidth = getColumns().stream().filter(tc -> tc != columnToResize).mapToDouble(tc -> tc.getWidth()).sum();
            double padding = getPadding().getLeft() + getPadding().getRight();
            columnToResize.setPrefWidth(width.doubleValue() - otherColsWidth - padding);
        };

        public void setColumnToResize(TableColumn<?, ?> columnToResize) {
            widthProperty().removeListener(tableWidthListener); // Ensuring to remove any previous listener
            this.columnToResize = columnToResize;
            if (this.columnToResize != null) {
                widthProperty().addListener(tableWidthListener);
            }
        }

        public TableColumn<?, ?> getColumnToResize() {
            return columnToResize;
        }
    }

    /**
     * Custom TableColumn
     *
     * @param <S>
     * @param <T>
     */
    class HGrowTableColumn<S, T> extends TableColumn<S, T> {
        public HGrowTableColumn(String title) {
            super(title);
            init();
        }

        private void init() {
            widthProperty().addListener((obs, old, width) -> {
                if (getTableView() instanceof HGrowTableView) {
                    TableColumn<?, ?> columnToResize = ((HGrowTableView) getTableView()).getColumnToResize();
                    if (columnToResize != null && HGrowTableColumn.this != columnToResize) {
                        double diff = width.doubleValue() - old.doubleValue();
                        columnToResize.setPrefWidth(columnToResize.getWidth() - diff);
                    }
                }
            });
        }
    }

    class Person {
        private final StringProperty firstName = new SimpleStringProperty();
        private final StringProperty lastName = new SimpleStringProperty();

        public Person(String firstName, String lastName) {
            this.firstName.set(firstName);
            this.lastName.set(lastName);
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String firstName) {
            this.firstName.set(firstName);
        }

        public StringProperty firstNameProperty() {
            return firstName;
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String lastName) {
            this.lastName.set(lastName);
        }

        public StringProperty lastNameProperty() {
            return lastName;
        }
    }
}
导入javafx.application.application;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.beans.value.ChangeListener;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
公共类TableColumnGrow扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
VBox根=新的VBox(10);
根部设置对齐(位置中心);
根。设置填充(新插图(10));
HGrowTableView tableView=新建HGrowTableView();
TableColumn colFirstName=新的HGrowTableColumn(“名字”);
TableColumn colLastName=新的HGrowTableColumn(“姓氏”);
colFirstName.setCellValueFactory(tf->tf.getValue().firstNameProperty());
colLastName.setCellValueFactory(tf->tf.getValue().lastNameProperty());
tableView.setColumnToResize(colLastName);
tableView.getColumns().addAll(colFirstName、colLastName);
tableView.getItems().addAll(
新人(“马丁”、“布罗迪”),
新人(“马特”、“胡珀”),
新人(“Sam”、“Quint”)
);
package tmp_table;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class App extends Application {
    public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) throws Exception {
      var people = FXCollections.observableArrayList(
          new Person("John Doe", "Male"),
          new Person("Jane Doe", "Female")
      );
      var table = new TableView<Person>(people);
      var nameCol = new TableColumn<Person, String>("Name");
      var genderCol = new TableColumn<Person, String>("Gender");

      nameCol.setCellValueFactory(
          cell -> cell.getValue().nameProperty());
      genderCol.setCellValueFactory(
          cell -> cell.getValue().genderProperty());

      table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
      // this gives name column 70% of table width, the 
      // CONSTRAINED_RESIZE_POLICY will make the other
      // remaining columns fill the table width equally
      nameCol.minWidthProperty().bind(
          table.widthProperty().multiply(0.7));

      table.getColumns().add(nameCol);
      table.getColumns().add(genderCol);

      var stackPane = new StackPane(table);
      StackPane.setAlignment(table, Pos.CENTER);
      primaryStage.setScene(new Scene(stackPane, 400, 200));
      primaryStage.show();
  }
}

class Person {
    StringProperty name = new SimpleStringProperty("");
    StringProperty gender = new SimpleStringProperty("");

    public Person(String name, String gender) {
        this.name.set(name);
        this.gender.set(gender);
    }

    public StringProperty nameProperty() {
        return name;
    }

    public StringProperty genderProperty() {
        return gender;
    }
}
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.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author blj0011
 */
public class JavaFXTestingGround extends Application{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        // Simple Interface
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(10));

        TableView<Person> tableView = new TableView<>();
        TableColumn<Person, String> colFirstName = new TableColumn<>("First Name");
        TableColumn<Person, String> colMiddleName = new TableColumn<>("Last Name");
        TableColumn<Person, String> colLastName = new TableColumn<>("Last Name");

        colFirstName.setCellValueFactory(tf -> tf.getValue().firstNameProperty());
        colLastName.setCellValueFactory(tf -> tf.getValue().lastNameProperty());
        colLastName.setCellValueFactory(tf -> tf.getValue().lastNameProperty());

        tableView.getColumns().addAll(colFirstName, colMiddleName, colLastName);

        tableView.getItems().addAll(
                new Person("Martin", "One", "Brody"),
                new Person("Matt", "Two", "Hooper"),
                new Person("Sam", "Three", "Quint")
        );


        root.getChildren().add(tableView);

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("TableColumnGrow Sample");
        primaryStage.show();

        DoubleProperty width = new SimpleDoubleProperty();
        width.bind(colMiddleName.widthProperty().add(colLastName.widthProperty()));
        width.addListener((ov, t, t1) -> {
            colFirstName.setPrefWidth(tableView.getWidth() - 5 - t1.doubleValue());
        });

        colFirstName.setPrefWidth(tableView.getWidth() - 5 - width.doubleValue());
        colFirstName.setResizable(false);

        tableView.widthProperty().addListener((ov, t, t1) -> {
            colFirstName.setPrefWidth(tableView.getWidth() - 5 - width.doubleValue());
        });
    }
}

class Person {
    private final StringProperty firstName = new SimpleStringProperty();
    private final StringProperty lastName = new SimpleStringProperty();
    private final StringProperty middleName = new SimpleStringProperty();

    public Person(String firstName, String middleName, String lastName) {
        this.firstName.set(firstName);
        this.middleName.set(middleName);
        this.lastName.set(lastName);
    }

    public String getFirstName() {
        return firstName.get();
    }

    public void setFirstName(String firstName) {
        this.firstName.set(firstName);
    }

    public StringProperty firstNameProperty() {
        return firstName;
    }

    public String getMiddleName() {
        return lastName.get();
    }

    public void setMiddleName(String lastName) {
        this.lastName.set(lastName);
    }

    public StringProperty middleNameProperty() {
        return lastName;
    }

    public String getLastName() {
        return lastName.get();
    }

    public void setLastName(String lastName) {
        this.lastName.set(lastName);
    }

    public StringProperty lastNameProperty() {
        return lastName;
    }
}