拖放与视觉指示

Posted

技术标签:

【中文标题】拖放与视觉指示【英文标题】:Drag and dropping with visual indication 【发布时间】:2014-10-17 05:47:36 【问题描述】:

我正在尝试在 2 个对象之间实现拖放。

问题是,当我从一个矩形拖动到另一个矩形时,我需要在源矩形上连接一条线的起点,并在该线的终点跟随鼠标。

然后当我放在第二个矩形时,该行的末尾应该绑定它并传递一个字符串。

一方面使用 onmouseclicked、dragged 和 release 我设法使线跟随鼠标,但无法让第二个矩形明白鼠标已在其上释放(如下面的代码所示)

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;


public class Test extends Application 
double orgSceneX, orgSceneY;
double orgTranslateX, orgTranslateY;

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

  @Override
  public void start(Stage primaryStage) 
    Pane root = new BorderPane();

    Rectangle rect1=new Rectangle(100,50);
    rect1.setFill(Color.AQUAMARINE);rect1.setStroke(Color.BLACK);
    Label rect1_label=new Label("Rectangle 1");
    rect1_label.setLayoutX(20);rect1_label.setLayoutY(15);
    rect1.setLayoutX(220);rect1.setLayoutY(240);

    Line line=new Line (rect1.getLayoutX()+rect1.getWidth(),rect1.getLayoutY()+rect1.getHeight()/2,
                        rect1.getLayoutX()+rect1.getWidth(),rect1.getLayoutY()+rect1.getHeight()/2);
    line.startXProperty().bind(rect1.translateXProperty().add(rect1.getLayoutX()+rect1.getWidth()));
    line.startYProperty().bind(rect1.translateYProperty().add(rect1.getLayoutY()+rect1.getHeight()/2));
    line.getStrokeDashArray().setAll(10.0, 5.0);

    Rectangle rect2=new Rectangle(100,50);
    rect2.setFill(Color.BISQUE);rect2.setStroke(Color.BLACK);
    Label rect2_label=new Label("Rectangle 2");
    rect2_label.setLayoutX(20);rect2_label.setLayoutY(15);
    rect2.setLayoutX(600);rect2.setLayoutY(240);


    root.getChildren().addAll(rect1,rect2,line);


        rect1.setOnMousePressed(new EventHandler<MouseEvent>()
            public void handle(MouseEvent event)
                line.setVisible(true);
                line.toBack();
                line.setEndX(event.getX());
                line.setEndY(event.getY());
                orgSceneX = event.getSceneX();
                orgSceneY = event.getSceneY();
                orgTranslateX = ((Rectangle)(event.getSource())).getTranslateX();
                orgTranslateY = ((Rectangle)(event.getSource())).getTranslateY();
                line.setEndX(event.getSceneX());
                line.setEndY(event.getSceneY());
            
        );

        rect1.setOnMouseDragged(new EventHandler<MouseEvent>()
            public void handle(MouseEvent event)
            
                double offsetX = event.getSceneX();
                double offsetY = event.getSceneY();
                double newTranslateX = offsetX;
                double newTranslateY = offsetY;
                line.setEndX(newTranslateX);
                line.setEndY(newTranslateY);
            
        );

        rect1.setOnMouseReleased(new EventHandler<MouseEvent>()
            public void handle(MouseEvent event)
            
                line.setVisible(false);
            
        );



    Scene scene = new Scene(root);
    primaryStage.setTitle("Nodes test 1");
    primaryStage.setMinWidth(1000);
    primaryStage.setMinHeight(600);
    primaryStage.setScene(scene);
    primaryStage.show();
  

.

我也知道如何将值或字符串从一个对象拖放到另一个对象

.

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;


public class Test2 extends Application 
double orgSceneX, orgSceneY;
double orgTranslateX, orgTranslateY;

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

  @Override
  public void start(Stage primaryStage) 
    Pane root = new BorderPane();

    Rectangle rect1=new Rectangle(100,50);
    rect1.setFill(Color.AQUAMARINE);rect1.setStroke(Color.BLACK);
    Label rect1_label=new Label("Rectangle 1");
    rect1_label.setLayoutX(20);rect1_label.setLayoutY(15);
    rect1.setLayoutX(220);rect1.setLayoutY(240);

    Line line=new Line (rect1.getLayoutX()+rect1.getWidth(),rect1.getLayoutY()+rect1.getHeight()/2,
                        rect1.getLayoutX()+rect1.getWidth(),rect1.getLayoutY()+rect1.getHeight()/2);
    line.startXProperty().bind(rect1.translateXProperty().add(rect1.getLayoutX()+rect1.getWidth()));
    line.startYProperty().bind(rect1.translateYProperty().add(rect1.getLayoutY()+rect1.getHeight()/2));
    line.getStrokeDashArray().setAll(10.0, 5.0);

    Rectangle rect2=new Rectangle(100,50);
    rect2.setFill(Color.BISQUE);rect2.setStroke(Color.BLACK);
    Label rect2_label=new Label("Rectangle 2");
    rect2_label.setLayoutX(20);rect2_label.setLayoutY(15);
    rect2.setLayoutX(600);rect2.setLayoutY(240);


    root.getChildren().addAll(rect1,rect2,line);

    rect1.setOnDragDetected(new EventHandler<MouseEvent>()
        @Override public void handle(MouseEvent event)
            Dragboard db = rect1.startDragAndDrop(TransferMode.ANY);
            ClipboardContent content = new ClipboardContent();
            content.putString("rec");
            db.setContent(content);
            event.consume();
        
    );

    rect2.setOnDragOver(new EventHandler<DragEvent>() 
        public void handle(DragEvent event) 
            event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
            event.consume();
        
    );

    rect2.setOnDragDropped(new EventHandler<DragEvent>()
        @Override public void handle(DragEvent event)
            final Dragboard db = event.getDragboard(); 
            if (db.getString().equals("rec"))
                System.out.println("Accepted");
                event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
            
        
    );

    Scene scene = new Scene(root);
    primaryStage.setTitle("Nodes test 1");
    primaryStage.setMinWidth(1000);
    primaryStage.setMinHeight(600);
    primaryStage.setScene(scene);
    primaryStage.show();
  

如果我同时使用它们就会出错

如何才能同时绘制线和传递值?

【问题讨论】:

【参考方案1】:

通过在发起拖动的节点上调用startFullDrag 来激活“完全按下-拖动-释放手势”。 Javadocs for MouseEvent 详细介绍了拖动手势类型之间的差异,但基本上这允许在拖动过程中将鼠标事件传递到发起拖动的节点以外的节点。

但请注意,除非在该节点上按下鼠标(据我所知),否则您不会在节点上收到 mouseReleased 事件。所以你需要做一些工作来确定释放是否发生在第二个矩形上。如果鼠标在拖动过程中进入节点,我通过设置一个标志来做到这一点,如果它退出,则将其设置为 false。您也可以通过在底层容器上查找鼠标释放来执行此操作,并查看节点的边界是否包含鼠标事件的坐标。

还要注意,在这个示例中,我需要调用 line.setMouseTransparent(true); 以确保该行没有消耗鼠标事件。

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class DragAndDropWithLine extends Application 

    @Override
    public void start(Stage primaryStage) 
        Pane pane = new Pane();
        Rectangle rect1 = new Rectangle(50, 50, 50, 100);
        rect1.setFill(Color.YELLOW);

        Rectangle rect2 = new Rectangle(200, 50, 50, 100);
        rect2.setFill(Color.BLUE);

        Line line = new Line();
        line.setMouseTransparent(true);

        pane.getChildren().addAll(rect1, rect2);

        BooleanProperty dragging = new SimpleBooleanProperty();
        BooleanProperty draggingOverRect2 = new SimpleBooleanProperty();

        rect1.setOnDragDetected(event -> 
            rect1.startFullDrag();
            Point2D mouseSceneCoords = new Point2D(event.getSceneX(), event.getSceneY());
            Point2D mousePaneCoords = pane.sceneToLocal(mouseSceneCoords);
            line.setStartX(mousePaneCoords.getX());
            line.setStartY(mousePaneCoords.getY());
            line.setEndX(mousePaneCoords.getX());
            line.setEndY(mousePaneCoords.getY());
            pane.getChildren().add(line);
            dragging.set(true);
        );

        pane.setOnMouseDragged(event -> 
            if (dragging.get()) 
                line.setEndX(event.getX());
                line.setEndY(event.getY());
            
        );

        rect1.setOnMouseReleased(event -> 
            if (draggingOverRect2.get()) 
                pane.getChildren().remove(rect1);
                rect2.setFill(Color.GREEN);
            
            dragging.set(false);
            draggingOverRect2.set(false);
            pane.getChildren().remove(line);
        );

        rect2.setOnMouseDragEntered(event -> 
            if (dragging.get()) 
                draggingOverRect2.set(true);
            
        );

        rect2.setOnMouseDragExited(event -> draggingOverRect2.set(false));


        primaryStage.setScene(new Scene(pane, 300, 200));
        primaryStage.show();
    

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

【讨论】:

非常感谢。你让我走上了正确的轨道,让它按预期工作。猜猜这有助于更深入地研究文档:-)

以上是关于拖放与视觉指示的主要内容,如果未能解决你的问题,请参考以下文章

IOS拖放与缩放

如何使用 jQuery 拖放与段落元素

拖放与物理行为

如何让 jQueryUI 拖放与触摸设备一起使用

AngularJS - 将拖放与流程图相结合

QListWidget 拖放与通过 setItemWidget 设置的自定义小部件