Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX 2.0 Table with multiline table header

Tags:

javafx-2

Is it possible to make javaFX 2.0 table with multiline header? All the examples, which i have found on the web, have tables, where columnt header width = its text size, without wraping. The exaple of what i have, and what i need is shown on a screen:enter image description here

like image 257
Victoria Agafonova Avatar asked Jun 08 '12 15:06

Victoria Agafonova


4 Answers

Found a solution without using labels. In Scene Builder 8.3.0 (Gluon) , JavaFX 8 , a button appears on mouse hover, just right of the Text field, where a multi - line can be chosen from the menu.

Menu for multi - line mode

This results in a following XML code:

<TableColumn fx:id="prodDisc" editable="false" prefWidth="50.0" text="Prod &#10;Disc" />
like image 190
Helmwag Avatar answered Nov 03 '22 06:11

Helmwag


I came up with the following function:

private void makeHeaderWrappable(TableColumn col) {
  Label label = new Label(col.getText());
  label.setStyle("-fx-padding: 8px;");
  label.setWrapText(true);
  label.setAlignment(Pos.CENTER);
  label.setTextAlignment(TextAlignment.CENTER);

  StackPane stack = new StackPane();
  stack.getChildren().add(label);
  stack.prefWidthProperty().bind(col.widthProperty().subtract(5));
  label.prefWidthProperty().bind(stack.prefWidthProperty());
  col.setGraphic(stack);
}

A complete executable example is in this gist (requires the 2.2 developer preview as a minimum).

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;

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

  @Override public void start(Stage stage) {
    TableColumn firstNameCol = new TableColumn("First Name (which is a really long name)");
    makeHeaderWrappable(firstNameCol);
    firstNameCol.setPrefWidth(100);
    firstNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName"));
    TableColumn lastNameCol = new TableColumn("Last Name");
    lastNameCol.setPrefWidth(100);
    lastNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("lastName"));

    TableView table = new TableView();
    table.getColumns().addAll(firstNameCol, lastNameCol);
    table.setItems(FXCollections.observableArrayList(
      new Person("Jacob", "Smith"),
      new Person("Isabella", "Johnson"),
      new Person("Ethan", "Williams")
    ));
    table.setPrefSize(250, 200);

    Pane layout = new VBox(10);
    layout.setStyle("-fx-padding: 10;");
    layout.getChildren().addAll(table);
    stage.setScene(new Scene(layout));
    stage.show();
  }

  private void makeHeaderWrappable(TableColumn col) {
    Label label = new Label(col.getText());
    label.setStyle("-fx-padding: 8px;");
    label.setWrapText(true);
    label.setAlignment(Pos.CENTER);
    label.setTextAlignment(TextAlignment.CENTER);

    StackPane stack = new StackPane();
    stack.getChildren().add(label);
    stack.prefWidthProperty().bind(col.widthProperty().subtract(5));
    label.prefWidthProperty().bind(stack.prefWidthProperty());
    col.setText(null);
    col.setGraphic(stack);
  }

  public static class Person {
    private final SimpleStringProperty firstName;
    private final SimpleStringProperty lastName;

    private Person(String fName, String lName) {
      this.firstName = new SimpleStringProperty(fName);
      this.lastName = new SimpleStringProperty(lName);
    }

    public String getFirstName() { return firstName.get(); }
    public void setFirstName(String fName) { firstName.set(fName); }
    public String getLastName() { return lastName.get(); }
    public void setLastName(String fName) { lastName.set(fName); }
  }
}

There is probably a better way to do this, but the function above did at least work for me in my test case.

I thought this would be achievable with a simple css style, but I could not get it to work via css alone.

like image 32
jewelsea Avatar answered Nov 03 '22 04:11

jewelsea


Is easier with a Label in the header graphic of the column:

  1. Add a label in the column header graphic (if the column has some text as title delete it).
  2. Set the label to allow Wrap Text (Scene Builder -> go to Properties of the label and select Wrap Text or in Code -> label.setWrapText(true))
  3. Set label width and height we wish

Note: is easier to do this in a FXML (with Scene Builder) than in code.

Example below:

    public class TableColumnLongTextLabel extends Application {

    @Override
    public void start(Stage stage) {
        TableView table = new TableView();
        TableColumn tableColumnData1 = new TableColumn(),
                tableColumnData2 = new TableColumn("Long Title without Text Wrap");

        tableColumnData1.setCellValueFactory(new PropertyValueFactory<SomeStructure, String>("data1"));
        tableColumnData2.setCellValueFactory(new PropertyValueFactory<SomeStructure, String>("data2"));

        table.getColumns().addAll(tableColumnData1, tableColumnData2);

        Label columnTitle = new Label("Long Title with Text Wrapped");
        columnTitle.setPrefWidth(125);
        columnTitle.setPrefHeight(50);
        columnTitle.setWrapText(true);
        columnTitle.setTextAlignment(TextAlignment.CENTER);
        tableColumnData1.setGraphic(columnTitle);

        table.setItems(FXCollections.observableArrayList(
                new SomeStructure("Java", "FX", 1),
                new SomeStructure("Java", "Swing", 0),
                new SomeStructure("Java", "Sample", 2),
                new SomeStructure("Some", "Other", 10)
        ));

        Pane layout = new VBox(10);
        layout.getChildren().addAll(table);
        stage.setScene(new Scene(layout, 350, 350));
        stage.show();
    }

    public static class SomeStructure {

        private final SimpleStringProperty data1;
        private final SimpleStringProperty data2;
        private final SimpleIntegerProperty data3;

        private SomeStructure(String data1, String data2, Integer data3) {
            this.data1 = new SimpleStringProperty(data1);
            this.data2 = new SimpleStringProperty(data2);
            this.data3 = new SimpleIntegerProperty(data3);
        }

        public String getData1() {
            return data1.get();
        }

        public void setData1(String data1) {
            this.data1.set(data1);
        }

        public String getData2() {
            return data2.get();
        }

        public void setData2(String data2) {
            this.data2.set(data2);
        }

        public Integer getData3() {
            return data3.get();
        }

        public void setData3(Integer data3) {
            this.data3.set(data3);
        }
    }

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

Example using FXML (No code needed :) ):

<TableView prefHeight="251.0" prefWidth="556.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
       <columns>
          <TableColumn editable="false" maxWidth="90.0" prefWidth="70.0" sortable="false" text="Player">
             <columns>
                <TableColumn editable="false" maxWidth="80.0" prefWidth="50.0" text="ID" />
                <TableColumn editable="false" maxWidth="200.0" prefWidth="180.0" text="Name" />
             </columns>
          </TableColumn>
          <TableColumn maxWidth="80.0" minWidth="50.0" prefWidth="60.0" text="Game" />
          <TableColumn editable="false" maxWidth="160.0" minWidth="125.0" prefWidth="135.0" sortable="false" text="Team" visible="false" />
          <TableColumn editable="false" maxWidth="160.0" minWidth="107.0" prefWidth="107.0" sortable="false">
             <graphic>
                <Label alignment="CENTER" text="Individual Points (Big Team)" textAlignment="CENTER" wrapText="true" />
             </graphic>
          </TableColumn>
          <TableColumn editable="false" maxWidth="160.0" minWidth="99.0" prefWidth="102.0" sortable="false">
             <graphic>
                <Label alignment="CENTER" text="Team Points (Small Maps)" textAlignment="CENTER" wrapText="true" />
             </graphic>
          </TableColumn>
          <TableColumn editable="false" maxWidth="116.0" minWidth="55.0" prefWidth="55.0" sortable="false">
             <graphic>
                <Label text="Total Points" textAlignment="CENTER" wrapText="true" />
             </graphic>
          </TableColumn>
       </columns>
    </TableView>

enter image description here

like image 7
Harry244 Avatar answered Nov 03 '22 05:11

Harry244


The easiest way to align header text is with CSS style, like this:

.table-view .column-header .label {
  -fx-text-alignment: center;
}

Use new line escape sequence "\n" in header text string to split it into multiple lines.

like image 6
user645859 Avatar answered Nov 03 '22 04:11

user645859