-
-
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); | |
} | |
} | |
} | |
} |
@Jojor Thanks for asking, but just use it as you need it, there's no license, it's part of a a tutorial, i. e. an answer on StackOverflow:
https://stackoverflow.com/questions/31708840/save-table-in-clipboad-javafx
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?
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
Hi @Roland09, like @s6ch13 I'm interested to reuse this gist if the license permits it. Would you mind adding the license in the file headers ?