JavaFX表格单元格编辑

JavaFX表格单元格编辑,java,javafx,tableview,scenebuilder,Java,Javafx,Tableview,Scenebuilder,我正在尝试用Java编写一个程序来管理我的博彩帐户。我是java新手,所以我想我应该选择一些简单的东西来看看它是如何工作的。我决定使用tableview并使单个单元格可编辑。我一直在学习这个教程。它详细介绍了如何使用java代码来实现这一点,并将其复制到一个新类中。因为我喜欢Sceneviewer,所以我决定尝试调整它以与FXML一起使用。我的问题是,数据被加载到表中,但当我单击/双击单元格时,什么也没有发生。这是我的密码 testController.java import javafx.co

我正在尝试用Java编写一个程序来管理我的博彩帐户。我是java新手,所以我想我应该选择一些简单的东西来看看它是如何工作的。我决定使用tableview并使单个单元格可编辑。我一直在学习这个教程。它详细介绍了如何使用java代码来实现这一点,并将其复制到一个新类中。因为我喜欢Sceneviewer,所以我决定尝试调整它以与FXML一起使用。我的问题是,数据被加载到表中,但当我单击/双击单元格时,什么也没有发生。这是我的密码

testController.java

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.util.Callback;

import java.net.URL;
import java.util.ResourceBundle;

public class testController implements Initializable {

@FXML
private TableColumn<Account, String> usernameCol;

@FXML
private TableColumn<Account, String> balanceCol;

@FXML
private TableView<Account> accountTable;

@FXML
private TableColumn<Account, String> bookieCol;

@FXML
private TableColumn<Account, String> passwordCol;

private ObservableList<Account> dataList =
        FXCollections.observableArrayList(
                new Account("bookie", "username", "password", "0"));


@Override
public void initialize(URL location, ResourceBundle resources) {
    Callback<TableColumn, TableCell> cellFactory =
            new Callback<TableColumn, TableCell>() {
                public TableCell call(TableColumn p) {
                    return new EditingCell();
                }
            };

    bookieCol.setCellValueFactory(
            new PropertyValueFactory<>("fieldBookie"));

    usernameCol.setCellValueFactory(
            new PropertyValueFactory<>("fieldUsername"));

    usernameCol.setOnEditCommit(
            new EventHandler<TableColumn.CellEditEvent<Account, String>>() {
                @Override public void handle(TableColumn.CellEditEvent<Account, String> t) {
                    ((Account)t.getTableView().getItems().get(
                            t.getTablePosition().getRow())).setFieldUsername(t.getNewValue());
                }
            });

    passwordCol.setCellValueFactory(
            new PropertyValueFactory<Account, String>("fieldPassword"));

    balanceCol.setCellValueFactory(
            new PropertyValueFactory<Account, String>("fieldBalance"));

    accountTable.setItems(dataList);

}

class EditingCell extends TableCell<Account, String> {

    private TextField textField;

    public EditingCell() {
    }

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

        if (textField == null) {
            createTextField();
        }

        setGraphic(textField);
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        textField.selectAll();
    }

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

        setText(String.valueOf(getItem()));
        setContentDisplay(ContentDisplay.TEXT_ONLY);
    }

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

        if (empty) {
            setText(null);
            setGraphic(textField);
        } else {
            if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setGraphic(textField);
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            } else {
                setText(getString());
                setContentDisplay(ContentDisplay.TEXT_ONLY);
            }
        }
    }

    private void createTextField() {
        textField = new TextField(getString());
        textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
        textField.setOnKeyPressed(t -> {
            if (t.getCode() == KeyCode.ENTER) {
                commitEdit(textField.getText());
            } else if (t.getCode() == KeyCode.ESCAPE) {
                cancelEdit();
            }
        });
    }

    private String getString() {
        return getItem() == null ? "" : getItem();
    }
}
}
最后,这里是我的fxml文件

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.canvas.*?>
<?import java.lang.*?>
<?import javafx.scene.*?>

<Group xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="testController">
   <children>
      <TableView fx:id="accountTable" editable="true" prefHeight="291.0" prefWidth="302.0">
        <columns>
          <TableColumn fx:id="bookieCol" prefWidth="75.0" text="Bookie" />
          <TableColumn fx:id="usernameCol" prefWidth="75.0" text="Username" />
            <TableColumn fx:id="passwordCol" prefWidth="75.0" text="Password" />
            <TableColumn fx:id="balanceCol" prefWidth="75.0" text="Balance" />
        </columns>
      </TableView>
   </children>
</Group>

正如我前面所说的,当我点击Username单元格时,什么也没有发生。没有错误,没有文本字段,什么都没有。
任何帮助都将不胜感激!谢谢

我没有试过你的例子,但我想你只是忘记了为特定列设置cellFactory。添加以下行应该可以解决此问题:

usernameCol.setCellFactory(cellFactory);

您可以使用:
TextFieldTableCell.forTableColumn()将textField添加到编辑单元格中
如果需要comboBox,请尝试:
ComboBoxTableCell.forTableColumn(列表)

//文本字段:
usernameCol.setCellFactory(TextFieldTableCell.forTableColumn());
//组合框:
ObservableList=FXCollections.observableArrayList();
列表。添加(“名称1”);
列表。添加(“名称2”);
列表。添加(“名称3”);
列表。添加(“名称4”);
回调cbtc=
ComboBoxTableCell.forTableColumn(列表);
usernameCol.setCellFactory(cbtc);

如果有人需要一个工作示例,我可以通过添加

usernameCol.setCellFactory(
                TextFieldTableCell.forTableColumn());
并将
usernameCol.setOnEditCommit
更改为

usernameCol.setOnEditCommit(
                (TableColumn.CellEditEvent<Account, String> t) ->
                    ( t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setFieldUsername(t.getNewValue())
                );

这是正确的,但是您还需要修复类型(
Callback
etc)。这种方法有点传统:您可以执行
usernameCol.setCellFactory(TextFieldTableCell.forTableColumn())
然后扔掉
编辑单元
好的,谢谢,我现在就试试。关于javafx和可编辑表的教程不多,遗憾的是:(这不是很好,但涵盖了基础知识。它工作得很好,我也删除了编辑单元格类!代码更少,对我来说更容易理解!谢谢两者。@OrdinaryDraft您可能想看看这里:。我面临着同样的挑战,不幸的是,这不是一件容易实现的事情。不确定是否有更好的方法,但kleopatra能够提供体面的解决方案。
usernameCol.setOnEditCommit(
                (TableColumn.CellEditEvent<Account, String> t) ->
                    ( t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setFieldUsername(t.getNewValue())
                );
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;

import java.net.URL;
import java.util.ResourceBundle;

public class testController implements Initializable {

    @FXML
    private TableColumn<Account, String> usernameCol;

    @FXML
    private TableColumn<Account, String> balanceCol;

    @FXML
    private TableView<Account> accountTable;

    @FXML
    private TableColumn<Account, String> bookieCol;

    @FXML
    private TableColumn<Account, String> passwordCol;

    private ObservableList<Account> dataList =
            FXCollections.observableArrayList(
                    new Account("bookie", "username", "password", "0"));


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        bookieCol.setCellValueFactory(
                new PropertyValueFactory<>("fieldBookie"));

        usernameCol.setCellValueFactory(
                new PropertyValueFactory<>("fieldUsername"));

        usernameCol.setCellFactory(
                TextFieldTableCell.forTableColumn());

        usernameCol.setOnEditCommit(
                (TableColumn.CellEditEvent<Account, String> t) ->
                    ( t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setFieldUsername(t.getNewValue())
                );

        passwordCol.setCellValueFactory(
                new PropertyValueFactory<Account, String>("fieldPassword"));

        balanceCol.setCellValueFactory(
                new PropertyValueFactory<Account, String>("fieldBalance"));

        accountTable.setItems(dataList);

    }
}