在javafx中使用show snapshot拖放vbox元素

时间:2014-03-15 12:55:58

标签: drag-and-drop javafx-2

我想在vbox中拖动一个元素作为父元素,并在拖放元素期间显示节点移动,如何通过最轻微的更改来实现。

3 个答案:

答案 0 :(得分:4)

只需使用VBox的元素注册鼠标监听器即可。您希望在dragDetected事件上的节点上调用startFullDrag(),并在dragReleased事件上旋转VBox的子节点。如果要向用户提供有关拖动的视觉提示,可以使用dragEntered和dragExited事件。

有关详情,请参阅API docs

简单示例(代码在JavaFX 8中更清晰,顺便说一下):

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            final VBox root = new VBox(5);
            final ScrollPane scroller = new ScrollPane();
            scroller.setContent(root);
            final Scene scene = new Scene(scroller,400,200);

            for (int i=1; i<=20; i++) {
                final Label label = new Label("Item "+i);
                addWithDragging(root, label);
            }

            // in case user drops node in blank space in root:
            root.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
                @Override
                public void handle(MouseDragEvent event) {
                    int indexOfDraggingNode = root.getChildren().indexOf(event.getGestureSource());
                    rotateNodes(root, indexOfDraggingNode, root.getChildren().size()-1);
                }
            });

            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    private void addWithDragging(final VBox root, final Label label) {
        label.setOnDragDetected(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                label.startFullDrag();
            }
        });

        // next two handlers just an idea how to show the drop target visually:
        label.setOnMouseDragEntered(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                label.setStyle("-fx-background-color: #ffffa0;");
            }
        });
        label.setOnMouseDragExited(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                label.setStyle("");
            }
        });

        label.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                label.setStyle("");
                int indexOfDraggingNode = root.getChildren().indexOf(event.getGestureSource());
                int indexOfDropTarget = root.getChildren().indexOf(label);
                rotateNodes(root, indexOfDraggingNode, indexOfDropTarget);
                event.consume();
            }
        });
        root.getChildren().add(label);
    }

    private void rotateNodes(final VBox root, final int indexOfDraggingNode,
            final int indexOfDropTarget) {
        if (indexOfDraggingNode >= 0 && indexOfDropTarget >= 0) {
            final Node node = root.getChildren().remove(indexOfDraggingNode);
            root.getChildren().add(indexOfDropTarget, node);
        }
    }


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

答案 1 :(得分:3)

这是@James_D's excellent answer

的附录

这显示了如何在@James_D的评论中建议将图像预览添加到可拖动节点:

     private void addPreview(final VBox root, final Label label) {
        ImageView imageView = new ImageView(label.snapshot(null, null));
        imageView.setManaged(false);
        imageView.setMouseTransparent(true);
        root.getChildren().add(imageView);
        root.setUserData(imageView);
        root.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                imageView.relocate(event.getX(), event.getY());
            }
        });
    }

    private void removePreview(final VBox root) {
        root.setOnMouseDragged(null);
        root.getChildren().remove(root.getUserData());
        root.setUserData(null);
    }

addPreview()中致电label.setOnDragDetected()。在removePreview()label.setOnMouseDragReleased()root.setOnMouseDragReleased()中致电{{1}}。

答案 2 :(得分:2)

有一个更好的解决方案,现在更清洁。

// Root is the node you want to drag, not the scene root.
root.setOnDragDetected(mouseEvent -> {
    final ImageView preview = new ImageView(root.snapshot(null, null));

    final Dragboard db = root.startDragAndDrop(TransferMode.ANY);
    db.setContent( // Set your content to something here.
    );
    db.setDragView(preview.getImage());

    mouseEvent.consume();
});