【问题标题】:JavaFX: How to group shapes for dragging?JavaFX:如何对形状进行分组以进行拖动?
【发布时间】:2015-02-17 17:01:25
【问题描述】:

如何在 JavaFX 中对形状(例如圆圈)进行分组以拖动它们?示例代码基于 Oracle 教程。每个单独的圆圈都可以移动。拖动时我想单独移动蓝色圆圈。我想在单击并拖动绿色圆圈时移动绿色和蓝色圆圈,并在单击并拖动红色圆圈时移动它们三个。有什么想法吗?

public class DragGroupSample extends Application {

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

    private void makeDraggable( Circle circle ) {
        DragContext dragContext = new DragContext();

        // --- remember initial coordinates of mouse cursor and node
        circle.addEventFilter( MouseEvent.MOUSE_PRESSED, (
                final MouseEvent mouseEvent ) -> {
            dragContext.dx = mouseEvent.getX() - circle.getCenterX();
            dragContext.dy = mouseEvent.getY() - circle.getCenterY();
        } );

        // --- Shift node calculated from mouse cursor movement
        circle.addEventFilter( MouseEvent.MOUSE_DRAGGED, (
                final MouseEvent mouseEvent ) -> {
            circle.setCenterX( mouseEvent.getX() + dragContext.dx );
            circle.setCenterY( mouseEvent.getY() + dragContext.dy );
        } );

        // --- Drop card onto allowed target field
        circle.addEventFilter( MouseEvent.MOUSE_RELEASED, (
                final MouseEvent mouseEvent ) -> {
            circle.setCenterX( mouseEvent.getX() + dragContext.dx );
            circle.setCenterY( mouseEvent.getY() + dragContext.dy );
        } );
    }

    @Override
    public void start( Stage primaryStage ) throws Exception {
        Circle[] circles = new Circle[3];
        circles[0] = new Circle( 30.0, 30.0, 30.0, Color.RED );
        circles[1] = new Circle( 45.0, 45.0, 30.0, Color.GREEN );
        circles[2] = new Circle( 60.0, 60.0, 30.0, Color.BLUE );
        for ( Circle circle : circles ) {
            makeDraggable( circle );
        }

        Group root = new Group();
        root.getChildren().addAll( circles[0], circles[1], circles[2] );
        primaryStage.setResizable( false );
        primaryStage.setScene( new Scene( root, 400, 350 ) );
        primaryStage.setTitle( DragGroupSample.class.getSimpleName() );
        primaryStage.show();
    }

    private static final class DragContext {
        public double dx, dy;
    }
}

【问题讨论】:

标签: javafx grouping shapes


【解决方案1】:

只需移动您要移动的所有圆圈。相对于固定的东西(如场景)存储最后一个鼠标位置可能更容易,而不是相对于圆工作。

这是一种方式,有很多:

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
import javafx.scene.Group;
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 DragGroupSample extends Application {

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

    // list of nodes that are dragged. Can be modified at any time (on the FX Application Thread):
    private final List<Circle> nodesToDrag = new ArrayList<>();

    private final Circle[] circles = new Circle[3] ;

    private void makeDraggable( Circle circle ) {
        MouseLocation lastMouseLocation = new MouseLocation();

        // --- remember initial coordinates of mouse cursor and node
        circle.addEventFilter( MouseEvent.MOUSE_PRESSED, (
                final MouseEvent mouseEvent ) -> {
            lastMouseLocation.x = mouseEvent.getSceneX() ;
            lastMouseLocation.y = mouseEvent.getSceneY() ;

            // just some example logic to modify the list of dragged nodes:
            boolean found = false ;
            for (Circle c : circles) {
                if (c == circle) found = true ;
                if (found) nodesToDrag.add(c);
            }
        } );

        // --- Shift node calculated from mouse cursor movement
        circle.addEventFilter( MouseEvent.MOUSE_DRAGGED, (
                final MouseEvent mouseEvent ) -> {
                    double deltaX = mouseEvent.getSceneX() - lastMouseLocation.x ;
                    double deltaY = mouseEvent.getSceneY() - lastMouseLocation.y ;
                    for (Circle c : nodesToDrag) {
                        c.setCenterX( c.getCenterX() + deltaX  );
                        c.setCenterY( c.getCenterY() + deltaY );
                    }
                    lastMouseLocation.x = mouseEvent.getSceneX();
                    lastMouseLocation.y = mouseEvent.getSceneY();
        } );

        circle.addEventFilter(MouseEvent.MOUSE_RELEASED, mouseEvent -> nodesToDrag.clear());

    }

    @Override
    public void start( Stage primaryStage ) throws Exception {

        circles[0] = new Circle( 30.0, 30.0, 30.0, Color.RED );
        circles[1] = new Circle( 45.0, 45.0, 30.0, Color.GREEN );
        circles[2] = new Circle( 60.0, 60.0, 30.0, Color.BLUE );

        for ( Circle circle : circles ) {
            makeDraggable( circle );
        }

        Group root = new Group();
        root.getChildren().addAll( circles[0], circles[1], circles[2] );
        primaryStage.setResizable( false );
        primaryStage.setScene( new Scene( root, 400, 350 ) );
        primaryStage.setTitle( DragGroupSample.class.getSimpleName() );
        primaryStage.show();
    }

    private static final class MouseLocation {
        public double x, y;
    }
}

【讨论】:

  • 因此解决方案是将鼠标移动应用于所有涉及的形状。我希望我可以动态创建一个组,向其中添加一些子项,然后使用 JavaFX 自动将鼠标移动应用于组的所有子项来移动组。我的示例中的圆圈(形状)的数量会随着时间而变化,因此我无法预先分配一些固定列表。感谢您的想法
  • 我想过那样做,你也许可以让它工作,但它最终会变得(非常)复杂。要更改“拖动组”中的内容,您必须先从现有父级中删除圆圈,然后将它们添加到组中。然后在某个时候(也许是鼠标释放),您需要将它们移出拖动组并将它们放回父组,并确保它们保留应用于组的翻译...
  • 另请注意,我的解决方案中没有任何内容可以阻止您动态更新将要拖动的节点列表。在这里,我实际上保留了三个这样的列表,在地图中引用,但是如果需要,您可以保留一个,并使用您想要的任何逻辑对其进行修改。我将修改解决方案以使其更像那样......
猜你喜欢
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
  • 2011-03-27
  • 1970-01-01
  • 1970-01-01
  • 2019-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多