0

I have a TableView and a Hbox below the table, in the hBox there are threeLabels one contains a text, and two contains the sum of two columns in the table. I want to set a spacing somehow dynamic for the HBox to align the two labels exactly below the two columns in the table to which they belong. Is there any possibility to bind the HBox's spacing to the columns position. I also accept any other solution that fixes the labels exactly below the respective columns. Here is an image that shows what I want:

enter image description here

Sunflame
  • 2,993
  • 4
  • 24
  • 48

1 Answers1

2

Bind each label's minWidth and prefWidth properties to the corresponding column's width property:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class TableWithLabelsBelowColumns extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<Void> table = new TableView<>();
        table.getItems().add(null);

        TableColumn<Void, Void> firstNameColumn = new TableColumn<>("First Name");
        TableColumn<Void, Void> lastNameColumn = new TableColumn<>("Last Name");
        TableColumn<Void, Void> emailColumn = new TableColumn<>("Email");
        table.getColumns().add(firstNameColumn);
        table.getColumns().add(lastNameColumn);
        table.getColumns().add(emailColumn);

        Label fnLabel = new Label("FN");
        Label lnLabel = new Label("LN");
        Label emailLabel = new Label("E");

        fnLabel.prefWidthProperty().bind(firstNameColumn.widthProperty());
        fnLabel.minWidthProperty().bind(firstNameColumn.widthProperty());
        lnLabel.prefWidthProperty().bind(lastNameColumn.widthProperty());
        lnLabel.minWidthProperty().bind(lastNameColumn.widthProperty());
        emailLabel.prefWidthProperty().bind(emailColumn.widthProperty());
        emailLabel.minWidthProperty().bind(emailColumn.widthProperty());

        HBox labels = new HBox(fnLabel, lnLabel, emailLabel);

        BorderPane root = new BorderPane(table);
        root.setBottom(labels);

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

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

An alternative approach is to subclass Pane and override the layoutChildren() method to position the labels according to the widths of the columns. Register a listener to request layout on the pane with each column's width:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class TableWithLabelsBelowColumns extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<Void> table = new TableView<>();
        table.getItems().add(null);

        TableColumn<Void, Void> firstNameColumn = new TableColumn<>("First Name");
        TableColumn<Void, Void> lastNameColumn = new TableColumn<>("Last Name");
        TableColumn<Void, Void> emailColumn = new TableColumn<>("Email");
        table.getColumns().add(firstNameColumn);
        table.getColumns().add(lastNameColumn);
        table.getColumns().add(emailColumn);

        Label fnLabel = new Label("FN");
        Label lnLabel = new Label("LN");
        Label emailLabel = new Label("E");

        Pane labelPane = new Pane(fnLabel, lnLabel, emailLabel) {
            @Override
            protected void layoutChildren() {
                double fnWidth = firstNameColumn.getWidth();
                double fnHeight = fnLabel.prefHeight(fnWidth);
                fnLabel.resizeRelocate(0, 0, fnWidth, fnHeight);

                double lnWidth = lastNameColumn.getWidth();
                double lnHeight = lnLabel.prefHeight(lnWidth);
                lnLabel.resizeRelocate(fnWidth, 0, lnWidth, lnHeight);

                double emailWidth = emailColumn.getWidth();
                double emailHeight = emailLabel.prefHeight(emailWidth);
                emailLabel.resizeRelocate(fnWidth+lnWidth, 0, emailWidth, emailHeight);
            }
        };
        ChangeListener<? super Number> listener = (obs, oldValue, newValue) -> labelPane.requestLayout();
        firstNameColumn.widthProperty().addListener(listener);
        lastNameColumn.widthProperty().addListener(listener);
        emailColumn.widthProperty().addListener(listener);

        BorderPane root = new BorderPane(table);
        root.setBottom(labelPane);

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    public static void main(String[] args) {
        launch(args);
    }
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • I have just tried it, but it is not working when I try to use for 3rd and 4th column, especially the first solution. The second may work, I have to play a little bit with the numbers `fnLabel.resizeRelocate(here, and her, fnWidth, fnHeight);` – Sunflame Jul 31 '17 at 07:12
  • At first was trying to use this solution :https://stackoverflow.com/questions/30506075/javafx-how-to-make-a-line-of-summationtotal-row-in-the-bottom-of-the-table/30509195#30509195, but the problem is that line is an Item of the table, so when I sort, filter, and so on it gets sorted, filtered. – Sunflame Jul 31 '17 at 07:20
  • Finally I solved it using your second suggestion, I have also added at first `.resizeRelocate()` the width of the previous colums so it is working fine now. Thanks. – Sunflame Jul 31 '17 at 15:18