我有以下用于演示的基本GUI:
我试图实现以下功能,但我已经用尽了所有尝试的途径。
用户可以左键单击任何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。
有更好的方法吗?我觉得我可以简单地完成我的代码,但必须是另一种方式。
答案 0 :(得分:2)
MouseEvent
s和MouseDragEvent
s上的文档。处理拖动有三种不同的模式。对于要发送到鼠标拖动期间启动拖动的节点以外的节点的事件(鼠标拖动事件),您需要处于完全“按下拖动释放手势”模式。您可以在响应startFullDrag()
事件时通过调用节点上的dragDetected
来激活此模式。我会从像
这样的东西开始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();
});