@FXML 注释无法正常工作

@FXML Annotation not working correctly

我目前正在使用 JavaFX 开发一个 'small' 项目。我使用 SceneBuilder 创建了我的 GUI 的第一个草图。它仍然需要一些调整和样式,但我想看看它到目前为止是否有效。

我在 GUI 上有 2 个超链接,如果用户单击其中之一,默认的系统浏览器应该打开特定的 URL。

到目前为止我得到了这个:

Main.java:

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws MalformedURLException, IOException {

    DataBean dataBean= new DataBean(primaryStage);
    Controller controller = new Controller(dataBean);
    controller.show();
}

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

DataBean.java:

public class DataBean {

private Stage primaryStage;

public DataBean(Stage stage) {

    primaryStage = stage;
}

public Stage getPrimaryStage() {
    return primaryStage;
}
}

TestautomatView.java:

public class TestautomatView implements Initializable {

@FXML 
private ComboBox<String> environmentCombo;

@FXML 
private Hyperlink crhl;

@FXML
private Hyperlink help;

@Override
public void initialize(URL location, ResourceBundle resources) {

}

private Scene scene;
private BorderPane root;

public TestautomatView() throws MalformedURLException, IOException {
    root = FXMLLoader.load(new URL(TestautomatView.class.getResource("Sample.fxml").toExternalForm()));

    scene = new Scene(root);
}

public void show(Stage stage) {
    stage.setTitle("CrossReport Testautomat");
    stage.setScene(scene);
    stage.show();
}


public ComboBox<String> getEnvironmentCombo() {
    return environmentCombo;
}

public Hyperlink getCrhl() {
    return crhl;
}

public Hyperlink getHelp() {
    return help;
}

public Scene getScene() {
    return scene;
}

}

在我的控制器中,我想将 ActionHandler 设置为超链接,但它不起作用,因为我认为 getters return null。

public class Controller  {

private DataBean dataBean;
private TestautomatView view;

public Controller(DataBean databean) throws MalformedURLException, IOException {
    this.dataBean = databean;
    this.view = new TestautomatView();

    setActionHandlers();
}

public void show() throws MalformedURLException, IOException {
    view.show(dataBean.getPrimaryStage());
}

private void setActionHandlers() {
//      setHyperlink(view.getCrhl(), "www.example.com");
//      setHyperlink(view.getHelp(), "www.example2.com");
}

private void setHyperlink(Hyperlink hl, String uri) {
    hl.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            //TODO - Open Default Browser
        }
    });
}

}

当我启动我的应用程序时,我可以看到 GUI,但是当我想添加 ActionHandlers 时,我得到一个 NullPointerException。

在“Sample.fxml”文件中,超链接是 HBox 的子项

<Hyperlink fx:id="crhl" text="Report" />
<Hyperlink fx:id="help" text="Help" />

但不仅仅是超链接,当我在调试器中检查我的应用程序时,ComboBox 也为 null。

我的错误在哪里?

问题是您正在使用 new TestautomatView() 手动创建控制器。它必须由 FXMLLoader 创建才能使注释起作用。您还必须将 Sample.fxml 中的 fx:controller 属性设置为您的控制器 (TestautomatView) 完全限定的 class 名称。

示例代码:

FXMLLoader fl = new FXMLLoader(new URL(TestautomatView.class.getResource("Sample.fxml").toExternalForm()));
root = fl.load();
TestautomatView controller = fl.getController();

PS:您应该将 TestautomatView 重命名为 TestautomatController。 FXML 文件是您的 "view".

正如另一个答案所指出的,问题是您创建了 TestautomatView "by hand" 的实例。 FXMLLoader 的默认行为是创建 FXML 文件中指定的控制器 class 的实例,并将该实例用作控制器。因此,您有两个 TestautomatView 的实例:一个是您创建的(并有一个引用),另一个是由 FXMLLoader 创建的。这是第二个初始化了 @FXML 注释字段的。

您可以通过创建 FXMLLoader 实例并直接在其上设置控制器来更改此默认行为。例如。考虑做:

public class TestautomatView implements Initializable {

    @FXML 
    private ComboBox<String> environmentCombo;

    @FXML 
    private Hyperlink crhl;

    @FXML
    private Hyperlink help;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

    }

    private Scene scene;
    private BorderPane root;

    public TestautomatView() throws MalformedURLException, IOException {

        FXMLLoader loader = new FXMLLoader(TestautomatView.class.getResource("Sample.fxml"));
        loader.setController(this);
        root = loader.load();

        scene = new Scene(root);
    }

    // etc...

}

由于您是直接设置控制器,因此您需要Sample.fxml文件中删除fx:controller属性才能正常工作。

您可能也对 this pattern 感兴趣,它与您在这里尝试做的非常相似(尽管不完全相同)。