Javafx IllegalArgumentException:Children:添加了重复的子项

时间:2016-05-27 03:38:08

标签: java javafx illegalargumentexception

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

有3个主要类别:

  1. WindowTease:加载舞台并调用loadTable()方法
  2. InventoryController:标准的fxml控制器,并包含通用的loadTable()方法
  3. InventoryCell:我用于每列的setcellfactory()。

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

  4. 这是我的控制器:

    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);

1 个答案:

答案 0 :(得分:2)

它被称为单元格工厂,而不是单元格容器,原因如下:

TableView使用cellFactory的{​​{1}}来创建节点以显示列的数据。对于显示的每一行,都会执行一次。

如果现在每次返回相同的TableColumn实例,稍后当TableCell的{​​{1}}最终组装布局时,最终会达到这样的情况:

Skin

不允许使用,因为TableView不得在场景图中多次包含。

因此,您必须确保为工厂的每次调用都返回不同的SomeParent | |--TableRow1 | | | |--InventoryCell1 | |--TableRow2 | |--InventoryCell1 实例。

InventoryCell1

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

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

TableCell
loadTable