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:
问题:
回答1:
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.
回答2:
Is easier with a Label in the header graphic of the column:
- Add a label in the column header graphic (if the column has some text as title delete it).
- 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))
- 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>
回答3:
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.
This results in a following XML code:
<TableColumn fx:id="prodDisc" editable="false" prefWidth="50.0" text="Prod Disc" />
回答4:
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.