1. ホーム
  2. java

[解決済み] setOnKeyPressed イベントが正しく動作しない

2022-02-16 15:54:18

質問

大学のプロジェクトで、曲線を使ったトンネルのようなものを生成する必要に迫られています。インターネットで、曲線のコントロールポイント(Anchorオブジェクトに付いている)をドラッグできるコードを見つけました。

しかし、矢印キー("up"と"down")でコントロールポイントのY位置を変更できるようにしたかったのですが、なぜか全くうまくいきません。この問題を自分で解決しようと絶望的になっているのですが、出口が見つかりません。

import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;

/** Example of how a cubic curve works, drag the anchors around to change the curve. */
public class testsdfasdf extends Application {
  public static void main(String[] args) throws Exception { launch(args); }


  @Override public void start(Stage primaryStage) throws Exception {
    QuadCurve curve = createStartingCurve();


    final BorderPane root = new BorderPane();
    Scene scene = new Scene(root, 1000, 1000);

    final Anchor control2 = new Anchor(Color.GOLDENROD, curve.controlXProperty(), curve.controlYProperty());


    root.getChildren().add(curve);
    root.getChildren().add(control2);


    primaryStage.setTitle("Quadcurve Manipulation");
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  private QuadCurve createStartingCurve() {
    QuadCurve curve = new QuadCurve();
    curve.setStartX(100);
    curve.setStartY(100);
    curve.setControlX(200);
    curve.setControlY(50);
    curve.setEndX(300);
    curve.setEndY(100);
    curve.setStroke(Color.BLACK);
    curve.setStrokeWidth(10);
    curve.setStrokeLineCap(StrokeLineCap.ROUND);
    curve.setFill(Color.CORNSILK.deriveColor(0, 1.2, 1, 0.6));
    return curve;
  }

  // a draggable anchor displayed around a point.
  class Anchor extends Circle { 

      Anchor(Color color, DoubleProperty x, DoubleProperty y) {
      super(x.get(), y.get(), 10);
      setFill(color.deriveColor(1, 1, 1, 0.5));

      y.bind(centerYProperty());
      enableDrag();
      changeCurve();
    }


    private void changeCurve() {
        setOnKeyPressed((event) -> { 
                System.out.println(event.getCode() == KeyCode.DOWN);
                if (event.getCode() == KeyCode.DOWN) {
                    double newY = getCenterY();
                    while (newY > 0 && newY < getScene().getHeight()) {
                        setCenterY(newY);
                        newY+=1;
                    }
                }
                else if (event.getCode() == KeyCode.UP) {
                    double newY = getCenterY();
                    while (newY > 0 && newY < getScene().getHeight()) {
                        setCenterY(newY);
                        newY-=1;
                    }
                }
        });
        setOnKeyReleased((event) -> {
                if (event.getCode() == KeyCode.DOWN) {
                }
                if (event.getCode() == KeyCode.UP) {
                }

            });
    }

    // make a node movable by dragging it around with the mouse.
    private void enableDrag() {
      setOnMousePressed(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent mouseEvent) {
          // record a delta distance for the drag and drop operation.
          getScene().setCursor(Cursor.MOVE);
        }
      });
      setOnMouseReleased(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent mouseEvent) {
          getScene().setCursor(Cursor.HAND);
        }
      });
      setOnMouseDragged(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent mouseEvent) {
          double newY = mouseEvent.getY();
          System.out.println(newY);
          if (newY > 0 && newY < getScene().getHeight()) {
            setCenterY(newY);
          }  
        }
      });
      setOnMouseEntered(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent mouseEvent) {
          if (!mouseEvent.isPrimaryButtonDown()) {
            getScene().setCursor(Cursor.HAND);
          }
        }
      });
      setOnMouseExited(new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent mouseEvent) {
          if (!mouseEvent.isPrimaryButtonDown()) {
            getScene().setCursor(Cursor.DEFAULT);
          }
        }
      });
    }
  }  
}

コードが多すぎるかもしれません。しかし、これは実際に曲線を描き、それを enableDrag() という関数があります。

チェンジカーブ() 関数が動作していないことが問題です。

どうすればいいですか?

問題点

ノードはフォーカスを当てないとイベントを聞きません。あなたのサークルはフォーカスを受けることがないため、キーイベントに反応することがありません。

解決方法

の1つです。 簡単 の解決策は、ステージが表示された後にフォーカスを要求することです。

primaryStage.show();
control2.requestFocus();

もう一つの解決策は、シーンの onKeyPressedProperty をサークルの onKeyPressedProperty . これにより、シーン上で起きているすべてのキー押下イベントがCircleにバインドされます。

このようなことをしたくない状況もあるかもしれません。

scene.onKeyPressedProperty().bind(control2.onKeyPressedProperty());

また、あなたの handle() もそうです。は必要ありません。 while loop . あなたはただ setCenterY() を、押されたキーに応じて、前の値より小さい/大きい値に変更します。

setOnKeyPressed((event) -> {
     if (event.getCode() == KeyCode.DOWN && getCenterY() < getScene().getHeight()){
         setCenterY(getCenterY() + 5);
     } else if (event.getCode() == KeyCode.UP && getCenterY() > 0) {
         setCenterY(getCenterY() - 5);
     }
});