Controller returning null in javafx helloworld

2019-08-09 18:03发布

问题:

So of course I dive straight in to creating a simple example.

public class Main extends Application {

URL bla = getClass().getResource("/sample.fxml");

@Override
public void start(Stage primaryStage) throws Exception{
    //If you get weird errors: http://zenjava.com/javafx/maven/fix-classpath.html
        //but not actually my issue. Example displays fine in intellij.

    try {

        FXMLLoader loader = new FXMLLoader(bla);
        Parent root = loader.load(bla);

        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();

        Controller controller = loader.<Controller>getController() ;
        assert(controller != null);
        controller.getLabel().setText("Kaboom!");
    } catch (Exception e) {
        // Exception gets thrown if the fxml file could not be loaded
        e.printStackTrace();
    }
}

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

I've read https://forums.oracle.com/thread/2317621 and I know that the top anchorpane needs to point to my Controller in the fxml.

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"      minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" xmlns:fx="http://javafx.com/fxml" fx:controller="mypackage.Controller">
  <children>

and it displays fine, but the assertion catches because there is no conroller!
Also the initialize() does actually run, which means the following controller is created!

public class Controller {

@FXML
private Label label ;

public Label getLabel()
{
    return label ;
}

@FXML
public void initialize()
{
    System.out.println("Swear a lot!");
    System.out.println(label);
}
}

A note to the FX developers if you're are watching this:

If you're going to have weakly coupled strings in an xml file pointing to classes, I really expect the .load() to throw a meaningful runtime exception if it can't find what it's looking for. There is no excuse for ever returning null... ideally take a page from the GWT widget team, and have a precompiler fail BEFORE your program actually gets underway, or best yet plugins for popular IDEs.

Further, you really should make it a snap to get the source-code for JavaFX up and running (put it in maven) for JavaFX, so it can download automatically and I can work out what the problem is myself. Too hard.

I'm sure there's something simple I'm doing wrong, but the tools should save me from this.

回答1:

To be able to get the controller class like this

Controller controller = loader.<Controller>getController();

you need to call the loading method of instantiated FXMLLoader, i.e.
Instead of

Parent root = loader.load(bla);

where the load() is static here, call

Parent root = (Parent) loader.load(bla.openStream());

But I agree it should be well documented.



回答2:

Uluk's answer already addresses the main issue raised in the question.

This "answer" only addresses ancillary questions.

I really expect the .load() to throw a meaningful runtime exception if it can't find what it's looking for.

Log a tweak issue in the JavaFX issue tracker for API changes, exception message modifications or documentation improvement requests. In this case it sounds like it is a documentation and API usage clarification.

Also note that use of FXML files are optional. Everything that can be done in FXML can also be done directly in the Java API, so you don't need "to have weakly coupled strings in an xml file pointing to classes".

In cases where you do have this weak string coupling, some development environments, such as Idea 12.1+, will run incremental validations, checks, error syntax highlighting and fxml/code navigation for you. So, current tools can help save you from some of the pitfalls to a certain extent (though likely not for the particular issue referenced in your post). Java frameworks have been integrating with XML in IDEs for a long time and, it's not a perfect marriage, but IDE developers have become quite adept at addressing some of the worst pain points.

Further, you really should make it a snap to get the source-code for JavaFX up and running (put it in maven) for JavaFX, so it can download automatically and I can work out what the problem is myself.

In the JavaFX issue tracker, there is an existing request for JavaFX source code bundling with the JDK. The issue is scheduled to be implemented for Java 8 before it's release. The solution is not applicable to earlier JavaFX versions such as JavaFX 2.2 as those versions are mostly closed source.

In the meantime, you may be interested in the alternative solutions of getting the source code from the open-jfx repository, which is presented in answers to: JavaFX source code not showing.

I did look at openJDK, but it looked like a mission.

Understandable - using sources from the open-jfx repository is more complicated than having a bundled src.zip that is included with the JDK distribution with automatic reference by new IDE projects (in the same way that the current jdk src.zip is used by IDEs).

I am sure that JavaFX source bundling with easy access to the JavaFX source from major IDEs will be implemented by the time of the Java 8 release.

I don't think placing the JavaFX libraries and code in a maven repository is a good solution as the libraries themselves now form part of JDK distributions. Other code in JDK distributions is not included in maven repositories. Perhaps by the time Java 9 comes around with a modular JDK approach, this may change.

Unless Scene Builder can create/modify java code, your recommendation of not using xml is not poignant.

Not using FXML is not a recommendation - it's just an alternative for those who may not like the XML based approach of matching a weekly typed string language with the strongly typed Java language.

The only real recommendation I ever make regarding FXML usage is not to use FXML and SceneBuilder when you first start out JavaFX development as (IMO):

  1. It is more efficient to just use the API when learning the principles of the JavaFX toolkit.
  2. There is less stuff to learn.
  3. You don't have a GUI tool automatically generating of complex UI elements that you may not yet know how to use correctly.
  4. You don't have to worry about how somewhat complicated, confusing and poorly documented FXML loaders work.
  5. You don't have to worry about keeping in sync mappings between UI elements in FXML files and Java code.
  6. You are forced to understand layout and scene graph structure from a low level API perspective.

If you're evaluating UI technologies specifically to allow for separation of concerns, so that layout designers may join the team...then your list of concerns is quite mute

Sure, any evaluation of JavaFX technology from a cross-functional team perspective would naturally involve evaluation of FXML and SceneBuilder use.

The reasoning provided for new JavaFX developers to perform initial JavaFX development using only APIs are not really concerns. They constitute my opinions on why a developer (not a cross-functional evaluator) might just stick to APIs only when initially learning JavaFX technologies.

I don't think it's wrong to make this a documentation issue, because it expects too much of the user.

That is an understandable sentiment. Perhaps deprecating the static FXMLLoader load methods might be a better approach to preventing the possibility of such user errors in the first place.

Regardless, the most direct way to request a change to either the documentation or the implementation is to create an issue request in the JavaFX issue tracker and discuss the issue with developers on the openjfx-dev mailing list. JavaFX is currently under active development, so such a request (if made promptly) has a reasonable chance of being implemented in the Java 8 timeframe.

If you have further ancillary questions, I recommend posting them to forums which best handle those question types (such as the Oracle JavaFX forums or the openjfx-dev JavaFX mailing list).



标签: javafx-2 fxml