如何将快捷方式(组合键)分配给JavaFx对话框

时间:2017-04-05 18:14:51

标签: javafx javafx-8

我还没有找到在JavaFx 8对话框中为按钮类型指定键盘快捷键的直接方法。

例如:

dialog.dialogPane().getButtonTypes.addAll(ButtonType.OK, ButtonType.Cancel)

如何将ESC键分配给ButtonType.Cancel?

感谢。

1 个答案:

答案 0 :(得分:1)

您可以使用加速器,如下所示:

JavaFX对话框在定义和使用按钮的方式上有点奇怪(并且复杂),因此添加加速器会有点复杂,但仍然有可能。下面的代码设置一个加速器,当按下一个组合键时触发按钮动作,快捷键+ f,快捷键将根据你的操作系统改变(在OS X上它是标记为#34的键;命令" )。

// Create a custom button type:
ButtonType fishingButtonType = new ButtonType( "Go fishing", ButtonBar.ButtonData.OTHER);

dialog.getDialogPane().getButtonTypes().add(fishingButtonType);

// Set an accelerator and an action for the fishing button.
Button fishingButton = (Button) dialog.getDialogPane().lookupButton(fishingButtonType);
fishingButton.addEventFilter(ActionEvent.ACTION, ae -> {
    // linkware image: http://www.iconka.com
    dialog.setGraphic(new ImageView("http://icons.iconarchive.com/icons/iconka/meow/64/cat-fish-icon.png"));
    ae.consume();  // consume the action so that the dialog does not close when the button is pressed.
});
fishingButton.sceneProperty().addListener((observable, oldValue, newScene) -> {
    if (newScene != null) {
        newScene.getAccelerators().put(
                new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN),
                fishingButton::fire
        );
    }
});

可执行示例代码

大部分代码都是从优秀的Makery JavaFX dialog tutorial中解脱出来的。附加代码已添加到教程代码中,以添加钓鱼按钮和加速器以触发它。

加速器触发前的对话: no fish

加速器触发后的对话: go fish

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.util.Pair;

import java.util.Optional;

public class LoginDialog extends Application {

    @Override 
    public void start(Stage stage) throws Exception {
        Button showDialogButton = new Button("Show Dialog");
        showDialogButton.setOnAction(event -> {
            showDialog();
        });

        StackPane layout = new StackPane(showDialogButton);
        layout.setPadding(new Insets(10));
        stage.setScene(new Scene(layout));

        stage.show();
    }

    private void showDialog() {
        // Create the custom dialog.
        Dialog<Pair<String, String>> dialog = new Dialog<>();
        dialog.setTitle("Login Dialog");
        dialog.setHeaderText("Look, a Custom Login Dialog");

        // Set the icon.
        // icon source: http://www.iconarchive.com/show/soft-scraps-icons-by-hopstarter/Lock-Lock-icon.html
        dialog.setGraphic(new ImageView("http://icons.iconarchive.com/icons/hopstarter/soft-scraps/64/Lock-Lock-icon.png"));

        // Set the button types.
        ButtonType loginButtonType = new ButtonType("Login", ButtonBar.ButtonData.OK_DONE);
        ButtonType fishingButtonType = new ButtonType( "Go fishing", ButtonBar.ButtonData.OTHER);
        dialog.getDialogPane().getButtonTypes().addAll(loginButtonType, fishingButtonType, ButtonType.CANCEL);

        // Create the username and password labels and fields.
        GridPane grid = new GridPane();
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20, 150, 10, 10));

        TextField username = new TextField();
        username.setPromptText("Username");
        PasswordField password = new PasswordField();
        password.setPromptText("Password");

        grid.add(new Label("Username:"), 0, 0);
        grid.add(username, 1, 0);
        grid.add(new Label("Password:"), 0, 1);
        grid.add(password, 1, 1);

        // Enable/Disable login button depending on whether a username was entered.
        Node loginButton = dialog.getDialogPane().lookupButton(loginButtonType);
        loginButton.setDisable(true);

        // Set an accelerator and an action for the fishing button.
        Button fishingButton = (Button) dialog.getDialogPane().lookupButton(fishingButtonType);
        fishingButton.addEventFilter(ActionEvent.ACTION, ae -> {
            // linkware image: http://www.iconka.com
            dialog.setGraphic(new ImageView("http://icons.iconarchive.com/icons/iconka/meow/64/cat-fish-icon.png"));
            ae.consume();
        });
        fishingButton.sceneProperty().addListener((observable, oldValue, newScene) -> {
            if (newScene != null) {
                newScene.getAccelerators().put(
                        new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN),
                        fishingButton::fire
                );
            }
        });

        // Do some validation (using the Java 8 lambda syntax).
        username.textProperty().addListener((observable, oldValue, newValue) -> {
            loginButton.setDisable(newValue.trim().isEmpty());
        });

        dialog.getDialogPane().setContent(grid);

        // Request focus on the username field by default.
        Platform.runLater(username::requestFocus);

        // Convert the result to a username-password-pair when the login button is clicked.
        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == loginButtonType) {
                return new Pair<>(username.getText(), password.getText());
            }
            return null;
        });

        Optional<Pair<String, String>> result = dialog.showAndWait();

        result.ifPresent(usernamePassword -> {
            System.out.println("Username=" + usernamePassword.getKey() + ", Password=" + usernamePassword.getValue());
        });
    }

    public static void main(String[] args) {
        launch(args);
    }
}