FXML Best Practices

Daniel Zwolenski zonski at gmail.com
Wed Dec 19 18:24:31 PST 2012


This is a conversation just getting started between Richard and myself on
FXML usage in the Tower Defender Game. It's more general JFX related,
rather than game related so I'm moving it here.

The general question revolved around Richard, using a pattern to load FXML
that more or less leaves the 'controller' out of the game and uses some
brute force techniques to load the view and attach 'control' to it.

So say we have an FXML 'login' dialog. Something like (pseudo code):

    <VBox>
        <TextField id="userNameField"/>
        <TextField id="passwordField"/>
        <Button id="loginButton"/>
    </VBox>

Then Richard has used a pattern where he creates a corresponding View
class, which does something like this (pseudo code):

    class LoginView extends StackPane {
        LoginView() {
            Parent content =
FXMLLoader.load(getClass().getResource("/LoginView.fxml"));
            getChildren().add(content);

            final TextField userNameField =
(TextField)content.lookup("#userNameField");
            final TextField passwordField =
(TextField)content.lookup("#passwordField");
            final Button loginButton =
(Button)content.lookup("#loginButton");
            loginButton.setOnAction(new EventHandler<ActionEvent>() {
                public void handle(ActionEvent actionEvent) {
                    String userName = userNameField.getText();
                    String password = passwordField.getText();
                    // do login
                }
            });
        }
    }

All the string based lookup stuff and manual event wire-ups is pretty ugly
in my opinion, leading to trouble with things like tool support, unit
testing, type safety, etc.

The 'controller' mechanism (with the newer injection stuff) would be the
more natural fit for doing the wiring up, so instead we'd have something
like:

    class LoginView extends VBox {

        @FXML TextField userNameField;
        @FXML TextField passwordField;

           public LoginView() {
            FXMLLoader fxmlLoader
                = new FXMLLoader(getClass().getResource("LoginView.fxml"));
            fxmlLoader.setRoot(this);
            fxmlLoader.setController(this);
            fxmlLoader.load();

            // side note: an FXMLLoader.load(this, "LoginView.fxml") would
be nice here
            // instead of all of the above. Especially if it threw a
runtime exception
            // instead of the annoying typed exception.
        }

        void login() {
            String userName = userNameField.getText();
            String password = passwordField.getText();
            // do login
        }
    }

And FXML like:

    <fx:root type="VBox">
        <TextField fx:id="userNameField"/>
        <TextField fx:id="passwordField" onAction="login"/>
        <Button id="loginButton" onAction="login"/>
    </fx:root>

Much cleaner code and better abstraction - details about the internals of
the actual view are better hidden in the FXML. This becomes more important
as the FXML gets more complex.

Also tools (e.g. IntelliJ) could be made to understand and help with the
second style (e.g. highlight in red parameters that are the wrong type or
don't exist in either the Contorl or FXML but not the other, ALT+ENTER on
an fx:id to create the corresponding field in the controller, etc) but
could never really be made to work with the first approach.

Obviously everyone is free to code whatever they want, and if you like one
approach over the other go for it. I'm raising it for two reasons though.
Firstly, Richard indicated the first approach was pretty much on par with
the second in his mind, so I wanted to highlight the differences between
them for reference. To me the second approach is much stronger/cleaner.

The second reason however is that Richard used SceneBuilder to create his
FXML and it makes me think that SB might be biased towards the first
pattern (?). Does SB integrate with Controller code and do smarts around
that, or does it leave the whole Controller bit out of the equation?

I skimmed through this video from Oracle on SB (
http://www.youtube.com/watch?v=rHcnsEoSK_c) and there's a magical mention
of controllers at the end but it's not real clear where this comes from and
how it's linked to the FXML file. I could go and play around with SB (I did
once and it wasn't for me) but I guess I'm more interested in the
philosophy and how SB is intended to be used. What is the workflow to go
from SB to code? Is SB an actual RAD tool or just a Graphical UI Builder (
http://en.wikipedia.org/wiki/Rapid_application_development)? If the latter,
how does it slot in to normal dev tools?

I'm the sort of person who will code FXML by hand, so SB as GUI Builder is
not something I use, but I would be keen to understand the patterns that SB
is promoting. It would be good to not promote a pattern that's going to
cause problems and result in less than ideal fxml for general use.

I'm also curious as to who 'owns' the FXML stream of work now that Greg is
gone?

Cheers,
Dan


More information about the openjfx-dev mailing list