gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 03:13:55 24 4
gpt4 key购买 nike

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

enter image description here

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

User can left click on any of the ImageView's and it will create an arrow that follows the user's cursor around until the user let's go of the mouse button. (arrow start x,y is where he clicked and end x,y is where his mouse currently is) If the user clicked on the Red ImageView and dragged it over the Blue ImageView and then let go, the program would print User just clicked from R to B

If the user clicked on the Red ImageView and let go of the mouse but was not over a different ImageView, the program would print User
just clicked from R but did not target a different ImageView
.

Under all circumstances, the arrow will appear when the user clicks on the ImageView and will disappear the second he lets go of the mouse.

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

import java.util.HashMap;

public class Test extends Application
{
public static int HEIGHT = 500, WIDTH = 600;

@Override
public void start(Stage primaryStage) throws Exception
{
ImageView blue = new ImageView(new Image("blue.png")),
red = new ImageView(new Image("red.png")),
dark = new ImageView(new Image("dark.png"));

// Final array as to bypass the `final` requirement of event handler inner classes.
final ImageView[] hoveredOver = new ImageView[1];
final Line[] linePtr = new Line[1];
linePtr[0] = new Line();
linePtr[0].setStrokeWidth(10);

HashMap<ImageView, Character> lookup = new HashMap<ImageView, Character>(3)
{{
put(blue, 'B');
put(red, 'R');
put(dark, 'D');
}};

for (ImageView i : new ImageView[] { blue, red, dark })
{
i.setFitWidth(150);
i.setFitHeight(150);

// Set the anchor points of the click and display the arrow.
i.setOnMousePressed(e -> {
linePtr[0].setStartX(e.getX());
linePtr[0].setStartY(e.getY());
linePtr[0].setVisible(true);
});
// Move the arrow as the mouse moves.
i.setOnMouseDragged(e -> {
linePtr[0].setEndX(e.getX());
linePtr[0].setEndY(e.getY());
});
i.setOnMouseReleased(e -> {
// Not null means that the user WAS actually just now hovering over an imageview.
if (hoveredOver[0] != null)
System.out.printf("The user clicked from %c to %c!\n", lookup.get(i), lookup.get(hoveredOver[0]));
// Null means the user is not over an ImageView.
else
System.out.printf("The user initially clicked %c but did not drag to another Imageview.\n", lookup.get(i));
linePtr[0].setVisible(false);
});
// If the user enters ANY of the ImageViews,
// Set a variable so that the drag release listener
// can know about it!
i.setOnMouseDragOver(e -> hoveredOver[0] = i);
i.setOnMouseDragExited(e -> hoveredOver[0] = null);
}

blue.setX(400);
blue.setY(250);

red.setY(300);
red.setX(50);

/*
In this example I'm using a Pane but in my real program
I might be using a VBOX HBOX etc where I cannot freely move stuff around as I'd like.
This makes things extremely difficult and without using a 'Pane'
I don't know how this can even be done. Suggestions?
*/
Pane pneRoot = new Pane(blue, red, dark, linePtr[0]);
Scene scene = new Scene(pneRoot, WIDTH, HEIGHT);
primaryStage.setScene(scene);
primaryStage.show();
}

public static void main(String[] args)
{
launch(args);
}
}

这是我最好的尝试,但还差得远。它移动一条线(不是箭头,理想情况下我希望我的箭头在移动时弯曲,就像 this example image from a popular video game )但不适合我的需要。但是,它无法检测到我在“拖动”ImageView 时放手的时间。

有更好的方法吗?我觉得我不能简单地继续编写代码,但必须还有另一种方法。

最佳答案

  1. Java 是一种面向对象的语言。基本思想是创建类来表示正在建模的数据,然后从这些类创建对象。如果您使用任意映射将事物绑定(bind)在一起来查找事物,并且数组无缘无故地乱转,那么您就从错误的地方开始了。
  2. JavaFX 有一个可观察系统 properties 。这些以可变的方式包装对象,并且可以被观察,以便您可以响应更改。
  3. 确保您阅读并理解 MouseEvents 上的文档和 MouseDragEvents 。处理拖动有三种不同的模式。对于要发送到在鼠标拖动期间启动拖动的节点以外的节点的事件(鼠标拖动事件),您需要处于完整的“按下-拖动-释放手势”模式。您可以在响应 dragDetected 事件时通过在节点上调用 startFullDrag() 来激活此模式。

我会从类似的事情开始

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();
});

关于JavaFX - 当用户将鼠标从一个节点拖动到另一个节点时通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40611746/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com