如何为按钮添加 javafx 快捷组合键



我的UI有一个添加按钮,我想为此分配一个键盘快捷键组合。我未能将 setAcceleartor 用于此目的。在 javafx 应用程序中设置键盘快捷键的最简单方法是什么?

UI 中的按钮声明:

 <Button fx:id="addButton" alignment="CENTER" minWidth="-Infinity" mnemonicParsing="false" onAction="#addAction" prefHeight="31.0" prefWidth="130.0"  text="Add"  HBox.hgrow="ALWAYS" />

控制器按钮绑定:

@FXML
private Button addButton;

想要为按钮的快捷方式设置操作的方法:

    public void addAction(ActionEvent event) throws SQLException, ClassNotFoundException {
    if (validateInput()) {
        String productName = productField.getText();
        double unitPrice = Double.parseDouble(priceField.getText());
        int quantity = Integer.parseInt(quantityField.getText());
        double total = unitPrice * quantity;
        ITEMLIST.add(new Item(productName, unitPrice, quantity, total));
        calculation();
        resetAdd();
        productTableView.getSelectionModel().clearSelection();
        ObservableList<Product> productsData = ProductDAO.searchProducts();
        populateProducts(productsData);
        searchField.setText("");
    }
}

初始化(( 方法:

@FXML
private void initialize() throws SQLException, ClassNotFoundException, IOException {
  setSaveAccelerator(addButton);
}

我用setAccelerator尝试的代码:

    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() {
                @FXML public void run() {
                    button.fire();
                }
            }
    );
}

setSaveAccelerator方法中,不要直接调用 addAction(ActionEvent event) ,只需指示按钮向其侦听器触发其事件,例如:button.fire() .例如:

    private void setSaveAccelerator(Button button) {
        if(button==null) {
            System.out.println("Button is null! "); // check that the button was injected properly through your fxml
        }
        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() {
                @FXML public void run() {
                    button.fire();
                }
            }
       );
   }

编辑

若要避免IllegalArgumentException,必须在将按钮附加到场景后附加加速器。我通过在控制器中创建一个公共方法来在设置场景后附加加速器来实现这一目标。然后,在加载场景的类中,可以调用控制器的方法来设置此功能。请参阅以下示例:

在控制器类中(在我的例子中MainController(:

public void setup() {
    setSaveAccelerator(button);
}

在主类中加载 fxml 文件时:

    FXMLLoader loader = new FXMLLoader(MainController.class.getResource("mainFXML.fxml"));
    AnchorPane page = (AnchorPane) loader.load();
    MainController controller = loader.getController();
    Scene scene = new Scene(page);
    controller.setup(); // calls the setup method attaching the accelerators

完整示例

主类:

public class Main extends Application{
    public static Stage primaryStage;
    @Override
    public void start(Stage primaryStage) throws Exception {
        Main.primaryStage=primaryStage;
        FXMLLoader loader = new FXMLLoader(MainController.class.getResource("mainFXML.fxml"));
        AnchorPane page = (AnchorPane) loader.load();
        MainController controller = loader.getController();
        Scene scene = new Scene(page);
        primaryStage.setTitle("Shortcut example");
        primaryStage.setScene(scene);
        controller.setup();
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

主控制器:

public class MainController {
    @FXML
    private ResourceBundle resources;
    @FXML
    private URL location;
    @FXML
    private Button button;
    @FXML
    private AnchorPane rootPane;
    @FXML
    private TextArea textarea;
    @FXML
    void action(ActionEvent event) {
        textarea.setText("Action fired!!");
    }
    @FXML
    void initialize() {
        assert button != null : "fx:id="button" was not injected: check your FXML file 'MainFXML.fxml'.";
        assert rootPane != null : "fx:id="rootPane" was not injected: check your FXML file 'MainFXML.fxml'.";
        assert textarea != null : "fx:id="textarea" was not injected: check your FXML file 'MainFXML.fxml'.";
    }
    public void setup() {
        setSaveAccelerator(button);
    }

    private void setSaveAccelerator(Button button) {
        if(button==null) {
            System.out.println("Button null!!");
        }
        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() {
                    @FXML public void run() {
                        button.fire();
                    }
                }
                );
    }
}

MainFXML.fxml

<AnchorPane fx:id="rootPane" prefHeight="408.0" prefWidth="330.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
   <children>
      <Button fx:id="button" layoutX="139.0" layoutY="350.0" mnemonicParsing="false" onAction="#action" text="Button" />
      <TextArea fx:id="textarea" layoutX="73.0" layoutY="38.0" prefHeight="200.0" prefWidth="200.0" />
   </children>
</AnchorPane>