【问题标题】:Handling both a KeyEvent and MouseEvent at the same time in JavaFX在 JavaFX 中同时处理 KeyEvent 和 MouseEvent
【发布时间】:2017-03-16 10:53:30
【问题描述】:

我正在制作一个游戏,用户需要将 ImageView 拖到 GridPane 上,当他们拖动它时,我希望他们能够按下一个键来旋转 ImageView。我只希望他们能够在拖动时旋转 ImageView,因此我在拖动事件开始时设置 KeyEvent 处理程序,然后将其删除。

这是设置处理程序的代码:

private void setPlacementHandlers()
{
    setOnMouseMoved(event -> trackMouse(event));
    setOnDragDetected(event -> pickedUp(event));
    setOnDragDone(event -> placed(event));
}      

这是 OnDragDetected 的代码:

private void pickedUp(MouseEvent event)
{
    //Get variables from Ship
    ShipPart[] parts = ship.getParts();
    int shipSize = ship.getSize();

    Dragboard db = this.startDragAndDrop(TransferMode.MOVE);

    ship.getBoard().setDraggedPart(this);

    ClipboardContent cbContent = new ClipboardContent();
    cbContent.putImage(this.getImage());

    db.setDragView(shipImage);

    db.setDragViewOffsetX((partIndex * 50) + mouseX);
    db.setDragViewOffsetY(mouseY);

    db.setContent(cbContent);

    setFocusTraversable(true);
    requestFocus();

    setOnKeyPressed(keyEvent -> rotate(keyEvent, db, cbContent));
    getScene().onKeyPressedProperty().bind(this.onKeyPressedProperty());

    for(int i = 0; i < shipSize; i++)
        parts[i].setVisible(false);

    event.consume();
}

这是我用于测试目的的 OnKeyPressed 临时版本:

private void rotate(KeyEvent keyEvent, Dragboard db, ClipboardContent cbContent)
{
    System.out.println("Potato");
}

我试过 setFocusTraversable(true);和 requestFocus();

出于调试的目的,我删除了在拖动完成后删除 KeyEvent 处理程序的代码,结果表明 KeyEvent 在 DragEvent 之后工作正常,但在拖动期间不能正常工作。

总而言之,问题似乎不在于 ImageView 没有获得 KeyEvent,它几乎似乎因为 DragEvent 而没有生成 KeyEvent。

感谢任何帮助。

更新:我还尝试将 KeyEvent 处理程序添加到另一个对象,然后将更改应用到我想要更改的对象,但这不起作用。我还尝试了线程和任务的各种组合。

【问题讨论】:

    标签: java javafx event-handling


    【解决方案1】:

    拖放操作是本机系统操作。它显示的任何图形都是本机对象,而不是 Java 应用程序的一部分,尽管系统为应用程序提供了有限的配置能力,Java 通过 Dragboard 等类提供访问权限。

    由于拖动的对象不是 JavaFX 节点,因此无法侦听其上的(大多数)关键事件。事实上,当拖动发生时,程序中的节点很可能没有键盘焦点。

    如果拖动源和拖动目标都在同一个场景中,您可以自己模拟拖动,方法是将场景的内容放在 StackPane 中,然后在同一个 StackPane 中放置一个“拖动窗格”以使其处于打开状态内容的顶部,带有一个剪辑,以确保它不会阻止内容的键盘或鼠标事件。拖动窗格既包含可拖动节点的副本(在您的情况下为 ImageView),也包含用于突出显示当前在拖动下的任何节点的形状。

    import java.nio.file.Paths;
    import java.util.List;
    
    import javafx.application.Application;
    
    import javafx.beans.Observable;
    import javafx.geometry.Bounds;
    import javafx.geometry.Insets;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    
    import javafx.stage.Stage;
    
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.control.SplitPane;
    import javafx.scene.image.ImageView;
    
    import javafx.scene.shape.Polyline;
    import javafx.scene.shape.Rectangle;
    import javafx.scene.shape.Shape;
    
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.GridPane;
    import javafx.scene.layout.Pane;
    import javafx.scene.layout.Region;
    import javafx.scene.layout.StackPane;
    
    import javafx.scene.input.KeyEvent;
    import javafx.scene.input.MouseEvent;
    
    import javafx.scene.paint.Color;
    
    public class ImageDragExample
    extends Application {
        private static final String DEFAULT_IMAGE =
            "http://solarsystem.nasa.gov/images/galleries/618486main_earth_320.jpg";
    
        private GridPane grid;
    
        private ImageView preview;
        private ImageView dragImage;
        private Pane dragPane;
        private Rectangle dragPaneClip;
    
        private Point2D dragStart;
        private Node dragTarget;
        private Shape dragHighlight;
    
        @Override
        public void start(Stage stage) {
            grid = new GridPane();
            grid.setHgap(24);
            grid.setVgap(24);
            grid.setPadding(new Insets(12));
            int id = 0;
            for (int row = 0; row < 3; row++) {
                Node p1 = createPlaceholder(String.valueOf(row * 4 + 1));
                Node p2 = createPlaceholder(String.valueOf(row * 4 + 2));
                Node p3 = createPlaceholder(String.valueOf(row * 4 + 3));
                Node p4 = createPlaceholder(String.valueOf(row * 4 + 4));
                grid.addRow(row, p1, p2, p3, p4);
            }
    
            List<String> args = getParameters().getRaw();
            preview = new ImageView(args.isEmpty() ? DEFAULT_IMAGE :
                Paths.get(args.get(0)).toUri().toString());
    
            BorderPane imageArea = new BorderPane(preview);
            imageArea.setPadding(new Insets(12));
    
            Region contents = new BorderPane(new SplitPane(grid, imageArea));
    
            dragImage = new ImageView();
            dragImage.imageProperty().bind(preview.imageProperty());
            dragImage.setFocusTraversable(true);
            dragImage.setOpacity(0);
            dragImage.setOnMousePressed(e -> startDrag(e));
            dragImage.setOnMouseDragged(e -> updateDrag(e));
            dragImage.setOnMouseReleased(e -> endDrag(e));
            dragImage.setOnKeyPressed(e -> rotate(e));
    
            dragPane = new AnchorPane(dragImage);
            dragPaneClip = new Rectangle();
            dragPane.setClip(dragPaneClip);
            StackPane pane = new StackPane(contents, dragPane);
    
            Scene scene = new Scene(pane);
            stage.setScene(scene);
    
            preview.boundsInParentProperty().addListener(this::placeDragImage);
            imageArea.boundsInParentProperty().addListener(this::placeDragImage);
            stage.widthProperty().addListener(this::placeDragImage);
            stage.heightProperty().addListener(this::placeDragImage);
            placeDragImage(null);
    
            stage.setTitle("Image Drag Example");
            stage.show();
        }
    
        private void rotate(KeyEvent e){
            System.out.println(e.getCode() + " pressed");
        }
    
        private void startDrag(MouseEvent event){
            dragStart = new Point2D(event.getScreenX(), event.getScreenY());
            dragImage.setOpacity(0.5);
            dragImage.requestFocus();
            dragPane.setClip(null);
        }
    
        private void updateDrag(MouseEvent event){
            double x = event.getScreenX();
            double y = event.getScreenY();
            double xDelta = x - dragStart.getX();
            double yDelta = y - dragStart.getY();
            dragImage.setTranslateX(xDelta);
            dragImage.setTranslateY(yDelta);
    
            Node newDragTarget = null;
            for (Node node : grid.getChildren()) {
                if (node.contains(node.screenToLocal(x, y))) {
                    newDragTarget = node;
                    break;
                }
            }
    
            removeDragHighlight();
            dragTarget = newDragTarget;
            addDragHighlight(dragTarget);
        }
    
        private void endDrag(MouseEvent event){
            if (dragTarget != null) {
                removeDragHighlight();
                System.out.println("Dropped on " + dragTarget.getId());
            }
    
            dragImage.setOpacity(0);
            dragImage.setTranslateX(0);
            dragImage.setTranslateY(0);
            dragPane.setClip(dragPaneClip);
            dragStart = null;
            dragTarget = null;
        }
    
        private void placeDragImage(Observable o) {
            if (preview.getScene() != null && dragImage.getScene() != null) {
                Point2D point = preview.localToScene(0, 0);
                if (point != null) {
                    point = dragImage.getParent().sceneToLocal(point);
                    AnchorPane.setLeftAnchor(dragImage, point.getX());
                    AnchorPane.setTopAnchor(dragImage, point.getY());
                    dragPaneClip.setX(point.getX());
                    dragPaneClip.setY(point.getY());
                    dragPaneClip.setWidth(dragImage.getLayoutBounds().getWidth());
                    dragPaneClip.setHeight(dragImage.getLayoutBounds().getHeight());
                }
            }
        }
    
        private void addDragHighlight(Node node) {
            if (node != null) {
                Bounds bounds = node.getBoundsInLocal();
    
                dragHighlight = null;
                if (node instanceof Region) {
                    dragHighlight = ((Region) node).getShape();
                }
                if (dragHighlight == null) {
                    dragHighlight = new Rectangle(
                        bounds.getMinX(), bounds.getMinY(),
                        bounds.getWidth(), bounds.getHeight());
                } else {
                    // Clone the node's shape by subtracting an empty shape from it.
                    dragHighlight = Shape.subtract(dragHighlight, new Polyline());
                }
                dragHighlight.setStrokeWidth(2);
                dragHighlight.setStroke(Color.RED);
                dragHighlight.setFill(null);
    
                bounds = dragHighlight.getBoundsInLocal();
                Point2D shapeOrigin = 
                    node.localToScene(bounds.getMinX(), bounds.getMinY());
                shapeOrigin = dragPane.sceneToLocal(shapeOrigin);
    
                dragPane.getChildren().add(dragHighlight);
                AnchorPane.setLeftAnchor(dragHighlight, shapeOrigin.getX());
                AnchorPane.setTopAnchor(dragHighlight, shapeOrigin.getY());
            }
        }
    
        private void removeDragHighlight() {
            if (dragHighlight != null) {
                dragPane.getChildren().remove(dragHighlight);
                dragHighlight = null;
            }
        }
    
        private Node createPlaceholder(String id) {
            Label label = new Label(id);
            label.setId(id);
            label.setAlignment(Pos.CENTER);
            label.setStyle("-fx-background-color: #c0c0ff;");
            label.setPrefSize(200, 200);
            return label;
        }
    }
    

    【讨论】:

    • 但我正在尝试处理来自作为 JavaFX 节点的 ImageView 的 KeyEvent,而不是来自拖动板上的任何内容。
    • 当你执行拖放操作时,被拖动的对象不是你的ImageView。它是一个本地系统对象,显示传递给 DragBoard.setDragView 的图像。在该拖动过程中,没有节点具有键盘焦点,因此不会看到按键。
    • 我知道被拖动的对象不是我的 ImageView,但我不知道它会阻止任何具有键盘焦点的节点。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多