2016-05-27 2 views
-1

Я не могу понять, почему ошибка повторяющихся детей появляется, даже когда я добавляю только один контент в таблицу.Javafx IllegalArgumentException: Children: Duplicate children added

Есть 3 основных класса:

  1. WindowTease: который загружает сцену и вызывает метод loadTable()
  2. InventoryController: стандартный контроллер FXML, и содержит общий loadTable() метод
  3. InventoryCell : который я использую для setcellfactory() для каждого столбца.

    Вызванный: java.lang.IllegalArgumentException: Дети: дублирующие дети добавил: родитель = TableRow @ 6c41701f [styleClass = ячейка индексированных ячейки таблицы строк ячейки] 'нулевой'

Вот мой контроллер:

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 
} 

и, наконец, я nventoryCell расширяет 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); 
     } 
    } 
} 

Update: Виновником определенно tablecolumn.setCellFactory(cellfactory);

+0

ли ваш метод пуска перейти в primaryStage? –

+0

да ..sry, я забыл добавить, что при копировании – rjbaj

+0

, как правило, фрагменты недостаточно хороши ... что действительно нужно, это SSCCE, который демонстрирует проблему ;-) Так что просто угадать: Component.getNode() может быть виновником, то есть узлом который добавляется несколько раз в сцену? – kleopatra

ответ

2

Это называется клетка завод, не клеточными Контейнер по причине:

TableView использует cellFactory из это TableColumn s для создания узлов для отображения данных для столбца. Это делается один раз для каждой отображаемой строки.

Если теперь возвращает тот же экземпляр TableCell каждый раз, в более позднем, когда Skin из TableView наконец компонует макет какой-то момент, некоторые ситуации, как это будет в конечном итоге будет достигнуто:

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

good catch +1 :-) – kleopatra

+0

вот что я думал о fabian. Благодарю. – rjbaj