-
-
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?