在我关于处理dragging from a TreeView的问题中,我从James_D得到了很好的答案。这帮助我烹饪了我需要的大部分东西。
我只需要解决一个问题:在丢弃时我需要知道放置位置的确切坐标,因为这实际上决定了需要做什么。 问题是在 Doh,我完全忽略了DragEvent中的DRAG_DROPPED
事件中,没有可用的drop坐标信息。getX()
和getY()
。所以这实际上完全解决了我的问题
在我知道之前,我想过使用MOUSE_RELEASED
事件的X和Y坐标。但我发现当你在DRAG_DETECTED
处理程序(单元格)中设置Dragboard的内容时,这些坐标(以及PickResult都会出错。这对我来说就像一个错误...
我修改了James_D的示例以向您展示我的意思。
当禁用db.setContent(cc);
的行时,从TreeView拖动到例如画布上时显示的拾取结果和坐标(我在我的应用程序中拖动的内容)也很好。在启用行的情况下执行完全相同的操作会导致完全错误的PickResult ...这是一个错误,还是我在做一些愚蠢的事情?
以下是示例代码的输出,将元素拖动到画布的左上角:
(禁用线路):PR=PickResult [node = Canvas@4e91835c, point = Point3D [x = 4.0, y = 2.0, z = 0.0], distance = 746.4101615137755
(启用线路):PR=PickResult [node = null, point = Point3D [x = 842.0, y = -500.0, z = 0.0], distance = 746.4101615137755
注意坐标完全是,以及拣选结果突然再也找不到节点......
代码(来自James_D的修改后的样本,以回答我的earlier question。
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.canvas.Canvas;
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.PickResult;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class DragBoard extends Application {
private static int cellCount = 0;
private final DataFormat objectDataFormat = new DataFormat("x-application/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) {
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));
}
});
setOnMouseReleased(e -> {
Object es = e.getSource();
PickResult pr = e.getPickResult();
System.out.println("PR=" + pr);
});
}
@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);
Canvas canvas = new Canvas(250, 100);
BorderPane root = new BorderPane(new Label("Loading..."));
buildTreeTask.setOnSucceeded(e -> {
tree.setRoot(buildTreeTask.getValue());
root.setTop(canvas);
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);
}
}