【问题标题】:Calling cancelEdit to all cells in a TableView JavaFx对 TableView JavaFx 中的所有单元格调用 cancelEdit
【发布时间】:2016-09-01 17:42:34
【问题描述】:

我正在使用我已经研究了一段时间的自定义可编辑表格单元格工厂。我目前正在实现一个允许单击开始编辑的功能。

我单击开始单元格编辑,但是如果您单击另一个单元格一次,前一个单元格不会关闭。我的想法是在打开单击的单元格进行编辑之前遍历所有调用 cancelEdit() 的单元格。

下面是我正在使用的整个单元格类(双击编辑可以正常工作)我正在处理的部分在构造函数中。

public class EditingCell<S, T> extends TableCell<S, T> {
    private TextField textField;

    public EditingCell() {
        TableView<S> table = this.getTableView();
        addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                for(TableColumn<S, ?> col : table.getColumns()) {
                    // cancelEdit() on all cells here
                }
                startEdit();
            }
        });
    }

    public void commit(Object val) {
        commit(val, this.getTableRow().getIndex(), getTableView().getColumns().indexOf(this.getTableColumn()));
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public void commit(Object val, int row, int col) {

        // Get the table
        TableView<S> t = this.getTableView();

        // Get the selected row/column
        S selectedRow = t.getItems().get(row);
        if (selectedRow == null)
            return;
        TableColumn<S, ?> selectedColumn = t.getColumns().get(col);

        // Get current property name
        String propertyName = ((PropertyValueFactory) selectedColumn.getCellValueFactory()).getProperty();

        // Create a method name conforming to java standards ( setProperty )
        propertyName = ("" + propertyName.charAt(0)).toUpperCase() + propertyName.substring(1);

        // Try to run the update
        try {

            // Type specific checks - could be done inside each
            // setProperty() method
            if (val instanceof Double) {
                Method method = selectedRow.getClass().getMethod("set" + propertyName, double.class);
                method.invoke(selectedRow, (double) val);
            }
            if (val instanceof String) {
                Method method = selectedRow.getClass().getMethod("set" + propertyName, String.class);
                method.invoke(selectedRow, (String) val);
            }
            if (val instanceof Integer) {
                Method method = selectedRow.getClass().getMethod("set" + propertyName, int.class);
                method.invoke(selectedRow, (int) val);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        // CommitEdit for good luck
        commitEdit((T) val);

        TableUtils.Refresh(t, t.getItems());

    }

    @Override
    public void startEdit() {
        if (!isEmpty()) {
            super.startEdit();
            createTextField();
            setText(null);
            setGraphic(textField);
            textField.selectAll();
        }
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();

        String val = "0.0";
        if (!textField.getText().equals(""))
            val = "" + Double.parseDouble(textField.getText());

        setText(NumberUtils.roundTo2(NumberUtils.parseDouble(val)) + "");
        setGraphic(null);

    }

    @Override
    public void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);

        if (empty) {
            setText("");
            setGraphic(null);
        } else {
            if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setText(null);
                setGraphic(textField);
            } else {
                setText(NumberUtils.roundTo3(NumberUtils.parseDouble(getString())) + "");
                setGraphic(null);
            }
        }
    }

    @SuppressWarnings({ "rawtypes" })
    private void createTextField() {
        textField = new TextField(getString());

        textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
        textField.focusedProperty().addListener(new ChangeListener<Boolean>() {

            @Override
            public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
                if (!arg2) {
                    if (textField.getText().equals(""))
                        commit(0.0);
                    else {
                        double val = Double.parseDouble(textField.getText());
                        commit(val);
                    }
                }
            }
        });
        textField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
            if (event.getCode() == KeyCode.ESCAPE) {
                textField.setText("" + getItem());
                cancelEdit();
                event.consume();
            }
            // Navigate up and down in table
            else if (event.getCode() == KeyCode.ENTER) {

                TableView<S> table = getTableView();
                int row = table.getEditingCell().getRow();

                // Commit changes
                if (textField.getText().equals(""))
                    commit(0.0);
                else {
                    double val = Double.parseDouble(textField.getText());
                    commit(val);
                }

                // Do move
                if (event.isShiftDown())
                    table.edit(row - 1, getTableColumn());
                else {
                    table.edit(row + 1, getTableColumn());
                }

            }

            // Move left and right in table
            else if (event.getCode() == KeyCode.TAB) {
                TableView<S> table = getTableView();
                int row = table.getEditingCell().getRow();

                // Save changes
                if (textField.getText().equals(""))
                    commit(0.0);
                else {
                    double val = Double.parseDouble(textField.getText());
                    commit(val);
                }

                ArrayList<TableColumn<S, ?>> cols = new ArrayList<TableColumn<S, ?>>();
                int index = 0;
                for (TableColumn<S, ?> c : table.getColumns()) {
                    if (c.isVisible() && c.isEditable())
                        cols.add(c);
                    if (c == getTableColumn())
                        index = cols.size() - 1;
                }

                // Do move
                if (event.isShiftDown()) {
                    try {
                        TableColumn<S, ?> prevCol = cols.get(index - 1);
                        table.edit(row, prevCol);
                    } catch (Exception e) {
                    }
                } else {
                    try {
                        TableColumn<S, ?> nextCol = cols.get(index + 1);
                        table.edit(row, nextCol);
                    } catch (Exception e) {
                    }
                }
            }
        });
        textField.setTextFormatter(new TextFormatter<String>((Change c) -> {
            String text = c.getText();

            TableView<S> table = getTableView();
            if (table.getSelectionModel().getSelectedCells().size() == 0) {
                return c;
            }
            TablePosition pasteCellPosition = table.getSelectionModel().getSelectedCells().get(0);
            int clipRow = 0;
            int clipCol = 0;

            String curCellText = text;

            if (text.contains("\t") || text.contains("\n")) {

                StringTokenizer row = new StringTokenizer(text, "\n");
                boolean hasRun = false;

                while (row.hasMoreTokens() || !hasRun) {
                    String r = row.nextToken();
                    StringTokenizer col;
                    if (r != null)
                        col = new StringTokenizer(r, "\t");
                    else
                        col = new StringTokenizer(text, "\t");

                    hasRun = true;
                    clipCol = 0;

                    while (col.hasMoreTokens()) {

                        String content = col.nextToken();

                        if (clipRow == 0 && clipCol == 0) {
                            curCellText = content;
                        }

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

                        // Skip hidden columns before current cell
                        for (int i = 0; i < colTable; i++)
                            if (!table.getColumns().get(i).isVisible())
                                colTable++;

                        // Skip hidden columns between current and goal
                        while (!table.getColumns().get(colTable).isVisible()) {
                            if (colTable >= table.getColumns().size())
                                break;
                            colTable++;
                        }

                        // Add row if we reach the end
                        if (rowTable >= table.getItems().size()) {
                            if (table.getItems().get(0) instanceof EditableTableRow)
                                ((EditableTableRow) table.getItems().get(0)).addRowToTable(table);

                            // continue;
                        }
                        if (colTable >= table.getColumns().size()) {

                            continue;
                        }

                        try {
                            double val = Double.parseDouble(content);
                            commit(val, rowTable, colTable);

                        } catch (Exception e) {
                            try {
                                int val = Integer.parseInt(content);
                                commit(val, rowTable, colTable);
                            } catch (Exception e2) {
                                commit(content, rowTable, colTable);
                            }
                        }

                        clipCol++;
                    }

                    clipRow++;
                }
            }
            c.setText(curCellText);

            return c;
        }));
        textField.requestFocus();
        textField.selectAll();
    }

    private String getString() {
        return getItem() == null ? "" : getItem().toString();
    }
}

【问题讨论】:

  • 您没有使用TextFieldTableCell 类有什么原因吗?
  • 主要原因-我刚刚发现存在.....但是,我想我会保持原样,因为我对功能进行了很多更改(例如修剪显示数字与实际数字并从 excel 粘贴)

标签: java javafx tableview


【解决方案1】:

您不能遍历所有单元格;您无法知道创建了哪些单元格,代表实际项目等。

你可以打电话

getTableView().edit(-1, null);

这将具有取消编辑的效果。 (请参阅Javadocs。)实际上打电话可能会更好

getTableView().edit(getIndex(), getTableColumn());

而不是调用startEdit()。这将(应该?我还没有测试过......)为您调用startEdit()。换句话说,做

public EditingCell() {
    addEventFilter(MouseEvent.MOUSE_CLICKED, e -> 
        getTableView().edit(getIndex(), getTableColumn()));
}

顺便说一句,你为什么要费尽心思让单元实现非常通用,然后假设单元值工厂是PropertyValueFactory 的一个实例?当然,您可以使用

获得单元格可观察值
ObservableValue<T> obs = getTableColumn().getCellObservableValue(getTableView().getItems().get(getIndex()));

然后就做

if (obs instanceof WritableValue) {
    ((WritableValue<?>) obs).setValue(val);
}

【讨论】:

  • 感谢您对编辑的建议,我会尝试的。我对 JavaFx 不太熟悉,无法了解所有最佳实践,所以我只使用了我的第一个工作解决方案。我把一切都保持得非常笼统,因为我在大约 20 个不同的表上使用了这个表单元格,所有表都有不同的行类。
  • 什么是获得我想要调用编辑的单元格位置的好方法? (在我调用startEdit的同一个构造函数中)
  • PropertyValueFactory 本身就是一种传统和不良做法。在我们有 lambda 表达式之前,它只是作为一个便利类编写的,它提供了一种类型安全的方式来指定列的属性,几乎没有额外的冗长:myColumn.setCellValueFactory(cellData -&gt; cellData.getValue().someProperty());。不过,要回答您的问题,只需使用我显示的代码:表格单元格中的getIndex() 给出行的索引,getTableColumn() 给出表格列:这些正是TableView.edit(...) 需要的参数。
  • 顺便说一句,不要假设调用构造函数时在单元格上设置了表格视图:在处理程序中调用getTableView(),而不是直接在构造函数中。
  • 哦,好的,谢谢,这完全符合预期。我还将更改为 PropertyValueFactory 以跟上惯例。感谢您的帮助!
猜你喜欢
  • 2014-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-22
  • 1970-01-01
  • 1970-01-01
  • 2015-09-17
相关资源
最近更新 更多