从 JavaFX DragAndDrop 剪贴板访问自定义对象的属性

joh*_*him 1 clipboard javafx

如何使用 getContent() 从 Dragboard 中取出我的实际对象?有没有可能指定类型?Todo 和 Doing 是 Fl​​owPanes - MyRectangle 是自定义组件的示例。

我想要什么: 放一个对象,例如。剪贴板上具有高度,填充颜色等的矩形,并从具有高度,颜色等的板上取回该对象....

private static final DataFormat itemFormat = new DataFormat("custom.item");
MyRectangle myRectangle = generateRectangle();

myRectangle.setOnDragDetected(new EventHandler<MouseEvent>() {

    @Override
    public void handle(MouseEvent event) {
        Dragboard db = myRectangle
            .startDragAndDrop(TransferMode.MOVE);

        ClipboardContent content = new ClipboardContent();
        content.put(taskFormat, myRectangle);

        // Rectangle has height 
        System.out.println(myRectangle.getHeight());
        TaskItem task = new TaskItem();
        task.setTime(6);
        content.put(itemFormat, task);
        db.setContent(content);

        event.consume();
    }
    });

    myRectangle.setOnDragDone(new EventHandler<DragEvent>() {
    public void handle(DragEvent event) {
        event.consume();
    }
    });

doing.setOnDragOver(new EventHandler<DragEvent>() {
    public void handle(DragEvent event) {
    if (event.getGestureSource() != doing) {
        event.acceptTransferModes(TransferMode.MOVE);
    }

    event.consume();
    }
});

doing.setOnDragEntered(new EventHandler<DragEvent>() {
    public void handle(DragEvent event) {
    event.consume();
    }
});

doing.setOnDragExited(new EventHandler<DragEvent>() {
    public void handle(DragEvent event) {
    event.consume();
    }
});

doing.setOnDragDropped(new EventHandler<DragEvent>() {
    public void handle(DragEvent event) {
    final Dragboard db = event.getDragboard();
    boolean success = false;
    if (db.hasContent(taskFormat)) {
        MyRectangle rect2 = (MyRectangle) db.getContent(taskFormat);


        System.out.println(rect2.getHeight());
        todo.getChildren().remove(rect2);
        doing.getChildren().add(rect2);
        success = true;
        // doing.getChildren().add(rectangle);
    }
    event.setDropCompleted(success);
    event.consume();
    }
});

private MyRectangle generateRectangle() {
final MyRectangle rect2 = new MyRectangle(0, 0, 10, 10);
rect2.setId("app");
rect2.setArcHeight(8);
rect2.setWidth(80);
rect2.setArcWidth(8);
rect2.setStrokeWidth(1);
rect2.setStroke(Color.WHITE);
rect2.setHeight(60);
return rect2;
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*s_D 5

好吧,您真的应该考虑拥有数据的表示(而不是数据的视图),即被拖放的对象。您注册一个处理程序来检测节点(数据视图)的拖动,将数据设置到拖动板中,然后在成功放置时创建另一个放置相同数据的视图。删除前一个节点进行移动,不要删除副本。

不幸的是,它不起作用。

看到这个 并投票给这个bug/feature,这将允许您直接执行此操作。

目前,如果 Java 对象实现了 Serializable,则只能将它们放置在拖板上。由于 JavaFX 属性不实现 Serializable,因此任何使用这些属性进行数据表示的类(恕我直言,是您想要用来表示要在应用程序周围拖放的数据的任何类)。即使您的类是可序列化的,正如我所理解的,该对象在将其放入拖动板时被序列化并在您删除它时反序列化,这意味着您在拖放时会得到一个新对象,而不是对相同的对象:这可能不是您想要的。(如果您通过拖放复制某些内容,然后对其进行编辑,您可能希望两个副本都尊重编辑。)

所以,就目前而言,我认为解决方案是创建某种本地存储库并将拖动的对象存储在其中。这可能像 一个 一样简单ObjectProperty<?> currentlyDraggedObject,或者更复杂,例如LocalDragboard我在前面引用讨论底部实现的。(这只不过是复制您在谷歌搜索“类型安全异构容器的标准示例”时会找到的代码。)

我不得不说,我发现拖放的方式有点奇怪。JavaFX 2 及更高版本中的几乎所有内容都是以非常现代的 Java 风格编写的,(几乎)所有内容都非常舒适地使用泛型,一些非常好的并发 API,专为较新的高级并发 API 设计,所有事件处理设计为关注最近的语言发展,例如 lambda 表达式和流。Bindings API 甚至似乎对整个反应式编程运动略有倾斜。但是拖放似乎被设计为好像我们希望通过拖动手势传输的唯一数据是字符串、图像和文件。就好像 DnD API 的设计者并没有真正理解程序员想要开发他们自己的数据表示类的想法。

因此,在这个非常现代的 GUI 框架中,您拥有一个看起来像是在 90 年代后期设计的 DnD API(如果是的话)。很奇怪。