4

我想在 JavaFX 中使用拖放功能,并有一个功能可以让您直观地看到被拖动的项目。我已经实现了我认为可行的解决方案,但 API 似乎存在问题。

根据 API startDragAndDrop(TransferMode...) 必须在 setOnDragDetected 内初始化。这是我使用 Dragboard 来存储我想转移到另一个节点的内容的地方。

编辑:这似乎与 TrasferMode 有关。如果我使用 TransferMode.NONE 没有问题,但使用 COPY、ANY、LINK 总是会导致这个问题。

但是调用 dragBoard.setContent(some clipboard content) 只允许鼠标移动非常小的增量(在任何方向上最多 4 个像素!)。删除这行代码,然后我可以拖动项目并看到它被拖动到任何地方,但是当然,我不能存储剪贴板内容。

我看到的问题是 setOnMouseDragged(..) 在 setOnDragDetected 之前被调用!为什么 setOnMouseDragged 在 setOnDragDetected 之前运行没有多大意义......

我的代码中是否有明显的东西可能会导致问题?我只是希望能够在拖动时看到 imgView 移动,并能够像往常一样将其拖放到目标上,并带有剪贴板内容。

编辑 2:更新了下面的代码以反映仅使用 Drag 事件,而不是 Drag 和 Mouse 事件。使用两者都会导致问题。仍然存在的问题是我无法放在目标上,因为使用 setOnDragOver 会使拖动的节点始终位于光标的正下方。

protected ImageView initImageView(Image img){

    final Pane ldzPane = GameBoard.getInstance().getLDZpane();

    final ObjectProperty<Point2D> dragAnchor = new SimpleObjectProperty<>();

    final ImageView imgView = new ImageView(img);

    final DoubleProperty initX = new SimpleDoubleProperty();
    final DoubleProperty initY = new SimpleDoubleProperty();

    final DoubleProperty dragX = new SimpleDoubleProperty();
    final DoubleProperty dragY = new SimpleDoubleProperty();

    final DoubleProperty newXPosition = new SimpleDoubleProperty();
    final DoubleProperty newYPosition = new SimpleDoubleProperty();

    final int buffer = 3;

    imgView.setOnDragDetected(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent event) {
            initX.set(imgView.getTranslateX());
            initY.set(imgView.getTranslateY());
            dragAnchor.set(new Point2D(event.getSceneX(), event.getSceneY()));
            ClipboardContent content = new ClipboardContent();
            content.putString(RHSIconizedToken.this.tokenLookupInfo());
            Dragboard db = imgView.startDragAndDrop(TransferMode.ANY); 
            db.setContent(content); 
            event.consume();
        }
    });

    imgView.setOnDragOver(new EventHandler<DragEvent>(){

        @Override
        public void handle(DragEvent event) {
            imgView.toFront();

            dragX.set(event.getSceneX() - dragAnchor.get().getX());
            dragY.set(event.getSceneY() - dragAnchor.get().getY());
            imgView.setOpacity(0.5);

            newXPosition.set(initX.get() + dragX.get());
            newYPosition.set(initY.get() + dragY.get());

            //if(       (Math.abs((newXPosition.get() - ldzPane.getWidth())) <=  ldzPane.getWidth() + startX + buffer) &&
            //      ((newXPosition.get() + startX + imgView.getImage().getWidth()+ buffer)<=  ldzPane.getWidth()))
                imgView.setTranslateX(newXPosition.get());

            //if(       (Math.abs((newYPosition.get() - ldzPane.getHeight())) <=  ldzPane.getHeight() + startY + buffer) &&
            //      ((newYPosition.get() + startY + imgView.getImage().getHeight()+ buffer)<=  ldzPane.getHeight()))
                imgView.setTranslateY(newYPosition.get());

            event.consume();
        }

    });

    imgView.setOnDragDone(new EventHandler<DragEvent>() {
        public void handle(DragEvent event) {

            LinkedList<RHSIconizedToken> iTokens = GameBoard.getInstance().getTokenBayItokens();
            if (event.getTransferMode() == TransferMode.MOVE) {
                RHSIconizedToken element = iTokens.remove(index);
                iTokens.add(index, new RHSIconizedToken(element.getImage(), new SourceToken("removed", "removed"), index));
                imgView.setVisible(false); 

                GameBoard theGameBoard = GameBoard.getInstance();
                GUI theGUI = GUI.getInstance();
                //was this the last one removed from the rhs?
                //if so we need to signal the CompileButton to be turned on!
                if(theGameBoard.isRHSempty())
                    theGUI.enableCompileButton();
                else
                    theGUI.disableCompileButton();
            }
            event.consume();
        }
    });

    imgView.setOnMouseEntered(new EventHandler <MouseEvent>() {
        public void handle(MouseEvent event) {
            imgView.setEffect(new Glow(0.5));
            event.consume();
        }
    });

    imgView.setOnMouseExited(new EventHandler <MouseEvent>() {
        public void handle(MouseEvent event) {
            imgView.setEffect(new Glow(0.0));
            imgView.setOpacity(1);
            event.consume();
        }
    });

    return imgView;
}
4

2 回答 2

3

Java 8 计划提供对可视拖放的更多支持。DragBoard 的 setDragView (Image, XOffset, YOffset) 方法效果很好,并且在 Java 8 beta 中可用。

    imgView.setOnDragDetected(new EventHandler<MouseEvent>() {
        public void handle(MouseEvent event) {
            ClipboardContent content = new ClipboardContent();
            content.putString(RHSIconizedToken.this.tokenLookupInfo());
            Dragboard db = imgView.startDragAndDrop(TransferMode.ANY);
            db.setDragView(image, 7, 7); 
            db.setContent(content); 
            event.consume();
        }
    });
于 2013-05-04T18:34:26.357 回答
2

我认为这会对您有所帮助:

DraggablePanelsExample.java

我也将它用于我的面板,它适用于 ImageView 就像一个魅力。

编辑:
你正在结合这个错误!您不能将 DragDetected 与 MouseDragged 结合使用。如果您开始在 JavaFX 中拖动,mouseevents 将不再被触发。
如果您想要一个 Drag-Board-String,那么只需将您的 String 保存在您的班级中。

ps:将 DragDone 替换为 MouseReleased

于 2013-04-18T06:35:15.403 回答