如何用 ComboBox 填充 table 列单元格并观察?

How to populate table column cells with ComboBox and observe?

我的 table 视图有 2 列。第一个有我的对象的名称,第二个我想要一个 ComboBox,其值来自我的对象属性列表。

对 ComboBox 的任何更改都会将其 selected 属性更改为用户选择的列表元素。

例如:

| Name          | Choices           |
|---------------|-------------------|
| Object 1 Name | Object 1 ComboBox |
| Object 2 Name | Object 2 ComboBox |

到目前为止,我已经设法填充了名称,但我仍然停留在选择列中。

MyObject 模型:

public class MyObject {

    // Objects name is the filename
    private File file; 
    // Selection from the ComboBox that is populated with infoList elements
    private SomeInfo selectedInfo; 

    private List<SomeInfo > infoList;

    ... getter/setter

控制器:

@FXML
private TableView<MyObject> myObjectTableView;
@FXML
private TableColumn<MyObject, String> myObjectNameTableColumn, myObjectChoicesTableColumn;

private void populateTableView(List<MyObject> myObjectList) {
    ObservableList<MyObject> myObjectObservableList = FXCollections.observableList(myObjectList);
    myObjectTableView.setItems(myObjectObservableList);
    myObjectNameTableColumn.setCellValueFactory(c -> new SimpleStringProperty(c.getValue().getFile().getName()));
}

你的 myObjectChoicesTableColumn 类型有误。你需要

@FXML
private TableColumn<MyObject, List<SomeInfo>> myObjectChoicesTableColumn ;

那么你的cell value factory可以是

myObjectChoicesTableColumn.setCellValueFactory(cellData -> 
    new SimpleObjectProperty<>(cellData.getValue().getInfoList()));

要显示组合框,您需要一个单元工厂:

myObjectChoicesTableColumn.setCellFactory(col -> {

    ComboBox<SomeInfo> combo ;

    TableCell<MyObject, List<SomeInfo>> cell = new TableCell<MyObject, List<SomeInfo>>() {
        @Override
        protected void updateItem(List<SomeInfo> info, boolean empty) {
            super.updateItem(info, empty);
            if (empty) {
                setGraphic(null);
            } else {
                MyObject rowItem = myObjectTableView.getItems().get(getIndex());
                combo.getItems().setAll(info);
                combo.setValue(rowItem.getSelectedInfo());
                setGraphic(combo);
            }
        }
    };

    combo.valueProperty().addListener((obs, oldValue, newValue) -> 
        myObjectTableView.getItems().get(cell.getIndex()).setSelectedInfo(newValue));

    return cell ;
}

您可能会发现重构模型更清晰,因此您可以将列表和所选项目包装在新的 class:

public class SelectableInfo {
    private final ObservableList<SomeInfo> infoList = FXCollections.observableArrayList() ;

    private SomeInfo selectedInfo ;

    public ObservableList<SomeInfo> getInfoList() {
        return infoList ;
    }

    public SomeInfo getSelectedInfo() {
        return selectedInfo ;
    }

    public void setSelectedInfo(SomeInfo info) {
        selectedInfo = info ;
    }
}

public class MyObject {
    private File file ;
    private SelectableInfo selectableInfo ;

    // getters and setters...
}

那么你会得到更简单的:

@FXML
private TableColumn<MyObject, SelectableInfo> myObjectChoicesTableColumn ;

myObjectChoicesTableColumn.setCellValueFactory(cellData -> new SimpleObjectProperty<>(cellData.getValue().getSelectableInfo());

myObjectChoicesTableColumn.setCellFactory(col -> {
    ComboBox<SomeInfo> combo = new ComboBox<>();
    TableCell<MyObject, SelectableInfo> cell = new TableCell<MyObject, SelectableInfo>() {
        @Override
        protected void updateItem(SelectableInfo info, boolean empty) {
            super.updateItem(info, empty) ;
            if (empty) {
                setGraphic(null);
            } else {
                combo.setItems(info.getInfoList());
                combo.setValue(info.getSelectedInfo());
                setGraphic(combo);
            }
        }
    };
    combo.valueProperty().addListener((obs, oldValue, newValue) -> 
        cell.getItem().setSelectedInfo(newValue));
    return cell ;
});