ssukienn
ssukienn

Reputation: 588

JavaFX button binding exception

public class AccountOverviewController {

//declarations ...

@FXML
private Button undoButton;

@FXML
private Button redoButton;

@FXML
private void initialize() {
    transactionsTable.getSelectionModel().setSelectionMode(
            SelectionMode.MULTIPLE);

    dateColumn.setCellValueFactory(dataValue -> dataValue.getValue()
            .getDateProperty());
    payeeColumn.setCellValueFactory(dataValue -> dataValue.getValue()
            .getPayeeProperty());
    categoryColumn.setCellValueFactory(dataValue -> dataValue.getValue()
            .getCategoryProperty());
    inflowColumn.setCellValueFactory(dataValue -> dataValue.getValue()
            .getInflowProperty());

    deleteButton.disableProperty().bind(Bindings.isEmpty(transactionsTable.getSelectionModel().getSelectedItems()));

    editButton.disableProperty().bind(Bindings.size(transactionsTable.getSelectionModel().getSelectedItems()).isNotEqualTo(1));

    undoButton.disableProperty().bind(Bindings.isEmpty(commandRegistry.getCommandStack()));
    redoButton.disableProperty().bind(Bindings.isEmpty(commandRegistry.getUndoCommandStack()));
}

//handlers&setters ...
}

These two lines at the end are causing error. I want to disable buttons when the commands stacks are empty. I don't know why. For example same button disabling for Delete/Edit button works fine. Whole application without these two works perfectly fine.

Exception chain:

javafx.fxml.LoadException: 
/home/simon/eclipse/java-neon-workspace/to2/lab2/cw3/bin/pl/edu/agh/iisg/to/javafx/cw3/view/AccountOverviewPane.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2571)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at pl.edu.agh.iisg.to.javafx.cw3.presenter.AccountPresenter.initRootLayout(AccountPresenter.java:35)
    at pl.edu.agh.iisg.to.javafx.cw3.Main.start(Main.java:20)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$106(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$119(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$117(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$118(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$450(GtkApplication.java:139)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2566)
    ... 13 more
Caused by: java.lang.NullPointerException
    at pl.edu.agh.iisg.to.javafx.cw3.view.AccountOverviewController.initialize(AccountOverviewController.java:97)
    ... 23 more

Both of stacks are declared like this in CommandRegistry class

private ObservableList<Command> commandStack = FXCollections.observableArrayList();

and getters are returning themselves naturally. What could possibly go wrong here?

Upvotes: 0

Views: 357

Answers (1)

beatngu13
beatngu13

Reputation: 9393

After looking at your project, especially AccountOverviewController and AccountPresenter, I'd say you get that NullPointerException because the controller tries to access commandRegistry within initialize() before the class has an instance of CommandRegistry.

Have a look at lines 38 – 41 of AccountPresenter:

AccountOverviewController controller = loader.getController();
controller.setPresenter(this);
controller.setData(DataGenerator.generateAccountData());
controller.setCommandRegistry(commandRegistry);

You create your controller and set commandRegistry afterwards. But initialize() is invoked directely after calling the constructor of AccountOverviewController (check out this question for details). At this time, commandRegistry is null.

One way to fix this is by moving the bindings into the setter:

public void setCommandRegistry(CommandRegistry commandRegistry) {
    this.commandRegistry = commandRegistry;

    undoButton.disableProperty().bind(Bindings.isEmpty(commandRegistry.getCommandStack()));
    redoButton.disableProperty().bind(Bindings.isEmpty(commandRegistry.getUndoCommandStack()));

    commandLogView.setItems(commandRegistry.getCommandStack());
    commandLogView.setCellFactory(lv -> new ListCell<Command>() {
        protected void updateItem(Command item, boolean empty) {
            super.updateItem(item, empty);
            setText((item != null && !empty) ? item.getName() : null);
        };
    });
}

Upvotes: 1

Related Questions