我正在两个树视图之间实现拖动和拖动。当treeItem被拖放到treeItem的另一个treeView时,在两个treeItem之间建立了一个线连接。这工作正常,但最初没有拖放事件的连接对我来说是个问题。 我正在使用treeCell进行拖放事件。
答案 0 :(得分:3)
正如我所想,事实证明这很困难。
根据设计,无法让TreeCell
属于给定的TreeItem
。这是因为"虚拟化" TreeView
的设计:创建最少数量的TreeCell
,并根据需要使用新的TreeItem
更新这些TreeCell
。因此,对于每个TreeItem
,通常不会是TreeItem
,而给定TreeCell
所代表的ObservableSet
可能会随时发生变化。
为了完成这项工作,首先要创建一个可观察的集合,存储树之间的所有连接(例如,AssignmentView
应该可以正常工作)。通过某个类来表示连接,该类公开可用于行的起点和终点。
为树创建自定义单元工厂。他们返回的细胞应该:
请注意,绑定坐标时,需要考虑单元格可能会移动的事实(例如,通过滚动或GUI布局中的其他更改)。您还需要将坐标从单元格自己的坐标系转换为坐标系统,无论哪个窗格连接到另一个窗格,显然,它们必须是两个常见的场景图的祖先。树)。
最后,你需要一些家务。连接需要确保它们变得不可见,或者如果它们不再绑定在一端或多端,则从场景中删除。
我创建了an example。我刚刚创建了一些用于生成连接的简单控件,但您可以通过拖放轻松完成此操作。封装连接视图的类是Assignment
;它使用ConnectedTrees
来表示连接的实际数据。 {{1}}类是主要的应用程序,大多数有趣的控制器类型的工作都在那里。其余的类只是数据表示。这个例子都是Java 8;我认为在JavaFX 2.2中它会更加丑陋。
答案 1 :(得分:2)
Set<Node> treeCells = tree.lookupAll(".tree-cell");
List<Node> cells = new ArrayList<>(treeCells);
int row = tree.getRow(((TreeItem) treeItem));
TreeCell cell= ((TreeCell) cells.get(row))
答案 2 :(得分:0)
此解决方案使用递归调用来遍历树视图的节点树。
通常这种递归不应该是危险的,因为只有有限的节点数(TreeCell
的实例被TreeView
重用):
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import java.util.List;
public class TreeViewExplore {
/**
* Returns a cell for the tree item given. Or null.
*
* @param treeItem tree item
* @param treeView tree view
* @return tree cell
*/
public static TreeCell findCellByItem(TreeItem treeItem, TreeView treeView) {
return recursiveFindCellByItem(treeItem, treeView);
}
private static TreeCell recursiveFindCellByItem(TreeItem treeItem, Node node) {
if (node.getStyleClass().contains("tree-cell")
&& TreeCell.class.isAssignableFrom(node.getClass())
&& ((TreeCell) node).getTreeItem() == treeItem)
return (TreeCell) node;
if (!Parent.class.isAssignableFrom(node.getClass()))
return null;
List<Node> nodes = ((Parent) node).getChildrenUnmodifiable();
if (nodes == null) return null;
for (Node n : nodes) {
TreeCell cell = recursiveFindCellByItem(treeItem, n);
if (cell != null) return cell;
}
return null;
}
}
用法:
// TreeItem treeItem = ...
TreeCell cell = TreeViewExplore.findCellByItem(treeItem, treeView);
// Check result:
System.out.println(
cell == null ? "cell is null" :
"(cell.getTreeItem() == treeItem) = "
+ (cell.getTreeItem() == treeItem));
使用lookupAll()
方法的另一种解决方案。这只是在这里,因为它看起来对我来说非常有效,因为这个方法收集所有给定CSS选择器的节点(并且在任何情况下遍历整个树):
public static TreeCell findCellByItem(TreeItem treeItem, TreeView treeView) {
return (TreeCell) treeView.lookupAll(".tree-cell").stream()
.filter(n -> ((TreeCell) n).getTreeItem() == treeItem)
.findFirst()
.orElse(null);
}