2017-03-16 85 views
1

我正在製作一個遊戲,用戶需要將ImageView拖動到GridPane上,同時拖動它,我希望它們能夠按一個鍵旋轉ImageView。我只希望他們能夠在拖動ImageView時旋轉ImageView,因此我在拖動事件啓動時設置了KeyEvent處理程序,然後將其刪除。在JavaFX中同時處理KeyEvent和MouseEvent

這裏是將處理器設置代碼:

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處理程序添加到另一個對象,然後將更改應用到我想要更改的對象,但不起作用。我也嘗試了線程和任務的各種組合。

回答

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; 
    } 
} 
+0

但我想從ImageView中處理KeyEvent,它是一個JavaFX節點,而不是從拖拽板上的任何東西。 –

+0

當您執行拖放操作時,被拖動的對象不是您的ImageView。它是一個本機系統對象,它顯示傳遞給DragBoard.setDragView的圖像。在拖動過程中,沒有節點具有鍵盤焦點,因此不會看到按鍵。 – VGR

+0

我知道被拖動的對象不是我的ImageView,但我不知道它阻止任何具有鍵盤焦點的節點。謝謝。 –