从ObservableList
移除项目时会触发change event,其中getFrom()
会提供删除位置,getRemoved()
会显示已删除的项目列表。 The documentation说:
getRemoved()
方法返回已从列表中替换或删除的元素列表。
没有这样说,但我暗示项目列表是原始列表中的连续子列表。我已经用这个假设编写了很多代码,但现在我遇到了TreeTableView
's selection model的困难,并没有那样做。
以一个简单的树表为例,它包含三个" Node"行。如果我选择那三行...
...然后单击并选择中间行...
... treeTableView.getSelectionModel().getSelectedItems()
上触发的更改事件如下所示:
{ [TreeItem [ value: Node 1 ], TreeItem [ value: Node 3 ]] removed at 0, }
在单个更改事件中,它会报告"节点1"和"节点3"已从selectedItems
列表的索引0中删除。
我原本希望Change
对象有两个由next()
调用分隔的单独删除事件。第一次拨打next()
会告诉我"节点1"在索引0处被删除,第二次调用next()
会告诉我"节点3"在索引1处被删除了。但是,不,我得到一个事件,同时列出两行。
getRemoved()
能否真正返回非连续项?这是我对列表更改事件如何工作的误解,还是TreeTableView
中的错误?
通常我不会责怪标准库,但这不是我在JavaFX中发现的第一个错误,所以它不是不可想象的。
如果我添加对setShowRoot(false)
的调用,则行为会发生变化。我得到了我所期望的,删除分为两部分:
{ [TreeItem [ value: Node 1 ]] removed at 0, [TreeItem [ value: Node 3 ]] removed at 1, }
另外,这是我的{{3}}:
import java.util.*;
import javafx.application.*;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.stage.*;
public class TreeTableSelectionEvents extends Application {
public void start(Stage stage) {
// Root node.
TreeItem<String> root = new TreeItem<>("Root");
root.setExpanded(true);
root.getChildren().setAll(Arrays.asList(
new TreeItem<>("Node 1"),
new TreeItem<>("Node 2"),
new TreeItem<>("Node 3")
));
// Single column.
TreeTableColumn<String, String> column = new TreeTableColumn<>("Column");
column.setPrefWidth(150);
column.setCellValueFactory((TreeTableColumn.CellDataFeatures<String, String> p) -> {
return new ReadOnlyStringWrapper(p.getValue().getValue());
});
// Tree table.
TreeTableView<String> table = new TreeTableView<>(root);
table.getColumns().add(column);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
// table.setShowRoot(false);
table.getSelectionModel().getSelectedItems().addListener(
(ListChangeListener.Change<? extends TreeItem<String>> change) -> {
System.out.printf("item change = %s, list is now %s%n", change, change.getList());
}
);
table.getSelectionModel().getSelectedIndices().addListener(
(ListChangeListener.Change<? extends Integer> change) -> {
System.out.printf("index change = %s, list is now %s%n", change, change.getList());
}
);
// Stage.
stage.setScene(new Scene(table));
stage.show();
}
}
答案 0 :(得分:1)
你是对的,事件应该包含两个单独的&#39;删除&#39;变化。截至1.8.0_74,TreeTableView的选择模型似乎无可救药地被打破。它甚至与TreeView的选择模型不一致,后者也很复杂(但不那么简单)。有太多的失败模式,现有的错误和回归错误,如果Oracle意识到问题,很难说。我建议提交另一个错误。下面的代码提供了一个适合播放功能的沙盒。
public class Test extends Application {
public void start(Stage pStage) {
pStage.setTitle("Test");
final TabPane tabPane = new TabPane();
tabPane.getTabs().addAll(
Stream.of(true, false).map(
pIsTreeTable -> {
final Tab result = new Tab(pIsTreeTable ? "TreeTableView" : "TreeView");
// create tree model
final TreeItem<String> root = new TreeItem<>("Root Node");
root.setExpanded(true);
final Collection<TreeItem<String>> children = IntStream.rangeClosed(
1, 5
).mapToObj(pIdx -> new TreeItem<>("Child Node " + pIdx)).collect(
Collectors.toList()
);
// create TreeView or TreeTableView
final Control tree;
final MultipleSelectionModel<TreeItem<String>> selectionModel;
if (pIsTreeTable) {
final TreeTableView<String> treeTableView = new TreeTableView<>(
root
);
final TreeTableColumn<String,String> column = new TreeTableColumn<>(
"Column"
);
column.setCellValueFactory(
pTreeItem -> new ReadOnlyStringWrapper(
pTreeItem.getValue().getValue()
)
);
treeTableView.getColumns().add(column);
tree = treeTableView;
selectionModel = treeTableView.getSelectionModel();
} else {
final TreeView<String> treeView = new TreeView<>(root);
tree = treeView;
selectionModel = treeView.getSelectionModel();
}
selectionModel.setSelectionMode(SelectionMode.MULTIPLE);
// add buttons
final ToggleButton childrenBtn = new ToggleButton("Children");
childrenBtn.selectedProperty().addListener(
(pObservable, pOldVal, pNewVal) -> {
if (pNewVal) {
root.getChildren().addAll(children);
} else {
root.getChildren().clear();
}
}
);
childrenBtn.setSelected(true);
final ToggleButton showRootBtn = new ToggleButton("Show Root");
showRootBtn.setSelected(true);
(
pIsTreeTable ?
((TreeTableView<?>) tree).showRootProperty() :
((TreeView<?>) tree).showRootProperty()
).bind(showRootBtn.selectedProperty());
// 'getSelectedItems()' tab
final Tab selectedItemsTab = new Tab("getSelectedItems()");
final TextArea selectedItemsTextArea = new TextArea();
selectionModel.getSelectedItems().addListener(
(ListChangeListener<TreeItem<String>>) pChange -> {
while (pChange.next()) {
if (pChange.getRemovedSize() > 0) {
selectedItemsTextArea.appendText(
"Removed " + pChange.getRemoved() + '\n'
);
}
if (pChange.getAddedSize() > 0) {
selectedItemsTextArea.appendText(
"Added " + pChange.getAddedSubList() + '\n'
);
}
}
selectedItemsTextArea.appendText(
"Selection: " + pChange.getList() + "\n\n"
);
}
);
selectedItemsTab.setContent(selectedItemsTextArea);
// 'getSelectedItem()' tab
final Tab selectedItemTab = new Tab("getSelectedItem()");
final TextArea selectedItemTextArea = new TextArea();
selectionModel.selectedItemProperty().addListener(
(pObservable, pOldVal, pNewVal) -> {
selectedItemTextArea.appendText("Selected " + pNewVal + '\n');
}
);
selectedItemTab.setContent(selectedItemTextArea);
// display selection data in text area
final TabPane selectionTabPane = new TabPane();
selectionTabPane.getTabs().addAll(selectedItemsTab, selectedItemTab);
final SplitPane splitPane = new SplitPane(
tree, new HBox(showRootBtn, childrenBtn), selectionTabPane
);
splitPane.setOrientation(Orientation.VERTICAL);
result.setContent(splitPane);
return result;
}
).collect(Collectors.toList())
);
pStage.setScene(new Scene(tabPane, 300, 450));
pStage.show();
}
public static void main(String[] pArgs) {launch(pArgs);}
}
相关(?)问题:
ListChangeListener.Change事件意味着&#34;子节点2&#34;被选中了。
&#34;子节点1&#34;被选中,但没有广播选择事件。
&#39;选择&#39; list包含null。
ListChangeListener.Change事件确实不包含删除。
既不为TreeView也不为TreeTableView广播事件。从那里,如果&#34; Show Root&#34;按下按钮,TreeView广播事件但TreeTableView没有。