Frank Roth
Frank Roth

Reputation: 6339

JavaFX access ui-elements from Controller(Singleton)

I have a javafx design in the file javafx.fxml where the root element has the following attribute

fx:controller="de.roth.jsona.javafx.ViewManagerFX"

This controller class has a singleton machanism and is binded with some ui-elements.

public class ViewManagerFX {

    private static ViewManagerFX instance = new ViewManagerFX();

    @FXML
    private Slider volumeSlider;
    @FXML
    private Label volumeLabel;
    public IntegerProperty volumeValue = new SimpleIntegerProperty();

    @FXML
    private TabPane musicTabs;
    public List<StringProperty> tabNames = new ArrayList<StringProperty>();

    public static ViewManagerFX getInstance() {
        return (instance);
    }

    public void initialize() {
        // Volume
        volumeSlider.valueProperty().bindBidirectional(volumeValue);
        volumeLabel.textProperty().bindBidirectional(volumeValue, new Format() {
            @Override
            public StringBuffer format(Object obj, StringBuffer toAppendTo,
                    FieldPosition pos) {
                toAppendTo.append(obj);
                toAppendTo.append("%");
                return toAppendTo;
            }

            @Override
            public Object parseObject(String source, ParsePosition pos) {
                return null; // no need to be implemented
            }
        });
        volumeValue.set(Config.getInstance().VOLUME);
    }

    public void addMusicFolderTab(final String t, final ArrayList<MusicListItem> items) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                Tab m = new Tab("Test Tab");
                musicTabs.getTabs().add(0, m);              
            }
        });
    }
}

The method addMusicFolderTab is called from a thread that is used to scan files and directories.

In the initialize method I can access the ui-elements but in the method addMusicFolderTab, that is called from the filescanner-thread, the variable musicTabs is null. Here is the exception:

java.lang.NullPointerException
    at de.roth.jsona.javafx.ViewManagerFX$3.run(ViewManagerFX.java:110)

I have no clue, why I can't access the TabPane from outside the initialize method.

Upvotes: 1

Views: 1569

Answers (1)

Alexandre
Alexandre

Reputation: 4602

Aside from the many questionable patterns used here, the problem is that your ViewManagerFX singleton (besides not being a singleton) never has its instance set.

When using FXML, the Controller is created and loaded dynamically by Reflection from the FXMLoader.

What happens is that by calling ViewManagerFX.getInstance(), you access the a different controller than the one created by the FXMLoader. The instance you access is the one created here:

private static ViewManagerFX instance = new ViewManagerFX();

The quickest way to solve the issue is to set the instance in the initialize() since it's called by the FXMLoader on the instance created by the FXMLoader.

public void initialize() {
    instance = this;
    // Volume
    ...
}

Upvotes: 6

Related Questions