【问题标题】:Is there any way to create more clarity in my JavaFX code? [closed]有没有办法让我的 JavaFX 代码更加清晰? [关闭]
【发布时间】:2020-01-03 15:01:28
【问题描述】:

我正在学习计算机科学的第一年,我刚刚完成了我的第一个项目,我必须在其中创建一个可以在 SQL 数据库上执行 CRUD 操作的应用程序。此应用程序需要有一个 GUI,为此我们需要使用 JavaFX。

目前我非常不确定我处理按钮点击的方式。例如,主屏幕有三个按钮(Accounts、Profiles、Watched),每个按钮都会创建一个带有三个按钮(Create、Edit、Delete)的新场景。这导致很多 lambda 表达式相互嵌套,这使得代码看起来非常混乱。下面你会看到我的部分代码:

public class GUI extends Application {

    Database db = new Database();

    @Override
    public void start(Stage stage) throws Exception {
        // Three buttons and a Label for the first scene.
        Button buttonAccounts = new Button("Accounts");
        Button buttonProfiles = new Button("Profiles");
        Button buttonWatched = new Button("Watched");
        Label pickAnOption = new Label("Pick an option:");

        // Two HBoxes, first one for the Label, the other one for the three Buttons.
        // Both HBoxes are aligned in the center.
        HBox options = new HBox(12);
        options.setAlignment(Pos.CENTER);
        options.getChildren().addAll(buttonAccounts, buttonProfiles, buttonWatched);
        HBox text = new HBox();
        text.setAlignment(Pos.CENTER);
        text.getChildren().add(pickAnOption);

        // The HBoxes are placed in a BorderPane.
        // HBox "text" has a top margin of 20 and HBox "options" has a bottom margin of 20.
        // This way, the BorderPane will be nicely aligned in the middle of the scene.
        BorderPane pane = new BorderPane();
        pane.setTop(text);
        pane.setMargin(text, new Insets(20, 0, 0 , 0));
        pane.setCenter(options);
        pane.setMargin(options, new Insets(0, 0, 20, 0));

        Scene selectionScreen = new Scene(pane, 500, 100);

        stage.setTitle("Netflix Statistix door S. Jaspers, I. Moerenhout en Z. Usmaeva");
        stage.setResizable(false);
        stage.setScene(selectionScreen);
        stage.show();

        // EventHandler for the Accounts Button.
        buttonAccounts.setOnAction(e -> {
            Button buttonCreateAccount = new Button("Create");
            Button buttonEditAccount = new Button("Edit");
            Button buttonDeleteAccount = new Button("Delete");
            Button back = new Button("Back");
            Label createEditOrDelete = new Label("Create a new account, or edit/delete an existing account:");

            back.setOnAction(e1 -> stage.setScene(selectionScreen));

            HBox text1 = new HBox();
            text1.setAlignment(Pos.CENTER);
            text1.getChildren().add(createEditOrDelete);
            HBox options1 = new HBox(12);
            options1.setAlignment(Pos.CENTER);
            options1.getChildren().addAll(buttonCreateAccount, buttonEditAccount, buttonDeleteAccount);
            HBox text2 = new HBox();
            text2.setSpacing(50);
            text2.getChildren().add(back);

            BorderPane pane1 = new BorderPane();
            pane1.setTop(text1);
            pane1.setMargin(text1, new Insets(15, 0, 0, 0));
            pane1.setCenter(options1);
            pane1.setMargin(options1, new Insets(0, 0, 15, 0));
            pane1.setBottom(text2);

            Scene accounts = new Scene(pane1, 500, 100);
            stage.setScene(accounts);

            // EventHandler for the Create Account button.
            buttonCreateAccount.setOnAction(e1 -> {
                GridPane grid = new GridPane();
                grid.setPadding(new Insets(10, 10, 10, 10));
                grid.setVgap(8);
                grid.setHgap(10);

                Button buttonSave = new Button("Save");
                Button buttonCancel = new Button("Cancel");

                buttonCancel.setOnAction(e3 -> {
                    stage.setScene(accounts);
                });

                Label accountName = new Label("Name:");
                Label accountAddress = new Label("Address:");
                Label accountCity = new Label("City:");

                TextField accountNameInput = new TextField();
                TextField accountAddressInput = new TextField();
                TextField accountCityInput = new TextField();

                grid.add(accountName, 0, 0);
                grid.add(accountNameInput, 1, 0);
                grid.add(accountAddress, 0, 1);
                grid.add(accountAddressInput, 1, 1);
                grid.add(accountCity, 0, 2);
                grid.add(accountCityInput, 1, 2);
                grid.add(buttonSave, 2, 3);
                grid.add(buttonCancel, 3, 3);

                Scene accountCreation = new Scene(grid);
                stage.setScene(accountCreation);

                buttonSave.setOnAction(e2 -> {
                    boolean succeeded = db.createAccount(accountNameInput.getText(), accountAddressInput.getText(), accountCityInput.getText());
                    if (succeeded) {
                        new Alert(Alert.AlertType.INFORMATION, "Account successfully created.").show();
                    } else {
                        new Alert(Alert.AlertType.WARNING, "Failed to create account.").show();
                    }
                });
            });

我对 JavaFX 还是很陌生,我想知道是否有任何方法可以使这段代码更清晰。非常感谢任何建议。

【问题讨论】:

  • 开设几个课程,button.setOnAction(evt -> stage.setScene(new EditScene());。 (不一定是这样,我经常用非JavaFX的类,过关了。)
  • 或者至少,将您的按钮操作移动到私有方法。

标签: java user-interface javafx lambda eventhandler


【解决方案1】:

我很想将此作为评论发布,但我不能。你检查过 FXML 吗? 它允许您以非常干净和简单的方式设置属性。如果你想要自动完成和检查,那么我推荐 IntelliJ IDEA。这是一篇很好的文章,它解释了 FXML 的好处:https://docs.oracle.com/javafx/2/fxml_get_started/why_use_fxml.htm

【讨论】:

    【解决方案2】:
    1. 您可以使您的GUI 类实现EventHandler 接口。然后您可以在代码中编写以下内容:
    buttonAccounts.setOnAction(this);
    

    handle() 方法的参数包含事件的来源,即被点击的按钮。您的代码如下所示:

    public class GUI extends Application implements EventHandler<Action> {
        public void handle(ActionEvent e) {
            Object source = e.getSource();
            if (source == buttonAccounts) {
                // Handle it.
            }
            else if (source == buttonEditAccount) {
            }
            // etc.
        }
    }
    
    1. 您可以使用method references。编写一个接受单个ActionEvent 参数并返回void 的方法,例如
    private void handleButtons(ActionEvent event) {
        Object source = event.getSource();
        // As above.
    }
    

    那你就可以写了……

    buttonAccounts.setOnAction(this::handleButtons);
    

    【讨论】:

    • IMO,在 Application 中实现 EventHandler 接口违反了single responsibility principleseperation of concerns。对于任何重要的应用程序(例如与数据库交互的应用程序),Application 类应该只实现应用程序的生命周期,如Application javadoc 中所述,所有其他的都应该委托给其他类。
    • 我还认为这里描述的共享事件处理程序是一个坏主意。只需为每个不同的事件源定义不同的事件处理程序,并将其直接设置在接收事件的节点上,而不是测试源的单个事件处理程序,然后根据源切换其功能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    • 2020-08-22
    • 2018-02-28
    • 2013-07-16
    • 2019-12-11
    相关资源
    最近更新 更多