How to copy / paste table cells in TableView

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 {

    /**
     * Install the keyboard handler:
     *   + CTRL + C = copy to clipboard
     *   + CTRL + V = paste to clipboard
     * @param table
     */
    public static void installCopyPasteHandler(TableView<?> table) {

        // install copy/paste keyboard handler
        table.setOnKeyPressed(new TableKeyEventHandler());

    }

    /**
     * Copy/Paste keyboard event handler.
     * The handler uses the keyEvent source for the clipboard data. The source must be of type TableView.
     */
    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) {

                    // copy to clipboard
                    copySelectionToClipboard( (TableView<?>) keyEvent.getSource());

                    // event is handled, consume it
                    keyEvent.consume();

                }

            } 
            else if (pasteKeyCodeCompination.match(keyEvent)) {

                if( keyEvent.getSource() instanceof TableView) {

                    // copy to clipboard
                    pasteClipboard( (TableView<?>) keyEvent.getSource());

                    // event is handled, consume it
                    keyEvent.consume();

                }

            } 

        }

    }

    /**
     * Get table selection and copy it to the clipboard.
     * @param table
     */
    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);

            // null-check: provide empty string for nulls
            if (cell == null) {
                cell = "";
            }

            // determine whether we advance in a row (tab) or a column
            // (newline).
            if (prevRow == row) {

                clipboardString.append('\t');

            } else if (prevRow != -1) {

                clipboardString.append('\n');

            }

            // create string from cell
            String text = cell.toString();

            // add new item to clipboard
            clipboardString.append(text);

            // remember previous
            prevRow = row;
        }

        // create clipboard content
        final ClipboardContent clipboardContent = new ClipboardContent();
        clipboardContent.putString(clipboardString.toString());

        // set clipboard content
        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));

            // TODO: what now? how to paste the data?  

        }

    }


}

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);

        // create table columns
        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();

        // enable multi-selection
        table.getSelectionModel().setCellSelectionEnabled(true);
        table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

        // enable copy/paste
        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!

+4
1

, , . : .

, , , .

. , . - , , .

        // get cell
        TableColumn tableColumn = table.getColumns().get(colIndex);
        ObservableValue observableValue = tableColumn.getCellObservableValue(rowIndex);

        if( observableValue instanceof StringProperty) { 

            ((StringProperty) observableValue).set(clipboardCellContent);

        }

, paste :

public static void pasteClipboard( TableView<?> table) {

    // abort if there not cell selected to start with
    if( table.getSelectionModel().getSelectedCells().size() == 0) {
        return;
    }

    // get the cell position to start with
    TablePosition pasteCellPosition = table.getSelectionModel().getSelectedCells().get(0);

    System.out.println("Pasting into cell " + pasteCellPosition);

    String pasteString = Clipboard.getSystemClipboard().getString();

    System.out.println(pasteString);

    int rowClipboard = -1;

    StringTokenizer rowTokenizer = new StringTokenizer( pasteString, "\n");
    while( rowTokenizer.hasMoreTokens()) {

        rowClipboard++;

        String rowString = rowTokenizer.nextToken();

        StringTokenizer columnTokenizer = new StringTokenizer( rowString, "\t");

        int colClipboard = -1;

        while( columnTokenizer.hasMoreTokens()) {

            colClipboard++;

            // calculate the position in the table cell
            int rowTable = pasteCellPosition.getRow() + rowClipboard;
            int colTable = pasteCellPosition.getColumn() + colClipboard;

            // skip if we reached the end of the table
            if( rowTable >= table.getItems().size()) {
                continue;
            }
            if( colTable >= table.getColumns().size()) {
                continue;
            }

            String clipboardCellContent = columnTokenizer.nextToken();

            // System.out.println( rowClipboard + "/" + colClipboard + ": " + cell);

            // get cell
            TableColumn tableColumn = table.getColumns().get(colTable);
            ObservableValue observableValue = tableColumn.getCellObservableValue(rowTable);

            System.out.println( rowTable + "/" + colTable + ": " +observableValue);

            // TODO: handle double, etc
            if( observableValue instanceof StringProperty) { 

                ((StringProperty) observableValue).set(clipboardCellContent);

            }
            else if( observableValue instanceof IntegerProperty) { 

                int value;
                try {
                    value = NumberFormat.getInstance().parse(clipboardCellContent).intValue();
                    ((IntegerProperty) observableValue).set(value);
                } catch (ParseException e) {
                    e.printStackTrace();
                }

            }
        }

    }

}

.

+3

All Articles