对于我正在开发的应用程序,我有一个带有(我自己的类型)TreeItems的TreeView。一切正常,我可以按预期显示项目。
现在,我希望能够处理将一个项目从此TreeView拖到应用程序窗口的另一部分,并使其在此执行某些操作。我现在面临两个(至少……)问题:
我尝试过的一些方法:
TreeView鼠标事件为我提供以下信息:
没有单元格单击: MouseEvent [source = TreeView[id=templateTreeView, styleClass=tree- view], target = TreeViewSkin$1@32a37c7a[styleClass=cell indexed-cell tree- cell]'null', eventType = MOUSE_PRESSED, consumed = false, x = 193.0, y = 289.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = TreeViewSkin$1@32a37c7a[styleClass=cell indexed-cell tree-cell]'null', point = Point3D [x = 192.0, y = 8.0, z = 0.0], distance = 1492.820323027551]
单击带有文本“属性”的单元格: MouseEvent [source = TreeView[id=templateTreeView, styleClass=tree-view], target = TreeViewSkin$1@16aa9102[styleClass=cell indexed-cell tree-cell]'Attributes', eventType = MOUSE_PRESSED, consumed = false, x = 76.0, y = 34.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = TreeViewSkin$1@16aa9102[styleClass=cell indexed-cell tree-cell]'Attributes', point = Point3D [x = 75.0, y = 13.0, z = 0.0], distance = 1492.820323027551]
我猜这个秘密在PickResult的Node中,但是从那里我仍然看不到如何到达TreeItem。
希望对此有一个简单的答案…
您犯了过早优化的罪过:)。
TreeCell
基本上只为中的 当前可见
项创建TreeView
。当您展开或折叠树中的节点时,或者在滚动时,这些TreeCell
s被重用以显示不同的TreeItem
s。这是updateItem(...)
和中类似方法的目的TreeCell
;当该TreeCell
实例显示的项目更改时,将调用它们。
TreeCell
我的系统上的A 高约1/4英寸;要显示100,000 TreeCell
秒,将需要一台超过2,000英尺/
630米高的显示器。那时,您可能比一些额外的侦听器有更严重的内存分配问题…。但是无论如何,仅当特定单元格上发生事件时,才会调用侦听器,并且与单元本身,因此,除非您有任何直接的证据在单元上注册侦听器(如您所观察到的那样,可大大降低代码复杂性),否则会对性能产生不利影响,因此应使用“每个单元侦听器”方法。
这是一个树的示例,其中包含1,000,000个Integer
值的树项。它跟踪TreeCell
创建的s
的数量(在我的系统上,我设置的窗口大小似乎从未超过20)。它还显示一个标签。您可以将值从树中拖到标签上,标签将显示在那里滴下的所有值的总计。
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TreeViewNoSelection extends Application {
private static int cellCount = 0 ;
private final DataFormat objectDataFormat = new DataFormat("application/x-java-serialized-object");
@Override
public void start(Stage primaryStage) {
TreeView<Integer> tree = new TreeView<>();
tree.setShowRoot(false);
Task<TreeItem<Integer>> buildTreeTask = new Task<TreeItem<Integer>>() {
@Override
protected TreeItem<Integer> call() throws Exception {
TreeItem<Integer> treeRoot = new TreeItem<>(0);
IntStream.range(1, 10).mapToObj(this::createItem)
.forEach(treeRoot.getChildren()::add);
return treeRoot ;
}
private TreeItem<Integer> createItem(int value) {
TreeItem<Integer> item = new TreeItem<>(value);
if (value < 100_000) {
for (int i = 0; i < 10; i++) {
item.getChildren().add(createItem(value * 10 + i));
}
}
return item ;
}
};
tree.setCellFactory(tv -> new TreeCell<Integer>() {
{
System.out.println("Cells created: "+(++cellCount));
setOnDragDetected(e -> {
if (! isEmpty()) {
Dragboard db = startDragAndDrop(TransferMode.COPY);
ClipboardContent cc = new ClipboardContent();
cc.put(objectDataFormat, getItem());
db.setContent(cc);
Label label = new Label(String.format("Add %,d", getItem()));
new Scene(label);
db.setDragView(label.snapshot(null, null));
}
});
}
@Override
public void updateItem(Integer value, boolean empty) {
super.updateItem(value, empty);
if (empty) {
setText(null);
} else {
setText(String.format("%,d", value));
}
}
});
IntegerProperty total = new SimpleIntegerProperty();
Label label = new Label();
label.textProperty().bind(total.asString("Total: %,d"));
label.setOnDragOver(e ->
e.acceptTransferModes(TransferMode.COPY));
// in real life use a CSS pseudoclass and external CSS file for the background:
label.setOnDragEntered(e -> label.setStyle("-fx-background-color: yellow;"));
label.setOnDragExited(e -> label.setStyle(""));
label.setOnDragDropped(e -> {
Dragboard db = e.getDragboard();
if (db.hasContent(objectDataFormat)) {
Integer value = (Integer) db.getContent(objectDataFormat);
total.set(total.get() + value);
e.setDropCompleted(true);
}
});
BorderPane.setMargin(label, new Insets(10));
label.setMaxWidth(Double.MAX_VALUE);
label.setAlignment(Pos.CENTER);
BorderPane root = new BorderPane(new Label("Loading..."));
buildTreeTask.setOnSucceeded(e -> {
tree.setRoot(buildTreeTask.getValue());
root.setCenter(tree);
root.setBottom(label);
});
primaryStage.setScene(new Scene(root, 250, 400));
primaryStage.show();
Thread t = new Thread(buildTreeTask);
t.setDaemon(true);
t.start();
}
public static void main(String[] args) {
launch(args);
}
}
对于选择问题:我会问你为什么要这样做;这会带来不寻常的用户体验。问题可能在于,管理选择的“内置”事件处理程序在定义的处理程序之前被调用,因此在您使用该事件时,选择已被更改。您可以尝试添加事件过滤器:
cell.addEventFilter(MouseEvent.MOUSE_PRESSED, Event::consume);
但这也会禁用扩展/折叠树中的节点。
因此,您可以尝试以下操作:
cell.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
if (getTreeItem() != null) {
Object target = e.getTarget();
if (target instanceof Node && ((Node)target).getStyleClass().contains("arrow")) {
getTreeItem().setExpanded(! getTreeItem().isExpanded());
}
}
e.consume();
});
在这一点上,它开始看起来像是骇客。
如果要完全禁用选择,则另一个选择可能是为树创建自定义选择模型,该模型总是返回空选择。
对于我正在开发的应用程序,我有一个带有(我自己类型的)TreeItems的TreeView。这是工作良好的,我得到的项目显示的预期。 我现在想要能够处理拖动一个项目从这个树视图到应用程序窗口的另一部分,并让它在那里执行一些操作。我现在面临两个(至少……)问题: null null TreeView鼠标事件提供以下信息: 未单击单元格: 单击了文本“Attributes”的单元格:
问题内容: 我正在尝试使用treeView创建菜单。这是我第一次使用treeView,并且已经在多个网站上进行了阅读。 我在进行动作事件时遇到一些问题。我想要做的基本上是在用户单击树形视图中的某个节点时触发并发生事件,到目前为止,我有以下内容: 不幸的是,这似乎不起作用。 有什么方法可以在不更改类型的情况下将甚至添加到单个项目? 问题答案: 根据JavaFX 2.2文档 : “..A TreeIt
注意:我实际上不确定为什么这种情况首先需要监听器,因为我甚至不想经常监听,而是在调用方法时得到结果。
我使用本教程在JavaFX2中创建了自己的TreeView。但是,我想隐藏我的根节点。 现在看起来是什么样子: null null null null 谢谢,木木
有人能举一个简单的例子来说明如何设置EventHandler以在窗格(JavaFX)上拖动图像视图。对于拖动,我的意思是在图像上按下鼠标,拖动和图像应该跟随,然后释放鼠标,图像视图将停止在该位置。
我尝试在我的JavaFX应用程序中实现一个TreeView。但不幸的是,没有项目显示,但我找不到一个问题。我搜索了一些例子,并像他们一样做了。 这是我的控制器代码: 我的FXML代码: