In a TableView one can select multiple columns to sort on by clicking the table column headers. The headers draw an arrow and a dot to indicate the sort order.
Ensure you have the columns sorting differently, some Descending and some Ascending, hiding all the columns except the first one will result is the arrow being miss-drawn.
Using the sample application, perform the following steps:
1 click the first column to have it sort Descending (down arrow)
2 holding the CTRL key, click on the remaining columns to add to the sort but have then sort Ascending (up arrow) , all columns should now have an arrow with dots under them, which is displayed correctly.
3 Now hide all columns except the first one. Notice that the arrows have redraw over each other.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TableViewColumnBug extends Application {
private TableView<Person> table = new TableView<Person>();
private final ObservableList<Person> data = FXCollections.observableArrayList(new Person("Jacob", "Smith", "jacob.smith@example.com"),
new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
new Person("Ethan", "Williams", "ethan.williams@example.com"),
new Person("Emma", "Jones", "emma.jones@example.com"),
new Person("Michael", "Brown", "michael.brown@example.com"));
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(450);
stage.setHeight(500);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
ObservableList<TableColumn<Person, ?>> columns = table.getColumns();
for (final TableColumn<Person, ?> tableColumn : table.getColumns()) {
ContextMenu contextMenu = new ContextMenu();
MenuItem hideMenu = new MenuItem();
hideMenu.setText("Hide");
hideMenu.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
tableColumn.setVisible(false);
}
});
contextMenu.getItems().add(hideMenu);
tableColumn.setContextMenu(contextMenu);
Menu showMenu = new Menu();
showMenu.setText("show");
contextMenu.getItems().add(showMenu);
for (final TableColumn<Person, ?> tableColumn2 : table.getColumns()) {
CheckMenuItem menuItemField = new CheckMenuItem();
menuItemField.setText(tableColumn2.getText());
menuItemField.setSelected(true);
showMenu.getItems().add(menuItemField);
Bindings.bindBidirectional(tableColumn2.visibleProperty(), menuItemField.selectedProperty());
}
}
((Group)scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
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);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}
Ensure you have the columns sorting differently, some Descending and some Ascending, hiding all the columns except the first one will result is the arrow being miss-drawn.
Using the sample application, perform the following steps:
1 click the first column to have it sort Descending (down arrow)
2 holding the CTRL key, click on the remaining columns to add to the sort but have then sort Ascending (up arrow) , all columns should now have an arrow with dots under them, which is displayed correctly.
3 Now hide all columns except the first one. Notice that the arrows have redraw over each other.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TableViewColumnBug extends Application {
private TableView<Person> table = new TableView<Person>();
private final ObservableList<Person> data = FXCollections.observableArrayList(new Person("Jacob", "Smith", "jacob.smith@example.com"),
new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
new Person("Ethan", "Williams", "ethan.williams@example.com"),
new Person("Emma", "Jones", "emma.jones@example.com"),
new Person("Michael", "Brown", "michael.brown@example.com"));
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(450);
stage.setHeight(500);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
ObservableList<TableColumn<Person, ?>> columns = table.getColumns();
for (final TableColumn<Person, ?> tableColumn : table.getColumns()) {
ContextMenu contextMenu = new ContextMenu();
MenuItem hideMenu = new MenuItem();
hideMenu.setText("Hide");
hideMenu.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
tableColumn.setVisible(false);
}
});
contextMenu.getItems().add(hideMenu);
tableColumn.setContextMenu(contextMenu);
Menu showMenu = new Menu();
showMenu.setText("show");
contextMenu.getItems().add(showMenu);
for (final TableColumn<Person, ?> tableColumn2 : table.getColumns()) {
CheckMenuItem menuItemField = new CheckMenuItem();
menuItemField.setText(tableColumn2.getText());
menuItemField.setSelected(true);
showMenu.getItems().add(menuItemField);
Bindings.bindBidirectional(tableColumn2.visibleProperty(), menuItemField.selectedProperty());
}
}
((Group)scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
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);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}