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

时间:2014-04-02 18:37:10

标签: javafx clipboard

如何使用getContent()将我的实际对象从Dragboard中取出?有没有可能指定类型? Todo和Doing是FlowPanes - 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;
}

1 个答案:

答案 0 :(得分:4)

嗯,你真的应该考虑对数据的表示(而不是数据的视图),这是被拖放的对象。您注册一个处理程序以检测节点的拖动(数据视图),将数据设置到拖动板,然后在成功删除时创建另一个删除它的相同数据的视图。删除上一个节点以进行移动,不要删除它以获取副本。

不幸的是,它没有用。

参见this 并投票支持bug/feature,这将允许您直接执行此操作。

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

所以,现在,我认为解决方案是创建某种本地存储库并将拖动的对象存储在其中。这可能就像ObjectProperty<?> currentlyDraggedObject一样简单,或者像我在discussion referenced earlier底部实现的LocalDragboard那样复杂。 (这只不过是复制您在google&#34;类型安全异构容器的标准示例中找到的代码&#34;。)

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

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