Hello,
I am trying to create a List of nodes where each node contains some labels and a table. The table within each node is based on an ObservableList.
Here's my code:
final Tab scheduleTab = new Tab();
ListView cmdSeqList = new ListView();
cmdSeqList.setItems(//ObservableList of CommandSequence);
cmdSeqList.setCellFactory(new Callback<ListView<CommandSequence>, ListCell<CommandSequence>>() {
public ListCell<CommandSequence> call(ListView<CommandSequence> lv) {
final CommandSequencePane cmdSeqPane = new CommandSequencePane();
final ListCell<CommandSequence> cell = new ListCell<CommandSequence>() {
@Override
public void updateItem(CommandSequence item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
cmdSeqPane.setData(item);
setGraphic(cmdSeqPane);
}}
};
return cell;
};});
Each CommandSequence has an ObservableList of Commands that the method setData uses to populate the data within the cmdSeqPane
public class CommandSequencePane extends Group {
private Label groupIdLabel;
private Label groupIdValue;
private Label scheduledTimeLabel;
private Label scheduledTimeValue;
private Label status;
private Button actionButton;
private ImageView comments;
private Label commentsTooltip = new Label();
private Image imgNote = new Image(getClass().getResourceAsStream("/images/notes.jpg"));
VBox cmdSeqPaneContent = new VBox();
HBox cmdSeqHeader = new HBox();
TableView commandTable = new TableView();
TableColumn cmdExtID = new TableColumn();
TableColumn cmdName = new TableColumn();
TableColumn cmdAction = new TableColumn();
TableColumn cmdStatus = new TableColumn();
TableColumn cmdSource = new TableColumn();
public CommandSequencePane() {
initLayout();
this.getChildren().add(cmdSeqPaneContent);
}
private void initLayout() {
//Methods to initialize the layout of the CommandSequencePane
cmdSeqHeader.getChildren().addAll(groupIdLabel, groupIdValue, scheduledTimeLabel,
scheduledTimeValue, status, actionButton, comments, commentsTooltip);
commandTable.getColumns().addAll(cmdExtID, cmdName, cmdName, cmdStatus, cmdSource);
cmdSeqPaneContent.getChildren().addAll(cmdSeqHeader, commandTable);
}
public void setData(CommandSequence cmdSeq) {
groupIdValue.textProperty().bind(new SimpleStringProperty(Long.toString(cmdSeq.getCmdSeqId())));
Date date = new Date(Long.valueOf(cmdSeq.getCommands().get(0).getScheduledTime()));
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a");
scheduledTimeValue.textProperty().bind(new SimpleStringProperty(sdf.format(date)));
status.textProperty().bind(new SimpleStringProperty(cmdSeq.getStatus()));
commentsTooltip.textProperty().bind(new SimpleStringProperty(cmdSeq.getComment()));
commentsTooltip.getStyleClass().add("customToolTip");
commentsTooltip.setVisible(false);
System.out.println(cmdSeq.getCommands());
commandTable.setItems(cmdSeq.getCommands());
}
}
What happens when I run it is I get a "duplicate children" error:
SEVERE: javafx.scene.control.Control loadSkinClass Failed to load skin 'com.sun.javafx.scene.control.skin.TableRowSkin' for control TableRow[id=null, styleClass=cell indexed-cell table-row-cell]
java.lang.IllegalArgumentException: Children: duplicate children added parent=TableRowSkin[id=null, styleClass=cell indexed-cell table-row-cell]
at javafx.scene.Parent$1.onProposedChange(Unknown Source)
at com.sun.javafx.collections.VetoableObservableList.setAll(Unknown Source)
at com.sun.javafx.scene.control.skin.TableRowSkin.updateCells(Unknown Source)
at com.sun.javafx.scene.control.skin.TableRowSkin.<init>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at javafx.scene.control.Control.loadSkinClass(Unknown Source)
at javafx.scene.control.Control.impl_cssSet(Unknown Source)
at javafx.scene.control.Labeled.impl_cssSet(Unknown Source)
at javafx.scene.Node.impl_cssSet(Unknown Source)
at com.sun.javafx.css.StyleHelper.transitionToState(Unknown Source)
at javafx.scene.Node.impl_processCSS(Unknown Source)
at javafx.scene.Parent.impl_processCSS(Unknown Source)
at javafx.scene.control.Control.impl_processCSS(Unknown Source)
at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(Unknown Source)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(Unknown Source)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(Unknown Source)
at com.sun.javafx.scene.control.skin.VirtualFlow$3.run(Unknown Source)
at com.sun.javafx.scene.control.skin.VirtualFlow$3.run(Unknown Source)
at com.sun.javafx.scene.control.skin.PositionMapper.computeViewportOffset(Unknown Source)
at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Parent.layout(Unknown Source)
at javafx.scene.Scene.layoutDirtyRoots(Unknown Source)
at javafx.scene.Scene.doLayoutPass(Unknown Source)
at javafx.scene.Scene.access$2800(Unknown Source)
at javafx.scene.Scene$ScenePulseListener.pulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.firePulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit$10.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(Unknown Source)
at com.sun.glass.ui.win.WinApplication$2$1.run(Unknown Source)
at java.lang.Thread.run(Thread.java:662)
What is interesting is that my data, I only have 3 items to add to my cmdSeqList ListView, but the method "setData" gets called 4 times, 2x for the first element and then once each for the remaining two. It seems like the cmdSeqList ListView handles the first elements one extra time for some strange reason and adds that listcell to the ListView and so it causes problems because of duplicate children being in the ListView.
Is this a bug or is there some workaround? Is there something else that I can do to get a table within a List?
Thanks