【问题标题】:Drag Image outside the window with JavaFX使用 JavaFX 将图像拖到窗口外
【发布时间】:2019-08-23 19:41:16
【问题描述】:

大家,

我想在我的应用程序中插入一个可以拖放到应用程序之外的图形。一旦图形被释放到窗口之外,应该打开一个未装饰/透明窗口,其中仅显示此图形。

    Stage newStage = new Stage();
    StackPane stack = new StackPane();
    ImageView imageView = new ImageView(new Image(this.getClass().getResourceAsStream(InBoxEnum.Graphic.INBOXLOGO.getFilename())));
    stack.getChildren().add(imageView);


    imageView.setOnDragDetected(event -> {
        Dragboard dragboard = imageView.startDragAndDrop(TransferMode.MOVE);

        dragboard.setDragView(imageView.snapshot(null, null));
        ClipboardContent content = new ClipboardContent();
        content.put(DRAGGABLE_INBOX_TYPE, "dontcare");
        dragboard.setContent(content);

        event.consume();
    });

    imageView.setOnDragDone(event -> {
        System.out.println(event.getScreenX());
        System.out.println(event.getScreenY());
    });

    Scene scene = new Scene(stack, 500, 500);
    newStage.setScene(scene);
    newStage.show();

到目前为止,DragDetected 事件也没有问题。

问题在于,在 dragDone 事件中,鼠标的位置始终为 0,我无法判断鼠标是在我的应用程序内部还是外部。如果在应用程序内释放鼠标,则不会发生任何事情。

我也尝试过使用机器人类,但我总是得到一个静态的奇怪 x/y 位置。

我正在使用 JAVA 11(采用 JDK)。

感谢您的帮助

【问题讨论】:

    标签: java javafx drag-and-drop


    【解决方案1】:

    使用Robot 对我来说效果很好(Oracle JDK 11 + JavaFX 12)。由于您实际上并不想拖放任何图像数据,因此您可以通过立即创建一个新阶段并使用ImageViewMOUSE_DRAGGED 来更新窗口的位置来解决此问题:

    Stage newStage = new Stage();
    StackPane stack = new StackPane();
    ImageView imageView = new ImageView(new Image(...));
    stack.getChildren().add(imageView);
    
    class DragHandler implements EventHandler<MouseEvent> {
    
        Stage dragTarget;
    
        @Override
        public void handle(MouseEvent event) {
            if (dragTarget != null) {
                // move stage
                dragTarget.setX(event.getScreenX());
                dragTarget.setY(event.getScreenY());
                event.consume();
            }
        }
    
    }
    
    final DragHandler dragHandler = new DragHandler();
    
    imageView.setOnDragDetected(event -> {
        // init stage at half transparency
        Group root = new Group(new ImageView(imageView.getImage())); 
        root.setOpacity(0.5);
    
        Scene displayScene = new Scene(root);
        displayScene.setFill(null);
        Stage displayStage = new Stage();
        displayStage.initStyle(StageStyle.TRANSPARENT);
        displayStage.setScene(displayScene);
        displayStage.setX(event.getScreenX());
        displayStage.setY(event.getScreenY());
        displayStage.show();
    
        dragHandler.dragTarget = displayStage;
    
        event.consume();
    });
    imageView.setOnMouseDragged(dragHandler);
    imageView.setOnMouseReleased(event -> {
        if (dragHandler.dragTarget != null) {
            if (stack.contains(event.getX(), event.getY())) { // check, if drop happened inside the bounds of the scene root
                dragHandler.dragTarget.hide();
            } else {
                // make stage fully opaque & cleanup
                dragHandler.dragTarget.getScene().getRoot().setOpacity(1);
                imageView.setImage(null);
            }
            dragHandler.dragTarget = null;
            event.consume();
        }
    });
    
    Scene scene = new Scene(stack, 500, 500);
    newStage.setScene(scene);
    newStage.show();
    

    【讨论】:

    • 感谢您的回答和您的榜样。我想我可以使用这个解决方案。像往常一样 - 我经常想办法变得复杂 :-) 周末愉快!
    • 我认为该解决方案不符合“如果在应用程序内释放鼠标,则不会发生任何事情”的要求。我用不同的解决方案遇到了同样的问题。
    【解决方案2】:

    建议的解决方案基于fabian's answer
    主要更改封装在withinBounds 方法中,该方法用于定义拖动是否在窗口边界内结束。此方法基于this 答案:

    import javafx.application.Application;
    import javafx.event.EventHandler;
    import javafx.geometry.Point2D;
    import javafx.geometry.Rectangle2D;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.stage.StageStyle;
    import javafx.stage.Window;
    
    public class DragOut extends Application {
    
        @Override
        public void start(Stage primaryStage) {
    
            ImageView imageView = new ImageView("https://findicons.com/files/icons/345/summer/128/cake.png");
            StackPane stack = new StackPane(imageView);
    
            DragHandler dragHandler = new DragHandler();
            imageView.setOnDragDetected(event -> {
                Stage displayStage = makeNewStage(imageView.getImage());
                displayStage.setX(event.getScreenX());
                displayStage.setY(event.getScreenY());
                dragHandler.setStage(displayStage);
                displayStage.show();
                event.consume();
            });
            imageView.setOnMouseDragged(dragHandler);
            imageView.setOnMouseReleased(event -> {
                if (! withinBounds(event, imageView.getScene().getWindow()) && dragHandler.dragTarget != null) {
                    // make stage fully opaque & cleanup
                    dragHandler.showStage();
                    imageView.setImage(null);
                    event.consume();
                }else{
                    dragHandler.closeStage();
                }
                dragHandler.setStage(null);
            });
    
            Scene scene = new Scene(stack, 300, 300);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private Stage makeNewStage(Image image) {
    
            Group root = new Group(new ImageView(image));
            root.setOpacity(0.5); // init stage at half transparency
            Stage displayStage = new Stage(StageStyle.TRANSPARENT);
            displayStage.setScene(new Scene(root, null));
    
            return displayStage;
        }
    
        private boolean withinBounds(MouseEvent event, Window window) {
    
            Point2D mouseLoc = new Point2D(event.getScreenX(), event.getScreenY());
            Rectangle2D windowBounds = new Rectangle2D(window.getX(), window.getY(),
                                                window.getWidth(), window.getHeight());
            return windowBounds.contains(mouseLoc);
        }
    
        class DragHandler implements EventHandler<MouseEvent> {
    
            private Stage dragTarget;
    
            @Override
            public void handle(MouseEvent event) {
                if (dragTarget != null) {
                    // move stage
                    dragTarget.setX(event.getScreenX());
                    dragTarget.setY(event.getScreenY());
                    event.consume();
                }
            }
    
            void setStage(Stage stage){
                dragTarget = stage;
            }
    
            void showStage(){
                if (dragTarget != null) {
                    dragTarget.getScene().getRoot().setOpacity(1);
                }
            }
    
            void closeStage(){
                if (dragTarget != null) {
                    dragTarget.close();
                }
            }
        }
    
        public static void main(final String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多