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

从JavaFX DragAndDrop剪贴板访问自定义对象的属性,javafx,clipboard,Javafx,Clipboard,如何使用getContent()将实际对象从Dragboard中取出?有没有可能指定类型?Todo和DO是流程窗格-MyRectangle是自定义组件的一个示例 我想要的是: 将一个对象,例如一个具有高度、填充颜色等的矩形放在剪贴板上,然后从板上取回具有高度、颜色等的对象 private static final DataFormat itemFormat = new DataFormat("custom.item"); MyRectangle myRectangle = generateRec

如何使用getContent()将实际对象从Dragboard中取出?有没有可能指定类型?Todo和DO是流程窗格-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;
}
private static final DataFormat itemFormat=新数据格式(“custom.item”);
MyRectangle MyRectangle=generateRectangle();
检测到myRectangle.setOnDragDetected(新的EventHandler(){
@凌驾
公共无效句柄(MouseeEvent事件){
拖板db=myRectangle
.startDragAndDrop(传输模式.MOVE);
ClipboardContent=新的ClipboardContent();
content.put(taskFormat,myRectangle);
//矩形有高度
System.out.println(myRectangle.getHeight());
TaskItem任务=新建TaskItem();
任务设置时间(6);
content.put(项目格式、任务);
db.setContent(content);
event.consume();
}
});
myRectangle.setOnDragDone(新的EventHandler(){
公共无效句柄(DrageEvent事件){
event.consume();
}
});
doing.setOnDragOver(新的EventHandler()){
公共无效句柄(DrageEvent事件){
if(event.getGestureSource()!=doing){
event.acceptTransferModes(TransferMode.MOVE);
}
event.consume();
}
});
doing.setOnDragenter(新的EventHandler()){
公共无效句柄(DrageEvent事件){
event.consume();
}
});
doing.setOnDragExited(新的EventHandler(){
公共无效句柄(DrageEvent事件){
event.consume();
}
});
doing.setOnDragDrop(新的EventHandler()){
公共无效句柄(DrageEvent事件){
final Dragboard db=event.getDragboard();
布尔成功=假;
if(db.hasContent(taskFormat)){
MyRectangle rect2=(MyRectangle)db.getContent(taskFormat);
System.out.println(rect2.getHeight());
todo.getChildren().remove(rect2);
doing.getChildren().add(rect2);
成功=真实;
//doing.getChildren().add(矩形);
}
事件。setDropCompleted(成功);
event.consume();
}
});
私有MyRectangle generateRectangle(){
最终MyRectangle rect2=新的MyRectangle(0,0,10,10);
rect2.setId(“app”);
rect2.setArcHeight(8);
2.设置宽度(80);
rect2.设置弧宽(8);
rect2.设定行程宽度(1);
rect2.设定行程(颜色为白色);
2.设置高度(60);
返回rect2;
}

嗯,您确实应该考虑使用数据的表示(而不是数据的视图),即拖放的对象。注册处理程序以检测节点(数据视图)的拖动,将数据设置到dragboard中,然后在成功拖放时,在拖放的位置创建相同数据的另一个视图。删除上一个节点以进行移动,而不是删除其副本

不幸的是,它不起作用

看 投票支持这个,这样你就可以直接这么做了

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

所以,现在,我认为解决方案是创建某种本地存储库,并将拖动的对象存储在其中。这可能只是一个
ObjectProperty currentlyDraggedObject
,也可能是一个更复杂的东西,比如在页面底部实现的
LocalDragboard
。(这只不过是复制您在谷歌搜索“类型安全异构容器的标准示例”时会发现的代码而已。)

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


因此,在这个看起来非常现代的GUI框架中,您有一个DNDAPI,它看起来像是在90年代末设计的(如果是的话)。非常奇怪。

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

不幸的是,它不起作用

看 投票支持这个,这样你就可以直接这么做了

目前,如果Java对象实现可序列化,则只能将其放置在拖板上。由于JavaFX属性不实现可序列化,因此任何使用这些属性表示数据的类(w