使用JAVAFX在TableView中粘贴文本数据

时间:2017-04-19 11:48:41

标签: javafx tableview

我有TableView通过单个单元格编辑接受数据。现在我还想通过粘贴文件来输入数据,如下所示。

11.12    23.32   15.43
22.23    24.45   26.65

我想使用说CTRL+V来粘贴数据。我已经看过post in StackOverflowthe GIT repo等帖子。我无法粘贴多行数据。

这里我给出了主要代码。

package testmatrix;

import javafx.application.Application;
import javafx.collections.*;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class TestMATRIX extends Application {
TableView<CommonDataClass> matrixData = new TableView<CommonDataClass>();
final ObservableList<CommonDataClass> matData = FXCollections.
        observableArrayList();
TableColumn[] matrixDataColumns = new TableColumn[6];
int numColVal = 0;
int theNDX = 0;
int maxRowNum = 0;
TextField TC1 = new TextField();
TextField TC2 = new TextField();
TextField TC3 = new TextField();
TextField TC4 = new TextField();
TextField TC5 = new TextField();
TextField TC6 = new TextField();
boolean numColStatus = false;
int oldRowVal = 0;
int oldColVal = 0;
boolean newRow = false;
boolean newCol = false;

@Override
public void start(Stage primaryStage) {
    final BorderPane root = new BorderPane();

    TextField myTextField = new TextField();
    Label colL = new Label("Column Number->");
    TextField colNumT = new TextField();
    Button getNum = new Button("SET");
    colNumT.setMaxWidth(40);
    TableUtils.doCopyPasteHandler (matrixData, matData);
    matrixData.setVisible(true);
    matrixData.setEditable(true);
    matrixData.getSelectionModel().setCellSelectionEnabled(true);
    matrixData.getSelectionModel ().setSelectionMode (SelectionMode.MULTIPLE);

    HBox hb1 = new HBox();
    HBox hb2 = new HBox();
    hb1.getChildren().add(matrixData);
    hb2.getChildren().addAll(colL, colNumT, getNum);

    root.setCenter(hb1);
    root.setRight(hb2);
    getNum.addEventHandler(ActionEvent.ACTION, e -> {
        numColStatus = (colNumT.getText().isEmpty()) ? false : true;
        numColVal = (numColStatus) ? Integer.parseInt(colNumT.getText()): 0;

        if (numColStatus) {
            addRowBelow();
            matrixData.getColumns ().clear ();
            for (int ii = 0; ii < numColVal; ii++) {
                matrixDataColumns[ii] = createCol(ii);
                editCommit(ii);
            }
            matrixData.setItems(matData);
            if (numColStatus) {
                for (int ii = 0; ii < numColVal; ii++) {
                    matrixData.getColumns().add(matrixDataColumns[ii]);
                }
            }
            matrixData.refresh();
        }
    });
    Scene scene = new Scene(root, 1200, 400);
    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

TableColumn<CommonDataClass, String> createCol(int icol) {
    TableColumn<CommonDataClass, String> column = new TableColumn<>();
    column.setMinWidth(30);
    column.setStyle(
            "-fx-alignment: CENTER-RIGHT;-fx-font-family: monospace; -fx-font-size: 10px; ");
    String nameC = "myD" + (icol + 1);
    System.out.println("colName->" + nameC);
    column.setCellValueFactory(
            new PropertyValueFactory<CommonDataClass, String>(nameC));

    column.setCellFactory(
            new DragSelectionCellFactory<CommonDataClass, String>(TextFieldTableCell.forTableColumn()
            )
    );
    column.setMinWidth(120);
    return column;
}

private void editCommit(int ii) {
    System.out.println("Command came here");
    matrixDataColumns[ii].setOnEditCommit(
            new EventHandler<CellEditEvent<CommonDataClass, String>>() {
        @Override
        public void handle(CellEditEvent<CommonDataClass, String> event) {
            int colNum = event.getTablePosition().getColumn();
            switch (colNum) {
                case 0:
                    event.getTableView().getItems().get(event.getTablePosition().getRow()).setMyD1(event.getNewValue());
                    break;
                case 1:
                    event.getTableView().getItems().get(event.getTablePosition().getRow()).setMyD2(event.getNewValue());
                    break;
                case 2:
                    event.getTableView().getItems().get(event.getTablePosition().getRow()).setMyD3(event.getNewValue());
                    break;
                case 3:
                    event.getTableView().getItems().get(event.getTablePosition().getRow()).setMyD4(event.getNewValue());
                    break;
                case 4:
                    event.getTableView().getItems().get(event.getTablePosition().getRow()).setMyD5(event.getNewValue());
                    break;
                case 5:
                    event.getTableView().getItems().get(event.getTablePosition().getRow()).setMyD6(event.getNewValue());
                    break;
            }
            matrixData.setItems(matData);
            matrixData.refresh();               
            if (!event.getNewValue().isEmpty()) {
                addRowBelow();
            }
        }
    });
}

void addRowBelow() {
    matData.add(new CommonDataClass(
            TC1.getText(), TC2.getText(), TC3.getText(),
            TC4.getText(), TC5.getText(), TC6.getText()
    ));
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}

这里我展示了TableView的数据结构。

package testmatrix;
import javafx.beans.property.*;

public class CommonDataClass {

private final SimpleStringProperty myD1;
private final SimpleStringProperty myD2;
private final SimpleStringProperty myD3;
private final SimpleStringProperty myD4;
private final SimpleStringProperty myD5;
private final SimpleStringProperty myD6;

public CommonDataClass(String myStr1, String myStr2, String myStr3, String myStr4, String myStr5, String myStr6) {
    this.myD1 = new SimpleStringProperty(myStr1);
    this.myD2 = new SimpleStringProperty(myStr2);
    this.myD3 = new SimpleStringProperty(myStr3);
    this.myD4 = new SimpleStringProperty(myStr4);
    this.myD5 = new SimpleStringProperty(myStr5);
    this.myD6 = new SimpleStringProperty(myStr6);
}

public String getMyD1(){
    return myD1.get();
}
public String getMyD2(){
    return myD2.get();
}
public String getMyD3(){
    return myD3.get();
}
public String getMyD4(){
    return myD4.get();
}
public String getMyD5(){
    return myD5.get();
}
public String getMyD6(){
    return myD6.get();
}
public void setMyD1(String myStr){
    myD1.set(myStr);
}
public void setMyD2(String myStr){
    myD2.set(myStr);
}
public void setMyD3(String myStr){
    myD3.set(myStr);
}
public void setMyD4(String myStr){
    myD4.set(myStr);
}
public void setMyD5(String myStr){
    myD5.set(myStr);
}
public void setMyD6(String myStr){
    myD6.set(myStr);
}


public StringProperty dataNameProperty(int index) {
    StringProperty strProp = null;

    switch (index) {
        case 0:
            strProp = myD1;
            break;
        case 1:
            strProp = myD2;
            break;
        case 2:
            strProp = myD3;
            break;
        case 3:
            strProp = myD4;
            break;
        case 4:
            strProp = myD5;
            break;
        case 5:
            strProp = myD6;
            break;
    }
    return strProp;
}
}

我在这里给出了DrageSelection单元格的代码。

package testmatrix;
import javafx.scene.control.TableCell;
import javafx.scene.input.*;

public class DragSelectionCell extends TableCell<CommonDataClass, String> {

public DragSelectionCell() {
    setOnDragDetected ((MouseEvent event) -> {
        startFullDrag ();
        getTableColumn ().getTableView ().getSelectionModel ().select (
                getIndex (), getTableColumn ());
    });
    setOnMouseDragEntered ((MouseDragEvent event) -> {
        getTableColumn ().getTableView ().getSelectionModel ().select (
                getIndex (), getTableColumn ());
    });
}

@Override
public void updateItem(String item, boolean empty) {
    super.updateItem (item, empty);
    if ( empty ) {
        setText (null);
    } else {
        setText (item);
    }
}
}

我在这里给出DragSelectionCellfactory代码。

package testmatrix;
import javafx.scene.control.*;
import javafx.util.Callback;


public class DragSelectionCellFactory<CommonDataClass, String> implements
    Callback<TableColumn<CommonDataClass, String>, TableCell<CommonDataClass, String>> {

private final Callback<TableColumn<CommonDataClass, String>, TableCell<CommonDataClass, String>> factory;

public DragSelectionCellFactory(
        Callback<TableColumn<CommonDataClass, String>, TableCell<CommonDataClass, String>> factory) {
    this.factory = factory;
}

public DragSelectionCellFactory() {
    this (col -> new TableCell<CommonDataClass, String> () {
        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem (item, empty);
            if ( empty || item == null ) {
                setText (null);
            } else {
                setText (item.toString ());
            }
        }
    });
}

@Override
public TableCell<CommonDataClass, String> call(
        final TableColumn<CommonDataClass, String> col) {
    TableCell<CommonDataClass, String> cell = factory.call (col);
    cell.setOnDragDetected (event -> {
        cell.startFullDrag ();
        col.getTableView ().getSelectionModel ().select (cell.getIndex (),
                col);
    });
    cell.setOnMouseDragEntered (event -> {
        col.getTableView ().getSelectionModel ().select (cell.getIndex (),
                col);
    });

    cell.setOnMouseEntered (e -> {
        String item = cell.getItem ();
        if ( item != null ) {
        }
    });

    return cell;
}
}

以下代码块描述类似于开头所述的复制/粘贴例程的表实用程序。但是,粘贴部分不起作用,所以我试图修改。现在我完全糊涂了。复制部分正在复制,而上面引用中显示的粘贴部分无法粘贴所有行和列。

package testmatrix;
import java.util.StringTokenizer;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.*;
import javafx.event.EventHandler;
import javafx.scene.control.*;
import javafx.scene.input.*;

public class TableUtils extends TableCell<CommonDataClass, String> {
ObservableList<CommonDataClass> datTab = FXCollections.
        observableArrayList ();

public static void doCopyPasteHandler(TableView<?> table,
        ObservableList<CommonDataClass> myData) {

    table.setOnKeyPressed (new TableKeyEventHandler ());
}

public static class TableKeyEventHandler implements EventHandler<KeyEvent> {
    KeyCodeCombination copyCode = new KeyCodeCombination (KeyCode.C,
            KeyCodeCombination.CONTROL_ANY);
    KeyCodeCombination pasteCode = new KeyCodeCombination (KeyCode.V,
            KeyCodeCombination.CONTROL_ANY);

    //@Override
    public void handle(KeyEvent event) {
        if ( copyCode.match (event) ) {
            if ( event.getSource () instanceof TableView ) {
                copySelection2Clipboard ((TableView<?>) event.getSource ());  // this will copy to clipboard
                event.consume (); // After using event please consume
            }
        } else if ( pasteCode.match (event) ) {
            if ( event.getSource () instanceof TableView ) {
                pasteFromClipboard ((TableView<?>) event.getSource ());
                event.consume ();
            }
        }
    }
}

public static void copySelection2Clipboard(TableView<?> table) {
    StringBuilder clipboardString = new StringBuilder ();
    ObservableList<TablePosition> positionList = table.getSelectionModel ().
            getSelectedCells ();
    int prevRow = -1;
    for ( TablePosition pos : positionList ) {
        int row = pos.getRow ();
        int col = pos.getColumn ();
        if ( prevRow == row ) {    // determine whether we advance in a row or col (newline)
            clipboardString.append ('\t');
        } else if ( prevRow != -1 ) {
            clipboardString.append ('\n');
        }
        String text = "";
        Object obsValue = (Object) table.getColumns ().get (col).
                getCellObservableValue (row);
        if ( obsValue == null ) {
            text = "";
        } else if ( obsValue instanceof StringProperty ) {
            text = ((StringProperty) obsValue).get ();
        } else {
            System.out.println ("Unsupported observable value: " + obsValue);
        }
        clipboardString.append (text);
        prevRow = row;
    }
    ClipboardContent clipboardContent = new ClipboardContent ();
    clipboardContent.putString (clipboardString.toString ());
}


public static void pasteFromClipboard(TableView<?> table) {
    if ( table.getSelectionModel ().getSelectedCells ().size () == 0 ) {
        return;
    }
    TablePosition pasteCellPosition = table.getSelectionModel ().
            getSelectedCells ().get (0);     // get cell position at start
    String pasteString = Clipboard.getSystemClipboard ().getString ();
    StringTokenizer rowTokenizer = new StringTokenizer (pasteString, "\n");
    int rowNum = rowTokenizer.countTokens () + 1;
    int rowCB = -1;
    while (rowTokenizer.hasMoreTokens ()) {
        rowCB++;
        String rowString = rowTokenizer.nextToken ();
        StringTokenizer colTokenizer = new StringTokenizer (rowString, "\t");
        int colCB = -1;
        while (colTokenizer.hasMoreTokens ()) {
            colCB++;
            String clpCellCont = colTokenizer.nextToken ();
            int rowTable = pasteCellPosition.getRow () + rowCB;
            int colTable = pasteCellPosition.getColumn () + colCB;
            if ( rowTable >= table.getItems ().size () ) {
                continue;
            }
            if ( colTable >= table.getColumns ().size () ) {
                continue;
            }

            TableColumn tabCol = table.getVisibleLeafColumn (colTable);
            ObservableValue obsVal = tabCol.
                    getCellObservableValue (rowTable);               
        }

    }
}

}

如果我得到任何帮助,那将会有很大的帮助。谢谢和问候

1 个答案:

答案 0 :(得分:1)

由于事件处理程序中没有代码,因此无法插入值。

此外,您不使用属性,这会使事情变得更复杂。

如果您使用属性

TableColumn<CommonDataClass, String> createCol(int icol) {
    ...
    column.setCellValueFactory(
            cd -> cd.getValue().dataNameProperty(icol));

您可以使用属性分配新值:

public static <T> void pasteFromClipboard(TableView<T> table) {
    if (table.getSelectionModel().getSelectedCells().isEmpty()) {
        return;
    }
    TablePosition pasteCellPosition = table.getSelectionModel().
            getSelectedCells().get(0);     // get cell position at start

    Clipboard cb = Clipboard.getSystemClipboard();

    // check, if clipboard contains a string
    if (!cb.hasString()) {
        return;
    }

    String pasteString = cb.getString();
    String[][] values = Stream.of(pasteString.split("\r?\n"))
            .map(line -> line.split("\t")).toArray(String[][]::new);

    final int offsetY = pasteCellPosition.getRow();
    final int offsetX = pasteCellPosition.getColumn();
    final int maxY = Math.min(table.getItems().size() - offsetY, values.length);
    final int colMax = table.getColumns().size() - offsetX;

    for (int y = 0; y < maxY; y++) {
        String[] r = values[y];
        final int maxX = Math.min(colMax, r.length);
        T rowObject = table.getItems().get(y+offsetY);
        for (int x = 0; x < maxX; x++) {
            Object property = table.getColumns().get(x + offsetX).getCellObservableValue(rowObject);
            if (property instanceof StringProperty) {
                // write value using the property
                ((StringProperty) property).set(r[x]);
            }
        }
    }
}

这只会将值插入现有行...

但请注意,您应该在DragSelectionCellFactory类中使用命名约定,即使用单个字母作为类型参数的名称。在您的情况下,类型参数名为CommonDataClassString,即现有类的名称,这几乎肯定会导致混淆......
可能你应该删除类型参数:

public class DragSelectionCellFactory implements
    Callback<TableColumn<CommonDataClass, String>, TableCell<CommonDataClass, String>> {

此外,复制内容无效,因为您忘记设置剪贴板内容:

ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putString(clipboardString.toString());
Clipboard.getSystemClipboard().setContent(clipboardContent);

此外,无法保证所选单元格位于矩形区域内。可以通过按住 Ctrl 来任意选择单元格。

另外

getNum.addEventHandler(ActionEvent.ACTION, e -> {...});

可以(并且在这种情况下,恕我直言)应该用

替换
getNum.setOnAction(e -> {...});