I am trying to wrap the text in the ComboBox but I cannot really manage it.
I need the wrapped text in the editor part, not in the dropdown part of the comboBox. I see that the editor is a TextField, and its text cannot really be wrapped or?
Is there any trick or solution to have a nicely wrapped text so if I have a really long text I can see it every time?
So instead of displaying the ... I want the whole text to be displayed.
Code part I don't know if I should add since it is really simple table cell, and a ComboBox set as Graphics, but if it helps I will edit the question.
Note: Setting the colum wider so the text can fit, is not a solution!
Here is a screenshot:
I am bit confused about the question. You want to show the wrapped text while editing or while in non edit mode.? Because if you are in editing mode you cannot see ... in text box.
So I assume you are asking for showing the wrapped text after selecting from popup list and the combo is not in edit mode.We can fix that using buttonCell.
If this is what you are not asking for, then a Minimal, Complete, and Verifiable example can help me to look into the actual issue.
Please refer to the below code of how to show the wrapped text.
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableViewComboBoxCell 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);
}
private final ObservableList<String> comboList = FXCollections.observableArrayList("First big sentence with very long text to check the text wrap",
"Second big sentence with very long text to check the text wrap",
"Third big sentence with very long text to check the text wrap",
"Fourth big sentence with very long text to check the text wrap");
#Override
public void start(Stage stage) {
for (int i = 0; i < 50; i++) {
if(i%5==0){
data.add(new Person("Name " + i, "Last " + i, "Mail " + i, comboList.get(0)));
}else {
data.add(new Person("Name " + i, "Last " + i, "Mail " + i));
}
}
Scene scene = new Scene(new StackPane());
stage.setTitle("Table View Sample");
stage.setWidth(650);
stage.setHeight(500);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol
.setCellValueFactory(new PropertyValueFactory<Person, String>(
"firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol
.setCellValueFactory(new PropertyValueFactory<Person, String>(
"lastName"));
TableColumn<Person, String> emailCol = new TableColumn<>("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>(
"email"));
TableColumn<Person, String> comboCol = new TableColumn<>("Combo");
comboCol.setMinWidth(200);
comboCol.setCellValueFactory(new PropertyValueFactory<Person, String>(
"combo"));
comboCol.setCellFactory(new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {
#Override
public TableCell<Person, String> call(TableColumn<Person, String> param) {
return new TableCell<Person, String>() {
private ComboBox<String> combo;
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
getCombo().getSelectionModel().clearSelection();
if (!empty) {
getCombo().setValue(item);
setGraphic(getCombo());
} else {
setGraphic(null);
}
}
private ComboBox<String> getCombo() {
if (combo == null) {
combo = new ComboBox<>();
combo.setItems(comboList);
combo.getSelectionModel().selectedItemProperty().addListener((obs, old, newVal) -> {
((Person) getTableRow().getItem()).setCombo(newVal);
});
combo.setButtonCell(new ListCell<String>() {
private Text textLbl;
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setGraphic(null);
if (!empty) {
getTextLbl().setText(item);
setGraphic(getTextLbl());
}
}
private Text getTextLbl(){
if(textLbl ==null){
textLbl = new Text();
textLbl.wrappingWidthProperty().bind(this.widthProperty().subtract(10));
}
return textLbl;
}
});
}
return combo;
}
};
}
});
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol, comboCol);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
((StackPane) 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 final SimpleStringProperty combo;
private Person(String fName, String lName, String email) {
this(fName,lName,email,null);
}
private Person(String fName, String lName, String email, String comboStr) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
this.combo = new SimpleStringProperty(comboStr);
}
public String getFirstName() {
return firstName.get();
}
public SimpleStringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public SimpleStringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public String getEmail() {
return email.get();
}
public SimpleStringProperty emailProperty() {
return email;
}
public void setEmail(String email) {
this.email.set(email);
}
public String getCombo() {
return combo.get();
}
public SimpleStringProperty comboProperty() {
return combo;
}
public void setCombo(String combo) {
this.combo.set(combo);
}
}
}
And the output is as below:
Related
I am working on a TableView (FXML) where I want to have all the rows accompanied with a delete button at the last column.
Here's a video that shows what I mean: YouTube Delete Button in TableView
Here's what I have in my main controller class:
public Button del() {
Button del = new Button();
del.setText("X");
del.setPrefWidth(30);
del.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
int i = index.get();
if(i > -1) {
goals.remove(i);
list.getSelectionModel().clearSelection();
}
}
});
return del;
}
private SimpleIntegerProperty index = new SimpleIntegerProperty();
#Override
public void initialize(URL location, ResourceBundle resources){
//DateFormat df = new SimpleDateFormat("dd MMM yyyy");
sdate.setValue(LocalDate.now());
edate.setValue(LocalDate.now());
seq.setCellValueFactory(new PropertyValueFactory<Goals, Integer>("id"));
gol.setCellValueFactory(new PropertyValueFactory<Goals, String>("goal"));
sdt.setCellValueFactory(new PropertyValueFactory<Goals, Date>("sdte"));
edt.setCellValueFactory(new PropertyValueFactory<Goals, Date>("edte"));
prog.setCellValueFactory(new PropertyValueFactory<Goals, Integer>("pb"));
del.setCellValueFactory(new PropertyValueFactory<Goals, Button>("x"));
list.setItems(goals);
list.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Object>() {
#Override
public void changed(ObservableValue<?> observable,
Object oldValue, Object newValue) {
index.set(goals.indexOf(newValue));
System.out.println("Index is: "+goals.indexOf(newValue));
}
});
}
Each time I launch the application, I will try to click the delete button from random rows but it always delete the first row. I guess the addListener method I use for list is not properly implemented and indexOf(newValue) is always 0 at every initialisation.
However, it will work if I click a row first and then click the delete button. But this is not what I want. I want users to be able to delete any row if they press the delete button without selecting the row.
Appreciate your help guys!
You need a custom cell factory defined for the column containing the delete button.
TableColumn<Person, Person> unfriendCol = new TableColumn<>("Anti-social");
unfriendCol.setCellValueFactory(
param -> new ReadOnlyObjectWrapper<>(param.getValue())
);
unfriendCol.setCellFactory(param -> new TableCell<Person, Person>() {
private final Button deleteButton = new Button("Unfriend");
#Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
if (person == null) {
setGraphic(null);
return;
}
setGraphic(deleteButton);
deleteButton.setOnAction(
event -> getTableView().getItems().remove(person)
);
}
});
Here is a sample app. It doesn't use FXML, but you could adapt it to work with FXML very easily. Just click on an "Unfriend" button in the "Anti-social" column to delete a friend. Do it a lot and you will soon run out of friends.
import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class GestureEvents extends Application {
private TableView<Person> table = new TableView<>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith"),
new Person("Isabella", "Johnson"),
new Person("Ethan", "Williams"),
new Person("Emma", "Jones"),
new Person("Michael", "Brown")
);
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
final Label label = new Label("Friends");
label.setFont(new Font("Arial", 20));
final Label actionTaken = new Label();
TableColumn<Person, Person> unfriendCol = new TableColumn<>("Anti-social");
unfriendCol.setMinWidth(40);
unfriendCol.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue()));
unfriendCol.setCellFactory(param -> new TableCell<Person, Person>() {
private final Button deleteButton = new Button("Unfriend");
#Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
if (person == null) {
setGraphic(null);
return;
}
setGraphic(deleteButton);
deleteButton.setOnAction(event -> data.remove(person));
}
});
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<>("firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<>("lastName"));
table.setItems(data);
table.getColumns().addAll(unfriendCol, firstNameCol, lastNameCol);
table.setPrefHeight(250);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 10, 10, 10));
vbox.getChildren().addAll(label, table, actionTaken);
VBox.setVgrow(table, Priority.ALWAYS);
stage.setScene(new Scene(vbox));
stage.show();
}
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);
}
}
}
I am going through the Oracle tutorial with tables, and have implemented my own tabPane into this code. What I want is for the table to be a global table, so that when I go onto tab 2, it is the exact same as it is on Tab 1, just only that i can edit certain columns in tab 2 compared to editing it all in tab 1.
Is there anyway this can be done instead of basically duplicating code and creating a second table, which i believe is tedious as I don't want two tables, I want one global table.
public class TableSample 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"));
public static void main(String[] args) {
launch(args);
}
private TableView table = new TableView();
public void start(Stage stage) {
Scene scene = new Scene(new Group());
TabPane tabPane = new TabPane();
Tab tab1 = new Tab("Tab 1");
tabPane.getTabs().add(tab1);
Tab tab2 = new Tab("Tab 2");
tabPane.getTabs().add(tab2);
table.setEditable(true);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
firstNameCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>() {
#Override
public void handle(CellEditEvent<Person, String> t) {
((Person) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setFirstName(t.getNewValue());
}
}
);
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
lastNameCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>() {
#Override
public void handle(CellEditEvent<Person, String> t) {
((Person) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setLastName(t.getNewValue());
}
}
);
TableColumn emailCol = new TableColumn("Email");
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
emailCol.setCellFactory(TextFieldTableCell.forTableColumn());
emailCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>() {
#Override
public void handle(CellEditEvent<Person, String> t) {
((Person) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setEmail(t.getNewValue());
}
}
);
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
final VBox vbox = new VBox();
vbox.getChildren().addAll(tabPane, table);
((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);
}
}
}
Your code structure is already setup correctly. You just need to add Nodes to the different Tabs
Key Code: You need to add a root node to each Tab. Each root node will hold the other nodes that give each Tab it looks.
Tab tab1 = new Tab("Tab 1");
Label tab1Label = new Label("Use tab1Root to add nodes for tab1!");
StackPane tab1Root = new StackPane(tab1Label);
tab1Root.setPrefSize(500, 500);
tab1.setContent(tab1Root);
tabPane.getTabs().add(tab1);
Tab tab2 = new Tab("Tab 2");
Button tab2Button = new Button("Press Me!");
tab2Button.setOnAction((event) -> {
System.out.println("Use tab2Root to add nodes for tab2!");
});
StackPane tab2Root = new StackPane(tab2Button);
tab2Root.setPrefSize(500, 500);
tab2.setContent(tab2Root);
tabPane.getTabs().add(tab2);
Full Code
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeTableColumn.CellEditEvent;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestingGround 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"));
public static void main(String[] args)
{
launch(args);
}
public void start(Stage stage)
{
Scene scene = new Scene(new Group());
TabPane tabPane = new TabPane();
Tab tab1 = new Tab("Tab 1");
Label tab1Label = new Label("Use tab1Root to add nodes for tab1!");
StackPane tab1Root = new StackPane(tab1Label);
tab1Root.setPrefSize(500, 500);
tab1.setContent(tab1Root);
tabPane.getTabs().add(tab1);
Tab tab2 = new Tab("Tab 2");
Button tab2Button = new Button("Press Me!");
tab2Button.setOnAction((event) -> {
System.out.println("Use tab2Root to add nodes for tab2!");
});
StackPane tab2Root = new StackPane(tab2Button);
tab2Root.setPrefSize(500, 500);
tab2.setContent(tab2Root);
tabPane.getTabs().add(tab2);
table.setEditable(true);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
firstNameCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>()
{
#Override
public void handle(CellEditEvent<Person, String> t)
{
// ((Person) t.getTableView().getItems().get(
// t.getTablePosition().getRow())).setFirstName(t.getNewValue());
}
}
);
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
lastNameCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>()
{
#Override
public void handle(CellEditEvent<Person, String> t)
{
// ((Person) t.getTableView().getItems().get(
// t.getTablePosition().getRow())).setLastName(t.getNewValue());
}
}
);
TableColumn emailCol = new TableColumn("Email");
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
emailCol.setCellFactory(TextFieldTableCell.forTableColumn());
emailCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>()
{
#Override
public void handle(CellEditEvent<Person, String> t)
{
// ((Person) t.getTableView().getItems().get(
// t.getTablePosition().getRow())).setEmail(t.getNewValue());
}
}
);
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
final VBox vbox = new VBox();
vbox.getChildren().addAll(tabPane, table);
((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);
}
}
}
I'm attempting to make TableView behave like Excel. I am having trouble selected the correct cells.
In Excel, if you select a column(say 5 adjacent cells in the column) and then you click SHIFT + LEFT, excel will automatically select all corresponding left most cell.
e.g.
Say in Excel I have [A1][A2][A3] selects and then I click SHIFT + RIGHT, know the selected cells would be:
[A1][B1][A2][B2][A3][B3]
How can I achieve similar behavior with a TableView.
I've tried doing something like the following with no luck.
// Table view
TableView tv = new TableView();
// Some more code goes here
// Select right most element
tv.getSelectionModel().selectRightCell();
The problem with selectRightCell() or selectLeftCell() function is that it selects just a single cell (to the left or right of the selected cell) not the all left or right cell of the selected cells.
Here is sample code below, you can select by dragging by mouse or by pressing control+arrow keys.
import com.sun.javafx.scene.control.behavior.TableCellBehavior;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.util.Arrays;
public class DragSelectionTable 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));
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
TableColumn<Person, String> emailCol = new TableColumn<>("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));
final Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory = new DragSelectionCellFactory();
firstNameCol.setCellFactory(cellFactory);
lastNameCol.setCellFactory(cellFactory);
emailCol.setCellFactory(cellFactory);
table.setEditable(true);
table.setItems(data);
table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol));
table.getSelectionModel().setCellSelectionEnabled(true);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
table.addEventHandler(KeyEvent.KEY_RELEASED, new ControlDownSelectionEventHandler());
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
public class DragSelectionCellFactory implements Callback<TableColumn<Person, String>, TableCell<Person, String>> {
#Override
public TableCell<Person, String> call(final TableColumn<Person, String> col) {
return new DragSelectionCell();
}
}
public class DragSelectionCell extends TableCell<Person, String> {
public DragSelectionCell() {
setOnDragDetected(new DragDetectedEventHandler(this));
setOnMouseDragEntered(new DragEnteredEventHandler(this));
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
setText(item);
}
}
}
public class DragDetectedEventHandler implements EventHandler<MouseEvent> {
TableCell<Person, String> tableCell;
public DragDetectedEventHandler(TableCell<Person, String> tableCell) {
this.tableCell = tableCell;
}
#Override
public void handle(final MouseEvent event) {
tableCell.startFullDrag();
}
}
public class DragEnteredEventHandler implements EventHandler<MouseDragEvent> {
TableCell<Person, String> tableCell;
public DragEnteredEventHandler(TableCell<Person, String> tableCell) {
this.tableCell = tableCell;
}
#Override
public void handle(final MouseDragEvent event) {
performSelection(tableCell.getTableView(), tableCell.getTableColumn(), tableCell.getIndex());
}
}
public class ControlDownSelectionEventHandler implements EventHandler<KeyEvent> {
#Override
public void handle(final KeyEvent event) {
KeyCode code = event.getCode();
if (event.isShiftDown() && (KeyCode.UP.equals(code) || KeyCode.DOWN.equals(code) || KeyCode.LEFT.equals(code) || KeyCode.RIGHT.equals(code))) {
int index = table.getFocusModel().getFocusedCell().getRow();
TableColumn column = table.getFocusModel().getFocusedCell().getTableColumn();
performSelection(table, column, index);
}
}
}
protected void performSelection(TableView<Person> table, TableColumn<Person, String> column, int index) {
final TablePositionBase anchor = TableCellBehavior.getAnchor(table, table.getFocusModel().getFocusedCell());
int columnIndex = table.getVisibleLeafIndex(column);
int minRowIndex = Math.min(anchor.getRow(), index);
int maxRowIndex = Math.max(anchor.getRow(), index);
TableColumnBase minColumn = anchor.getColumn() < columnIndex ? anchor.getTableColumn() : column;
TableColumnBase maxColumn = anchor.getColumn() >= columnIndex ? anchor.getTableColumn() : column;
table.getSelectionModel().clearSelection();
final int minColumnIndex = table.getVisibleLeafIndex((TableColumn) minColumn);
final int maxColumnIndex = table.getVisibleLeafIndex((TableColumn) maxColumn);
for (int _row = minRowIndex; _row <= maxRowIndex; _row++) {
for (int _col = minColumnIndex; _col <= maxColumnIndex; _col++) {
table.getSelectionModel().select(_row, table.getVisibleLeafColumn(_col));
}
}
table.getFocusModel().focus(index, column);
}
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);
}
}
}
Right now I have dialog show up at the mouse position when an row was selected in the tableview.
I'm looking to have the dialog show up when I hover over each row, there seems to be a CSS :hover so I assume it can be caught in java code in some capacity.
You can create a custom table row factory which adds a listener to the hover property of the row and takes action when the hover status changes.
Here is some sample code which updates a label as the user hovers over table rows:
table.setRowFactory(tableView -> {
final TableRow<Person> row = new TableRow<>();
row.hoverProperty().addListener((observable) -> {
final Person person = row.getItem();
if (row.isHover() && person != null) {
label.setText("Address Book: "
+ person.getFirstName() + " "
+ person.getLastName()
);
} else {
label.setText("Address Book");
}
});
return row;
});
In the sample image the mouse pointer (not shown) is hovered over the row for Emma Jones, so the title header is modified to read "Address Book: Emma Jones"
Here is a complete sample adopted from the Oracle JavaFX TableView tutorial sample code:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.*;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TableViewSample 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) {
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<>("firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<>("lastName"));
TableColumn<Person, String> emailCol = new TableColumn<>("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<>("email"));
table.setRowFactory(tableView -> {
final TableRow<Person> row = new TableRow<>();
row.hoverProperty().addListener((observable) -> {
final Person person = row.getItem();
if (row.isHover() && person != null) {
label.setText(
"Address Book: "
+ person.getFirstName() + " "
+ person.getLastName()
);
} else {
label.setText("Address Book");
}
});
return row;
});
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
final VBox vbox = new VBox(10);
vbox.setPadding(new Insets(10));
vbox.getChildren().addAll(label, table);
Scene scene = new Scene(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);
}
}
}
I have two TableView (table1 and table2) one next to the other
What I need to do is:
When you select an item in table1 the corresponding item is selected in table2
So far so good was easy, but I need to reproduce the same effect in table2, and it is when
arises the NPE the listener applied in table1 conflict with the listener of table2.
I tried to create an event in focusedProperty () but without success :(
I made a test application to post here, as it would not fit all code follows
download link TableView - Teste.
This feels like it might be a bug, but I don't have time to experiment with it properly. A workaround seems to be to update the selection in the "other" table inside a Platform.runLater(). You need to be careful not to create an infinite number of these calls by checking the selection really is different:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class TwoTableTest extends Application {
private ChangeListener<Number> table1SelectionListener ;
private ChangeListener<Number> table2SelectionListener ;
#Override
public void start(Stage primaryStage) {
TableView<Person> table1 = createTableView() ;
TableView<Person> table2 = createTableView() ;
table1.getSelectionModel().select(0);
table2.getSelectionModel().select(0);
table1SelectionListener = (obs, oldIndex, newIndex) -> {
int table1SelectedIndex = table1.getSelectionModel().getSelectedIndex() ;
int table2SelectedIndex = table2.getSelectionModel().getSelectedIndex() ;
if (table1SelectedIndex != table2SelectedIndex) {
Platform.runLater(() -> table2.getSelectionModel().select(table1SelectedIndex));
}
};
table2SelectionListener = (obs, oldIndex, newIndex) -> {
int table1SelectedIndex = table1.getSelectionModel().getSelectedIndex() ;
int table2SelectedIndex = table2.getSelectionModel().getSelectedIndex() ;
if (table1SelectedIndex != table2SelectedIndex) {
Platform.runLater(() -> table1.getSelectionModel().select(table2SelectedIndex));
}
};
table1.getSelectionModel().selectedIndexProperty().addListener(table1SelectionListener);
table2.getSelectionModel().selectedIndexProperty().addListener(table2SelectionListener);
HBox root = new HBox(5, table1, table2);
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableView<Person> createTableView() {
TableView<Person> table = new TableView<>();
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setCellValueFactory(data -> data.getValue().firstNameProperty());
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setCellValueFactory(data -> data.getValue().lastNameProperty());
TableColumn<Person, String> emailCol = new TableColumn<>("Email");
emailCol.setCellValueFactory(data -> data.getValue().emailProperty());
table.getColumns().addAll(firstNameCol, lastNameCol);
table.getItems().addAll(
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")
);
return table ;
}
public static void main(String[] args) {
launch(args);
}
public static class Person {
private final StringProperty firstName;
private final StringProperty lastName;
private final StringProperty email ;
Person(String firstName, String lastName, String email) {
this.firstName = new SimpleStringProperty(this, "firstName",
firstName);
this.lastName = new SimpleStringProperty(this, "lastName", lastName);
this.email = new SimpleStringProperty(this, "email", email);
}
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;
}
public String getEmail() {
return email.get();
}
public void setEmail(String email) {
this.email.set(email);
}
public StringProperty emailProperty() {
return email ;
}
#Override
public String toString() {
return firstName.get() + " " + lastName.get();
}
}
}