1

I am trying to learn some JavaFx these days. I set up a simple MVC and it works well until I click the button to invoke click envet. It throws java.lang.NullPointerException. I think the problem is that the instance variable "controller" is not initialized after GUI launched. But I do initialize it in the main method. Below is view class and what I did in the main method.

package javafxdemogui;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

/**
 *
 * @author Jason
 */
public class DemoView extends Application {

    private TextArea inputText;
    private TextArea outputText;
    private DemoController controller;

    @Override
    public void start(Stage primaryStage) {
        BorderPane borderPane = new BorderPane();

        this.inputText = new TextArea();
        this.outputText = new TextArea();
        this.inputText.setWrapText(true);
        this.outputText.setWrapText(true);
        this.outputText.setEditable(false);

        borderPane.setTop(inputText);

        HBox hbox = new HBox();
        hbox.setSpacing(10);
        Button resetBtn = new Button("reset");
        Button copyInputBtn = new Button("copyInput");
        hbox.getChildren().addAll(resetBtn, copyInputBtn);
        hbox.setAlignment(Pos.CENTER);
        borderPane.setCenter(hbox);

        borderPane.setBottom(outputText);


        resetBtn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                controller.processResetEvent();
            }
        });

        copyInputBtn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                controller.processCopyEvent(inputText.getText());
            }
        });

        Scene scene = new Scene(borderPane, 600, 400);
        primaryStage.setTitle("JavaFXDemoGUI");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void registerObserver(DemoController controller) {
        this.controller = controller;
    }

    /**
     * Updates input display based on String provided as argument.
     *
     * @param input new value of input display
     */
    public void updateInputDisplay(String input) {
        this.inputText.setText(input);
    }

    /**
     * Updates output display based on String provided as argument.
     *
     * @param output new value of output display
     */
    public void updateOutputDisplay(String output) {
        this.outputText.setText(output);
    }

    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public void viewLaunch(String[] args) {
        launch(args);
    }
}

And What I did in the main method....

public static void main(String[] args) {
    /*
     * Create instances of the model, view, and controller objects, and
     * initialize them; view needs to know about controller, and controller
     * needs to know about model and view
     */
    DemoModel model = new DemoModel();
    DemoView view = new DemoView();
    DemoController controller = new DemoController(model, view);

    view.registerObserver(controller);
    view.viewLaunch(args);
}
4

1 回答 1

1

我建议将 main() 方法放在您的应用程序类中,而不是在 main 中执行任何操作,而是启动应用程序。

我还没有尝试过,但我愿意打赌,当 Application.launch 被调用时,它会生成你的应用程序类的一个新实例,所以在启动之前你在 main 中编写的所有代码都会被忽略.

我知道有一段时间,对于 Java 8,Oracle 团队正在考虑在启动时不调用 main 来启动 JavaFX 应用程序(虽然不确定最终结果是什么,也许他们仍然调用 main 方法)。

相反,您真正应该做的是在应用程序的 init 或 start 方法中处理所有初始化。另请注意(在 JavaFX 2.2 中),如果您在 init 中执行操作,则对可以实例化的 JavaFX 对象有一些限制(因为您还没有在 JavaFX 应用程序线程上),例如,您不能创建 Tooltips 或 WebViews off the JavaFX 应用程序线程。由于这个原因,您看到的大多数 JavaFX 应用程序最终都会在 start 方法前面的 JavaFX 应用程序线程上创建它们的 UI。

此外,一个好的方法是将可以从 JavaFX 应用程序线程(例如将数据库读取到类似 DemoModel 之类的东西)中完成的任何长时间运行的任务搁置到 JavaFX 并发任务中,这样您就可以获得进度反馈和消息从那个长时间运行的任务返回到您的 UI 以更新初始化状态(如果您的框架需要该级别的复杂性)。

于 2013-09-16T23:48:14.023 回答