12

JavaFXニーモニックを機能させようとしています。シーンにいくつかのボタンがあり、達成したいのは、Ctrl + S を押してこのボタン イベントを発生させることです。コードスケルトンは次のとおりです。

@FXML
public Button btnFirst;

btnFirst.getScene().addMnemonic(new Mnemonic(btnFirst, 
            new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN)));

ボタンの mnemonicParsing が false です。(まあ、これを機能させようとしているときに、trueに設定しようとしましたが、結果はありません)。JavaFX のドキュメントでは、ニーモニックがシーンに登録され、KeyCombination が消費されていないシーンに到達すると、ターゲット ノードに ActionEvent が送信されると記載されています。しかし、これは機能しません。おそらく、私は間違っています...

標準のボタンのニーモニックを使用できます (mnemonicParsing を true に設定し、「F」文字の​​前にアンダースコア文字を付けます)。しかし、この方法では、ユーザーは Alt キーを使用する必要があり、メニュー バーのあるブラウザーで奇妙な動作が発生します (アプリケーションが Web ページに埋め込まれている場合、Alt+S を押してボタン イベントを発生させた後にブラウザーのメニューがアクティブになります)。また、標準的な方法では、Ctrl+Shift+F3 などのショートカットを作成できません。

それで、これを機能させる方法があれば?

4

1 に答える 1

23

あなたのユースケースでは、実際にはニーモニックではなくアクセラレータを使用したいと思います。

button.getScene().getAccelerators().put(
  new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN), 
  new Runnable() {
    @Override public void run() {
      button.fire();
    }
  }
);

ほとんどの場合、上記のコードのように、修飾子指定子として KeyCombination.SHORTCUT_DOWN を使用することをお勧めします。これについての適切な説明は、KeyCombinationのドキュメントにあります。

ショートカット修飾子は、ホスト プラットフォームのキーボード ショートカットで一般的に使用される修飾キーを表すために使用されます。これは、たとえば、Windows ではコントロール、Mac ではメタ (コマンド キー) です。ショートカット キー修飾子を使用することで、開発者はプラットフォームに依存しないショートカットを作成できます。そのため、「Shortcut+C」キーの組み合わせは、Windows では「Ctrl+C」、Mac では「Meta+C」として内部的に処理されます。

Ctrl+S キーの組み合わせのみを処理するように具体的にコーディングしたい場合は、次を使用できます。

new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN)

実行可能な例を次に示します。

import javafx.animation.*;
import javafx.application.Application;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.input.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class SaveMe extends Application {
  @Override public void start(final Stage stage) throws Exception {
    final Label response = new Label();
    final ImageView imageView = new ImageView(
      new Image("http://icons.iconarchive.com/icons/gianni-polito/colobrush/128/software-emule-icon.png")
    );
    final Button button = new Button("Save Me", imageView);
    button.setStyle("-fx-base: burlywood;");
    button.setContentDisplay(ContentDisplay.TOP);
    displayFlashMessageOnAction(button, response, "You have been saved!");

    layoutScene(button, response, stage);
    stage.show();

    setSaveAccelerator(button);
  }

  // sets the save accelerator for a button to the Ctrl+S key combination.
  private void setSaveAccelerator(final Button button) {
    Scene scene = button.getScene();
    if (scene == null) {
      throw new IllegalArgumentException("setSaveAccelerator must be called when a button is attached to a scene");
    }

    scene.getAccelerators().put(
      new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN), 
      new Runnable() {
        @Override public void run() {
          fireButton(button);
        }
      }
    );
  }

  // fires a button from code, providing visual feedback that the button is firing.
  private void fireButton(final Button button) {
    button.arm();
    PauseTransition pt = new PauseTransition(Duration.millis(300));
    pt.setOnFinished(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent event) {
        button.fire();
        button.disarm();
      }
    });
    pt.play();
  }

  // displays a temporary message in a label when a button is pressed, 
  // and gradually fades the label away after the message has been displayed.
  private void displayFlashMessageOnAction(final Button button, final Label label, final String message) {
    final FadeTransition ft = new FadeTransition(Duration.seconds(3), label);
    ft.setInterpolator(Interpolator.EASE_BOTH);
    ft.setFromValue(1);
    ft.setToValue(0);
    button.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent event) {
        label.setText(message);
        label.setStyle("-fx-text-fill: forestgreen;");
        ft.playFromStart();
      }
    });
  }

  private void layoutScene(final Button button, final Label response, final Stage stage) {
    final VBox layout = new VBox(10);
    layout.setPrefWidth(300);
    layout.setAlignment(Pos.CENTER);
    layout.getChildren().addAll(button, response);
    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 20; -fx-font-size: 20;");
    stage.setScene(new Scene(layout));
  }

  public static void main(String[] args) { launch(args); }
}
// icon license: (creative commons with attribution) http://creativecommons.org/licenses/by-nc-nd/3.0/
// icon artist attribution page: (eponas-deeway) http://eponas-deeway.deviantart.com/gallery/#/d1s7uih

出力例:

サンプルプログラムの出力

2020 年 1 月に更新、複数のコントロールに同じアクセラレータを使用

現在および以前の実装 (JavaFX 13 以前) のアクセラレーターに関する 1 つの注意点は、単一のアプリケーション内の複数のメニューまたはコントロールで使用するために、そのままでは同じアクセラレーター キーの組み合わせを定義できないことです。

詳細については、次を参照してください。

リンクされたイシュー レポートには、アプリケーション内の複数の場所 (たとえば、異なるコンテキスト メニューの 2 つの異なるメニュー項目) で同じアクセラレータを定義して使用できるようにするために使用できる回避策が含まれています。

これは、アプリケーション内の複数の場所で同じアクセラレータを使用しようとする場合にのみ適用されることに注意してください。使用する必要がない場合は、この情報を無視できます。

于 2012-10-03T18:38:42.647 に答える