我似乎无法弄清楚为什么即使我仅将一个内容添加到表中,也会显示重复添加子项的错误。

有3个主要类别:


WindowTease:加载阶段并调用loadTable()方法
InventoryController:标准fxml控制器,包含通用loadTable()方法
InventoryCell:我用来为每一列设置setcellfactory()。

引起原因:java.lang.IllegalArgumentException:子级:添加了重复的子级:parent = TableRow @ 6c41701f [styleClass = cell indexed-cell table-row-cell]'null'


这是我的控制器:

public class InventoryController {

    @FXML protected TableView mainTable;

  public <U> void loadTable(TableCell<U, Component> cellFactory){

    mainTable.getColumns().clear();

    final String[] propertyName = {"id", "invCategory", "quantity", "description", "perItem", "icon"};
    final String[] columnName = {"ID", "Category", "Quantity", "Description", "Price (Per Item)", "Process"};

    for (int i = 0; i < propertyName.length; i++) {
        TableColumn<U, Component> column = new TableColumn<>(columnName[i]);
        column.setCellValueFactory(new PropertyValueFactory<>(propertyName[i]));
        column.setCellFactory(param -> cellFactory);    //this is the culprit
        //column.setCellFactory(param -> new InventoryCell());   //this shows with no problem
        mainTable.getColumns().add(column);
    }

    ObservableList<Inventory> items = FXCollections.observableArrayList();
    mainTable.getItems().clear();

    for (int i = 0; i < 1; i++) {
        Inventory inve = new Inventory(
                new ID("WSS", i), new Describer("Click me !!"),
                new PercentQuantity(i, 100), new Describer("Click me !!"), new Price(Currency.CHINESE_YEN, i*1000.00),
                new HoverIcon("images/assignment_returned.png"));
        mainTable.getItems().add(inve);
    }

}


这是Application类:

public class WindowTease extends Application {

    @Override
    private void start(Stage primaryStage) throws Exception {
    FXMLLoader loader = new FXMLLoader());
    loader.setLocation(WindowTease.class.getResource("/layouts/inventory.fxml"));
    InventoryController controller = new InventoryController();
    loader.setController(controller);
    Parent root = loader.load();
    Scene scene = new Scene(root);

    controller.loadTable(new InventoryCell());

    primaryStage.setScene(scene);
    primaryStage.show();            //Caused by: java.lang.RuntimeException: Exception in Application start method
}


最后InventoryCell扩展了TableCell:

public class InventoryCell extends TableCell<Inventory, Component>{

    @Override
    protected void updateItem(Component item, boolean empty) {
        if (item == null || empty) return;
        super.updateItem(item, empty);
        Object node = item.getNode();
        if (node instanceof Node) {
            Node graphix = ((Node)node);
            HBox box = new HBox(graphix);
            setText("");
            setGraphic(box);

        } else if (node instanceof String) {
            setText((String)node);
            setGraphic(null);
        }
    }
}


更新:
罪魁祸首肯定是tablecolumn.setCellFactory(cellfactory);

最佳答案

由于某种原因,它被称为cellFactory,而不是cellContainer:

TableView使用其cellFactory中的TableColumn创建节点以显示列的数据。对于显示的每一行都执行一次。

如果现在每次都返回相同的TableCell实例,则在SkinTableView最终组装布局的某个时候,最终将出现以下情况:

SomeParent
    |
    |--TableRow1
    |      |
    |      |--InventoryCell1
    |
    |--TableRow2
           |
           |--InventoryCell1


这是不允许的,因为在场景图中,不得多次包含InventoryCell1

因此,您必须确保每次工厂调用都返回不同的TableCell实例。

param -> cellFactory


只会返回TableCell的实例,该实例一遍又一遍地传递给loadTable方法。

使用方法java 8引用,您可以轻松创建工厂:

public <U> void loadTable(Supplier<TableCell<U, Component>> cellFactory){
    ...
    column.setCellFactory(param -> cellFactory.get());




controller.loadTable(InventoryCell::new);

09-05 02:16