我正在尝试拖动节点并将它们放在一起。这是一个简单的类,我期望它会对拖动手势作出反应,但它不会
public class CircleDrag extends Circle
{
double x, y;
String name;
int count = 0;
public CircleDrag(double centerX, double centerY, String name)
{
super(centerX, centerY, 10);
this.name = name;
setOnDragDetected(e ->
{
startFullDrag();
startDragAndDrop(TransferMode.ANY); // tried with and without this line.
logIt(e);
});
setOnDragEntered(e ->
{
logIt(e);
});
setOnDragDone(e ->
{
logIt(e);
});
setOnDragOver(e ->
{
logIt(e);
});
setOnMousePressed(e ->
{
logIt(e);
setMouseTransparent(true);
x = getLayoutX() - e.getSceneX();
y = getLayoutY() - e.getSceneY();
});
setOnMouseReleased(e ->
{
logIt(e);
setMouseTransparent(false);
});
setOnMouseDragged(e ->
{
logIt(e);
setLayoutX(e.getSceneX() + x);
setLayoutY(e.getSceneY() + y);
});
}
private void logIt(Event e)
{
System.out.printf("%05d %s: %s\n", count++, name, e.getEventType().getName());
}
}
我原本希望将一堆CircleDrags添加到窗格中,当将一个CircleDrags拖到另一个窗格上时,另一个会触发onDrag *事件。但事实并非如此。
我不明白这个姿势是什么?
由于 奥利。
答案 0 :(得分:1)
以下是您一般可以做到的事情:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class PhysicsTest extends Application {
public static List<Circle> circles = new ArrayList<Circle>();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
Group root = new Group();
Circle circle1 = new Circle( 50);
circle1.setStroke(Color.GREEN);
circle1.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.3));
circle1.relocate(100, 100);
Circle circle2 = new Circle( 50);
circle2.setStroke(Color.BLUE);
circle2.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.3));
circle2.relocate(200, 200);
MouseGestures mg = new MouseGestures();
mg.makeDraggable( circle1);
mg.makeDraggable( circle2);
circles.add( circle1);
circles.add( circle2);
root.getChildren().addAll(circle1, circle2);
primaryStage.setScene(new Scene(root, 1600, 900));
primaryStage.show();
}
public static class MouseGestures {
double orgSceneX, orgSceneY;
double orgTranslateX, orgTranslateY;
public void makeDraggable( Node node) {
node.setOnMousePressed(circleOnMousePressedEventHandler);
node.setOnMouseDragged(circleOnMouseDraggedEventHandler);
}
EventHandler<MouseEvent> circleOnMousePressedEventHandler = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
Circle p = ((Circle) (t.getSource()));
orgTranslateX = p.getCenterX();
orgTranslateY = p.getCenterY();
}
};
EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
double newTranslateX = orgTranslateX + offsetX;
double newTranslateY = orgTranslateY + offsetY;
Circle p = ((Circle) (t.getSource()));
p.setCenterX(newTranslateX);
p.setCenterY(newTranslateY);
for( Circle c: circles) {
if( c == p)
continue;
if( c.getBoundsInParent().intersects(p.getBoundsInParent())) {
System.out.println( "Overlapping!");
}
}
}
};
}
}
请注意,此解决方案使用父级中的边界,即最后使用矩形进行重叠检查。如果您想使用例如圆形检查,您可以使用半径并检查圆圈之间的距离。取决于您的要求。
答案 1 :(得分:0)
您当前解决方案面临的挑战
您需要在dragboard中添加一些内容
如果在最初检测到拖动时没有在拖动板中放置任何内容,则无需拖动任何内容,因此将永远不会触发后续拖动相关事件,例如dragEntered,dragDone和dragOver。
将“使用鼠标拖动节点”与“拖放内容处理”混为一谈很难
由于鼠标拖动事件处理的拖动以及拖放操作生效,我无法使其完全正常工作,因为只要拖放操作生效,节点就会停止接收鼠标拖动事件。
示例解决方案
由于上述挑战,我采取的方法是:
不幸的是,JavaFX拖动事件与鼠标事件不同。拖动事件似乎不包括完整位置信息(例如x,y或sceneX,sceneY)。这意味着您需要一种独立于事件来确定此信息的方法。我不知道JavaFX中的API来检测鼠标光标的当前位置,所以我不得不求助于awt MouseInfo类来确定当前的鼠标位置。
在此过程中,我在初始和最终节点位置计算中失去了一点准确性。对于小圈子来说,这似乎并不重要。对于其他应用程序,您可以稍微修改我的逻辑,使拖放过渡100%准确和平滑。
我使用Java 8作为示例解决方案(DragView在Java 7中不可用)。 CircleDrag是可拖动节点的更新版本,具有拖放处理功能。 CircleDragApp只是CircleDrag节点的JavaFX应用程序测试工具。
CircleDrag.java
import javafx.event.Event;
import javafx.scene.SnapshotParameters;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import java.awt.Point;
import java.awt.MouseInfo;
public class CircleDrag extends Circle {
private final String name;
private int count = 0;
public CircleDrag(double centerX, double centerY, String name) {
super(centerX, centerY, 10);
this.name = name;
setOnDragDetected(e -> {
ClipboardContent content = new ClipboardContent();
content.putString(name);
Dragboard dragboard = startDragAndDrop(TransferMode.ANY);
dragboard.setContent(content);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
dragboard.setDragView(snapshot(params, null));
dragboard.setDragViewOffsetX(dragboard.getDragView().getWidth() / 2);
dragboard.setDragViewOffsetY(dragboard.getDragView().getHeight() / 2);
setVisible(false);
e.consume();
logIt(e);
});
setOnDragEntered(this::logIt);
setOnDragDone(e ->
{
Point p = MouseInfo.getPointerInfo().getLocation();
relocate(
p.x - getScene().getWindow().getX() - getScene().getX() - getRadius(),
p.y - getScene().getWindow().getY() - getScene().getY() - getRadius()
);
setVisible(true);
logIt(e);
});
setOnDragDropped(e -> {
Dragboard db = e.getDragboard();
System.out.println("Dropped: " + db.getString() + " on " + name);
e.setDropCompleted(true);
e.consume();
logIt(e);
});
setOnDragOver(e -> {
if (e.getGestureSource() != this) {
e.acceptTransferModes(TransferMode.ANY);
logIt(e);
}
e.consume();
});
}
private void logIt(Event e) {
System.out.printf("%05d %s: %s\n", count++, name, e.getEventType().getName());
}
}
CircleDragApp.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.Random;
public class CircleDragApp extends Application {
private static final int W = 320;
private static final int H = 200;
private static final int R = 5;
private Random random = new Random(42);
public void start(Stage stage) throws Exception {
Pane pane = new Pane();
pane.setPrefSize(W, H);
for (int i = 0; i < 10; i++) {
CircleDrag circle = new CircleDrag(
random.nextInt(W - R) + R,
random.nextInt(H - R) + R,
i + ""
);
circle.setFill(Color.rgb(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
pane.getChildren().add(circle);
}
stage.setScene(new Scene(pane));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
分手思考
Lorand的解决方案没有使用拖动事件处理程序,与我所拥有的相比看起来相当不错,并且可能没有什么怪癖。研究两者并选择最适合您情况的解决方案。
我的一般建议是,如果您要进行数据传输处理,那么拖放API可能是一种很好的方法。如果您没有进行数据传输处理,那么坚持使用普通鼠标事件可能是最好的方法。