Problem
One of the most basic tasks associated with tables is to copy / paste data from table cells. JavaFX TableView does not support it out of the box.
Question
How do you access table cells instead of data objects to paste clipboard data into selected cells?
the code
Here is what I got so far:
TableUtils.java
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
public class TableUtils {
public static void installCopyPasteHandler(TableView<?> table) {
table.setOnKeyPressed(new TableKeyEventHandler());
}
public static class TableKeyEventHandler implements EventHandler<KeyEvent> {
KeyCodeCombination copyKeyCodeCompination = new KeyCodeCombination(KeyCode.C, KeyCombination.CONTROL_ANY);
KeyCodeCombination pasteKeyCodeCompination = new KeyCodeCombination(KeyCode.V, KeyCombination.CONTROL_ANY);
public void handle(final KeyEvent keyEvent) {
if (copyKeyCodeCompination.match(keyEvent)) {
if( keyEvent.getSource() instanceof TableView) {
copySelectionToClipboard( (TableView<?>) keyEvent.getSource());
keyEvent.consume();
}
}
else if (pasteKeyCodeCompination.match(keyEvent)) {
if( keyEvent.getSource() instanceof TableView) {
pasteClipboard( (TableView<?>) keyEvent.getSource());
keyEvent.consume();
}
}
}
}
public static void copySelectionToClipboard(TableView<?> table) {
StringBuilder clipboardString = new StringBuilder();
ObservableList<TablePosition> positionList = table.getSelectionModel().getSelectedCells();
int prevRow = -1;
for (TablePosition position : positionList) {
int row = position.getRow();
int col = position.getColumn();
Object cell = (Object) table.getColumns().get(col).getCellData(row);
if (cell == null) {
cell = "";
}
if (prevRow == row) {
clipboardString.append('\t');
} else if (prevRow != -1) {
clipboardString.append('\n');
}
String text = cell.toString();
clipboardString.append(text);
prevRow = row;
}
final ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putString(clipboardString.toString());
Clipboard.getSystemClipboard().setContent(clipboardContent);
System.out.println( "Clipboard string: " + clipboardContent);
}
public static void pasteClipboard(TableView<?> table) {
TablePosition focusedCellPosition = table.getFocusModel().getFocusedCell();
System.out.println("Pasting into cells starting at " + focusedCellPosition);
String pasteString = Clipboard.getSystemClipboard().getString();
System.out.println(pasteString);
Pattern pattern = Pattern.compile("([^\t]*)\t([^\t]*)\t([^\n]*)(\n)?");
Matcher matcher = pattern.matcher(pasteString);
while (matcher.find()) {
System.out.println(matcher.group(1) + "," + matcher.group(2) + "," + matcher.group(3));
}
}
}
TableCopyCellsDemo.java
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class TableCopyCellsDemo extends Application {
private final ObservableList<Person> data = FXCollections.observableArrayList(new Person("Jacob", "Smith", 18), new Person("Isabella", "Johnson", 19), new Person("Ethan", "Williams", 20), new Person("Michael", "Brown", 21));
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
stage.setWidth(500);
stage.setHeight(550);
TableColumn<Person, String> firstNameCol = new TableColumn<Person, String>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<Person, String>("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
TableColumn<Person, Integer> ageCol = new TableColumn<Person, Integer>("Age");
ageCol.setMinWidth(60);
ageCol.setCellValueFactory(new PropertyValueFactory<Person, Integer>("age"));
TableView<Person> table = new TableView<>();
table.setPlaceholder(new Text("No content in table"));
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, ageCol);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 10, 10, 10));
BorderPane borderPane = new BorderPane();
borderPane.setCenter(table);
vbox.getChildren().addAll(borderPane);
vbox.getChildren().add( new Label( "Select cells and press CTRL+C. Paste the data into Excel or Notepad"));
Scene scene = new Scene(vbox);
stage.setScene(scene);
stage.show();
table.getSelectionModel().setCellSelectionEnabled(true);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
TableUtils.installCopyPasteHandler(table);
}
public static class Person {
private final StringProperty firstName;
private final StringProperty lastName;
private final IntegerProperty age;
private Person(String fName, String lName, Integer age) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.age = new SimpleIntegerProperty(age);
}
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final java.lang.String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final java.lang.String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final java.lang.String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final java.lang.String lastName) {
this.lastNameProperty().set(lastName);
}
public final IntegerProperty ageProperty() {
return this.age;
}
public final int getAge() {
return this.ageProperty().get();
}
public final void setAge(final int age) {
this.ageProperty().set(age);
}
}
}
The problem is TODO in the pasteClipboard method. You can copy the data of the selected cells to the clipboard using the CTRL + the C . Using CTRL + V, you get data from the clipboard and analyze it. But I have not yet found a means to write data directly to the table.
Many thanks!