当前位置: 首页 > 知识库问答 >
问题:

实现拖动多个选定节点

羊昊苍
2023-03-14
Class DraggableNode extends Node
{
    ...
     onMouseDraggedProperty().set(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
               offsetX = dragStartPoitionX - event.getSceneX();
               offsetY = dragStartPoitionY - event.getSceneY();
               setLayoutX (event.getSceneX());
               setLayoutY (event.getSceneY());
                 ...
            }
     }
 }

共有1个答案

汤乐家
2023-03-14

首先创建一个选择模型,比如一个set 。无论何时向选定内容添加节点,都将其添加到选定内容模型中。

拖动节点时,只需更改选择模型中所有其他节点在事件处理程序中的位置。

就这么简单。

import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeLineCap;
import javafx.stage.Stage;

public class NodeSelection extends Application {

    public static Image image = new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/320px-Siberischer_tiger_de_edit02.jpg");
//  public Image image = new Image( getClass().getResource( "tiger.jpg").toExternalForm());

    SelectionModel selectionModel = new SelectionModel();

    DragMouseGestures dragMouseGestures = new DragMouseGestures();

    static Random rnd = new Random();

    @Override
    public void start(Stage primaryStage) {

        Pane pane = new Pane();
        pane.setStyle("-fx-background-color:white");

        new RubberBandSelection( pane);

        double width = 200;
        double height = 160;

        double padding = 20;
        for( int row=0; row < 4; row++) {
            for( int col=0; col < 4; col++) {

                Selectable selectable = new Selectable( width, height);
                selectable.relocate( padding * (col+1) + width * col, padding * (row + 1) + height * row);

                pane.getChildren().add(selectable);

                dragMouseGestures.makeDraggable(selectable);

            }
        }

        Label infoLabel = new Label( "Drag on scene for Rubberband Selection. Shift+Click to add to selection, CTRL+Click to toggle selection. Drag selected nodes for multi-dragging.");
        pane.getChildren().add( infoLabel);

        Scene scene = new Scene( pane, 1600, 900);
        scene.getStylesheets().add( getClass().getResource("application.css").toExternalForm());

        primaryStage.setScene( scene);
        primaryStage.show();        



    }

    private class Selectable extends Region {

        ImageView view;

        public Selectable( double width, double height) {

            view = new ImageView( image);
            view.setFitWidth(width);
            view.setFitHeight(height);

            getChildren().add( view);

            this.setPrefSize(width, height);
        }

    }

    private class SelectionModel {

        Set<Node> selection = new HashSet<>();

        public void add( Node node) {

            if( !node.getStyleClass().contains("highlight")) {
                node.getStyleClass().add( "highlight");
            }

            selection.add( node);
        }

        public void remove( Node node) {
            node.getStyleClass().remove( "highlight");
            selection.remove( node);
        }

        public void clear() {

            while( !selection.isEmpty()) {
                remove( selection.iterator().next());
            }

        }

        public boolean contains( Node node) {
            return selection.contains(node);
        }

        public int size() {
            return selection.size();
        }

        public void log() {
            System.out.println( "Items in model: " + Arrays.asList( selection.toArray()));
        }

    }

    private class DragMouseGestures {

        final DragContext dragContext = new DragContext();

        private boolean enabled = false;

        public void makeDraggable(final Node node) {

            node.setOnMousePressed(onMousePressedEventHandler);
            node.setOnMouseDragged(onMouseDraggedEventHandler);
            node.setOnMouseReleased(onMouseReleasedEventHandler);

        }

        EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

                // don't do anything if the user is in the process of adding to the selection model
                if( event.isControlDown() || event.isShiftDown())
                    return;

                Node node = (Node) event.getSource();

                dragContext.x = node.getTranslateX() - event.getSceneX();
                dragContext.y = node.getTranslateY() - event.getSceneY();

                // clear the model if the current node isn't in the selection => new selection
                if( !selectionModel.contains(node)) {
                    selectionModel.clear();
                    selectionModel.add( node);
                }

                // flag that the mouse released handler should consume the event, so it won't bubble up to the pane which has a rubberband selection mouse released handler
                enabled = true;

                // prevent rubberband selection handler 
                event.consume();
            }
        };

        EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

                if( !enabled)
                    return;

                // all in selection
                for( Node node: selectionModel.selection) {
                    node.setTranslateX( dragContext.x + event.getSceneX());
                    node.setTranslateY( dragContext.y + event.getSceneY());
                }

            }
        };

        EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

                // prevent rubberband selection handler 
                if( enabled) {

                    // set node's layout position to current position,remove translate coordinates
                    for( Node node: selectionModel.selection) {
                        fixPosition(node);
                    }

                    enabled = false;

                    event.consume();
                }
            }
        };

        /**
         * Set node's layout position to current position, remove translate coordinates.
         * @param node
         */
        private void fixPosition( Node node) {

            double x = node.getTranslateX();
            double y = node.getTranslateY();

            node.relocate(node.getLayoutX() + x, node.getLayoutY() + y);

            node.setTranslateX(0);
            node.setTranslateY(0);

        }

        class DragContext {

            double x;
            double y;

        }

    }

    private class RubberBandSelection {

        final DragContext dragContext = new DragContext();
        Rectangle rect;

        Pane group;
        boolean enabled = false;

        public RubberBandSelection( Pane group) {

            this.group = group;

            rect = new Rectangle( 0,0,0,0);
            rect.setStroke(Color.BLUE);
            rect.setStrokeWidth(1);
            rect.setStrokeLineCap(StrokeLineCap.ROUND);
            rect.setFill(Color.LIGHTBLUE.deriveColor(0, 1.2, 1, 0.6));

            group.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler);
            group.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler);
            group.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler);

        }

        EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

                // simple flag to prevent multiple handling of this event or we'd get an exception because rect is already on the scene
                // eg if you drag with left mouse button and while doing that click the right mouse button
                if( enabled)
                    return;

                dragContext.mouseAnchorX = event.getSceneX();
                dragContext.mouseAnchorY = event.getSceneY();

                rect.setX(dragContext.mouseAnchorX);
                rect.setY(dragContext.mouseAnchorY);
                rect.setWidth(0);
                rect.setHeight(0);

                group.getChildren().add( rect);

                event.consume();

                enabled = true;
            }
        };

        EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

                if( !event.isShiftDown() && !event.isControlDown()) {
                    selectionModel.clear();
                }

                for( Node node: group.getChildren()) {

                    if( node instanceof Selectable) {
                        if( node.getBoundsInParent().intersects( rect.getBoundsInParent())) {

                            if( event.isShiftDown()) {

                                selectionModel.add( node);

                            } else if( event.isControlDown()) {

                                if( selectionModel.contains( node)) {
                                    selectionModel.remove( node);
                                } else {
                                    selectionModel.add( node);
                                }
                            } else {
                                selectionModel.add( node);
                            }

                        }
                    }

                }

                selectionModel.log();

                rect.setX(0);
                rect.setY(0);
                rect.setWidth(0);
                rect.setHeight(0);

                group.getChildren().remove( rect);

                event.consume();

                enabled = false;
            }
        };

        EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

                double offsetX = event.getSceneX() - dragContext.mouseAnchorX;
                double offsetY = event.getSceneY() - dragContext.mouseAnchorY;

                if( offsetX > 0)
                    rect.setWidth( offsetX);
                else {
                    rect.setX(event.getSceneX());
                    rect.setWidth(dragContext.mouseAnchorX - rect.getX());
                }

                if( offsetY > 0) {
                    rect.setHeight( offsetY);
                } else {
                    rect.setY(event.getSceneY());
                    rect.setHeight(dragContext.mouseAnchorY - rect.getY());
                }

                event.consume();

            }
        };

        private final class DragContext {

            public double mouseAnchorX;
            public double mouseAnchorY;


        }
    }


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

}
.highlight {
    -fx-effect: dropshadow(three-pass-box, red, 4, 4, 0, 0);
}
 类似资料:
  • 本文向大家介绍Android自定义View实现拖动选择按钮,包括了Android自定义View实现拖动选择按钮的使用技巧和注意事项,需要的朋友参考一下 本文为大家分享了Android实现拖动选择按钮的具体代码,供大家参考,具体内容如下 效果图 View代码 第一步:自定义属性 第二步:自定义圆形 第三步:自定义拖动按钮 使用方法 布局文件: 页面代码: 以上就是本文的全部内容,希望对大家的学习有所

  • https://play.vuejs.org/#eNqlVE2PmzAQ/StTLkskStIes9nVtmpV9dBL1... 上面地址中的代码需要修改成: 1:鼠标在红或绿色div上按下后移动鼠标,则相应的div会随着鼠标移动。 2:不管是红还是绿色div鼠标按下移动时不能超出窗口的边界。 有人知道怎么修改不?对鼠标那块的知识不怎么熟,学了忘。

  • 我正在尝试将一个矩形拖动到VBox,然后从VBox内部再次拖动它。 如果矩形被放置在目标VBox之外的任何位置,那么它应该将其位置恢复到它所属的位置:如果它是左VBox的子级,则将其重置回其中;如果它是右VBox的子级,则将其重置回右VBox内部。 第一部分工作正常,我可以将其拖到VBox并将其添加为子级。第二部分是我遇到问题的地方。 重现问题的步骤:<br>1)将左矩形拖动到右矩形的顶部(在VB

  • 问题内容: 我试图在这个问题中创建一个类似于“奖杯轮”的可旋转节点。到目前为止,我具有甩尾功能,可以使用效果很好的UIPanGestureRecognizer在物理物体上添加角度脉冲。我也可以通过触摸停止旋转。 现在,我试图通过拖动或滑动手势来微调方向盘,这样,如果玩家对最终的效果不满意,就可以手动旋转/拖动/旋转它所喜欢的旋转方式。 目前,我将触摸的位置保存在touchesBegan中,并尝试在

  • 本文向大家介绍Android自定义view实现拖动小球移动,包括了Android自定义view实现拖动小球移动的使用技巧和注意事项,需要的朋友参考一下 Android应用界面中可以看得见的都是由一个个的View所组成的,几乎所有的可视的控件都是基于View写的。在View中提供了对touch也就是手势的捕获和传递,我们可以对View里面手势的重写来达到我们所需要的特性。比如说我们现在要做一款游戏,

  • 本文向大家介绍js实现鼠标拖拽多选功能示例,包括了js实现鼠标拖拽多选功能示例的使用技巧和注意事项,需要的朋友参考一下 最近做了一个用js实现鼠标拖拽多选的功能,于是整理了一下思路,写了一个小demo: 遮罩出现: 被遮罩盖住的,即为选中的块(背景色为粉色) 下面是具体代码,注释已在文中,与大家交流。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。