-
-
Save Roland09/6fb31781a64d9cb62179 to your computer and use it in GitHub Desktop.
| 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 TableCopyPasteCellsDemo 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); | |
| } | |
| } | |
| } |
| import java.text.NumberFormat; | |
| import java.text.ParseException; | |
| import java.util.StringTokenizer; | |
| import javafx.beans.property.DoubleProperty; | |
| import javafx.beans.property.IntegerProperty; | |
| import javafx.beans.property.StringProperty; | |
| import javafx.beans.value.ObservableValue; | |
| import javafx.collections.ObservableList; | |
| import javafx.event.EventHandler; | |
| import javafx.scene.control.TableColumn; | |
| 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 { | |
| private static NumberFormat numberFormatter = NumberFormat.getNumberInstance(); | |
| /** | |
| * 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's 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 | |
| pasteFromClipboard( (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(); | |
| // 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 = ""; | |
| Object observableValue = (Object) table.getColumns().get(col).getCellObservableValue( row); | |
| // null-check: provide empty string for nulls | |
| if (observableValue == null) { | |
| text = ""; | |
| } | |
| else if( observableValue instanceof DoubleProperty) { // TODO: handle boolean etc | |
| text = numberFormatter.format( ((DoubleProperty) observableValue).get()); | |
| } | |
| else if( observableValue instanceof IntegerProperty) { | |
| text = numberFormatter.format( ((IntegerProperty) observableValue).get()); | |
| } | |
| else if( observableValue instanceof StringProperty) { | |
| text = ((StringProperty) observableValue).get(); | |
| } | |
| else { | |
| System.out.println("Unsupported observable value: " + observableValue); | |
| } | |
| // 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); | |
| } | |
| public static void pasteFromClipboard( TableView<?> table) { | |
| // abort if there's 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++; | |
| // get next cell data from clipboard | |
| String clipboardCellContent = columnTokenizer.nextToken(); | |
| // 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; | |
| } | |
| // 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 boolean, etc | |
| if( observableValue instanceof DoubleProperty) { | |
| try { | |
| double value = numberFormatter.parse(clipboardCellContent).doubleValue(); | |
| ((DoubleProperty) observableValue).set(value); | |
| } catch (ParseException e) { | |
| e.printStackTrace(); | |
| } | |
| } | |
| else if( observableValue instanceof IntegerProperty) { | |
| try { | |
| int value = NumberFormat.getInstance().parse(clipboardCellContent).intValue(); | |
| ((IntegerProperty) observableValue).set(value); | |
| } catch (ParseException e) { | |
| e.printStackTrace(); | |
| } | |
| } | |
| else if( observableValue instanceof StringProperty) { | |
| ((StringProperty) observableValue).set(clipboardCellContent); | |
| } else { | |
| System.out.println("Unsupported observable value: " + observableValue); | |
| } | |
| System.out.println(rowTable + "/" + colTable); | |
| } | |
| } | |
| } | |
| } |
This approach doesn't works for embeded columns (columns containing subcolumns) because the column number you get with "int col = position.getColumn();" will be incorrect.
Table containing ColA (itself containing Col1 and Col2) then ColB (itself containing Col3 and Col4). When selecting Col4 cell, position.getcolumn() will return 3 but table.getColumns().get(col).getCellObservableValue( row) will not work as table has only 2 columns.
Example above shall be adapted to browse down embeded columns.
I used a different approach:
Object thisLineObject = table.getSelectionModel().getSelectedItems().get(0);
Allows to obtain the object associated with the row from whom property values are obtained.
ObjectProperty anObject = position.getTableColumn().cellValueFactoryProperty();
Allow to obtain the Value Factory, then
PropertyValueFactory factory = (PropertyValueFactory) anObject.getValue();
String fieldName = factory.getProperty();
Method method = thisLineObject.getClass().getMethod(fieldName);
Object methRes = method.invoke(thisLineObject);
if (methRes instanceof StringProperty) text = ((StringProperty) methRes).getValue();
For this to work, all the class used inside TableView shall provide a method with same name as field name returning a StingProperty.
Columns shall be assigned with this syntax:
column.setCellValueFactory(new PropertyValueFactory<>("BillingInvoiceNo"));
The call back syntax:
column.setCellValueFactory(cellData -> cellData.getValue().BillingInvoiceNo());
doesn't work
I have a textfield inside a table cell. When copy pasting from clipboard, it should update the value of the textfield instead of tablecell. How will you do that?