JavaFX - 当用户将鼠标从一个节点拖动到另一个节点时通知?

时间:2016-11-15 14:00:42

标签: java user-interface javafx

我有以下用于演示的基本GUI:

enter image description here

我试图实现以下功能,但我已经用尽了所有尝试的途径。

  

用户可以左键单击任何ImageView,它将创建一个   跟随用户光标的箭头,直到用户离开   鼠标按钮。 (箭头开始x,y是他点击的地方,结束x,y是   他的鼠标当前所在的位置)如果用户点击了红色   steps并将其拖过蓝色ImageView,然后放手,   该程序将打印ImageView

     

如果用户点击红色User just clicked from R to B并放开鼠标但是   如果没有超过ImageView,该程序将打印ImageView

     

在所有情况下,用户点击时都会显示箭头   User just clicked from R but did not target a different ImageView并且在他放开鼠标的第二个时间消失。

ImageView

这是我最好的尝试,它甚至没有接近。它移动一条线(不是箭头,理想情况下我希望我的箭头在移动时像this example image from a popular video game那样弯曲),但不符合我的需要。然而,当我拖过时,它无法检测到什么?一个ImageView。

有更好的方法吗?我觉得我可以简单地完成我的代码,但必须是另一种方式。

1 个答案:

答案 0 :(得分:2)

  1. Java是一种面向对象的语言。基本思想是创建类来表示您正在建模的数据,然后从这些类创建对象。如果你把事物和任意地图绑在一起看东西,并且阵列无缘无故地开始,那么你就是在错误的地方开始。
  2. JavaFX有一个可观察的properties系统。它们以可变的方式包装对象,并且可以被观察,以便您可以响应更改。
  3. 请务必阅读并理解MouseEventsMouseDragEvents上的文档。处理拖动有三种不同的模式。对于要发送到鼠标拖动期间启动拖动的节点以外的节点的事件(鼠标拖动事件),您需要处于完全“按下拖动释放手势”模式。您可以在响应startFullDrag()事件时通过调用节点上的dragDetected来激活此模式。
  4. 我会从像

    这样的东西开始
    public class NamedDragAwareImageView {
    
        private final ObjectProperty<NamedDragAwareImageView> source ;
        private final ObjectProperty<NamedDragAwareImageView> destination ;
        private final String name ;
        private final ImageView imageView ;
    
        public NamedDragAwareImageView(ObjectProperty<NamedDragAwareImageView> source,
            ObjectProperty<NamedDragAwareImageView> destination,
            String name, String resource) {
    
            this.source = source ;
            this.destination = destination ;
            this.name = name ;
            this.imageView = new ImageView(new Image(resource));
    
            imageView.setOnDragDetected(e -> {
                source.set(this);
                destination.set(null);
                imageView.startFullDrag();
            });
    
            imageView.setOnMouseDragReleased(e -> {
                if (source.get() != null && source.get() != this) {
                    destination.set(this);
                }
            });
    
            // other image view config...
    
        }
    
        public ImageView getView() {
            return imageView ;
        }
    
        public String getName() {
            return name ;
        }
    
    }
    

    然后你可以做以下事情:

    // observable properties to represent start and end nodes for drag:
    ObjectProperty<NamedDragAwareImageView> source = new SimpleObjectProperty<>();
    ObjectProperty<NamedDragAwareImageView> destination = new SimpleObjectProperty<>();
    
    
    Pane root = new Pane();
    // create your named image views, referencing the source and destination
    // and add their image views to root, e.g.
    NamedDragAwareImageView red = new NamedDragAwareImageView(source, destination, "Red", "red.png");
    root.getChildren().add(red.getView());
    
    // recommend using SVG paths (i.e. javafx.scene.shape.Path) for the arrow
    // easy to draw programmatically, easy to manipulate elements etc:
    Path arrowHead = new Path();
    MoveTo arrowHeadStart = new MoveTo();
    arrowHead.getElements().add(arrowHeadStart);
    arrowHead.getElements().addAll(/* draw an arrow head with relative path elements... */);
    arrowHead.setVisible(false);
    // avoid arrowHead interfering with dragging:
    arrowHead.setMouseTransparent(true);
    
    // this will contain a MoveTo and a bunch of LineTo to follow the mouse:
    Path arrowLine = new Path();
    arrowLine.setMouseTransparent(true);
    
    root.getChildren().addAll(arrowHead, arrowLine);
    
    // change listener for source. source is set when drag starts:
    source.addListener((obs, oldSource, newSource) -> {
        if (newSource == null) return ;
        arrowHeadStart.setX(/* x coord based on newSource */);
        arrowHeadStart.setY(/* similarly */);
        arrowHead.setVisible(true);
    });
    
    // change listener for destination. destination is only set
    // when drag complete:
    destination.addListener((obs, oldDestination, newDestination) -> {
        if (newDestination != null) {
            System.out.println("User dragged from "+source.get().getName()+
                " to "+destination.get().getName());
        }
    });
    
    root.setOnMouseDragOver(e -> {
        if (source.get()==null && destination.get()!=null) {
            // update arrowStart position
            // add line element to arrowLine
        }
    });
    
    root.setOnMouseReleased(e -> {
        // clear arrow:
        arrowHead.setVisible(false);
        arrowLine.getElements().clear();
    });