Issue
I have a TableView
that will shrink/grow properly as the window is resized.
However, I want one of the columns to automatically grow as well. Similar to how the HGrow
property works on other nodes.
A TableColumn
does not seem to have any type of HGrow
or similar properties to tell that column to use all available space.
I did try to set the PrefWidth
property to Double.MAX_VALUE
, but is causing the column to expand indefinitely.
My goal is to have the TableView
fit within the window and if the window is resized, instead of expanding the last pseudo column (which isn't actually a column at all), it will expand the preferred column.
Here is my 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;
}
}
So the goal is to remove the column in red and instead have the "First Name" column take up the extra space (without pushing "Last Name" out of bounds).
Is this possible without resorting to expensive calculations of widths?
Edit: While my example does use the first column in the TableView
, I would want this to be applicable to any column I choose, and regardless of how many columns the TableView
has.
Solution
I thought I would take a crack at it. I am basically listening to when a column width changes and when the table width changes.
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;
}
}
Answered By - Sedrick