Search code examples
javajavafxafterburner.fx

Pagenavigation and value passing with afterburner fx in JavaFX?


I'm using afterburner fx the DI-framework.
My problem is, that I have a "RootLayout" which is a BorderPane. On the top is a MenueBar, which works and in the center I loaded an other pane on startup. Now I want to be able to click on a button, so that the Center-Pane changes to a new View AND I want to pass a value to the new View/Controller.

My main class:

@Override
public void start(Stage primaryStage) throws Exception {
    initInjector();

    //BorderPane
    RootView appView = new RootView();
    Scene scene = new Scene(appView.getView());
    primaryStage.setTitle("Personalplanung");
    primaryStage.setScene(scene);
    primaryStage.show();
}

Controller/Presenter of my Root

public class RootPresenter implements Initializable {

@FXML
private AnchorPane center;

/**
 * Initializes the controller class.
 */
@Override
public void initialize(URL url, ResourceBundle rb) {
    MainView view = new MainView();
    center.getChildren().add(view.getView());
}

//Doesn't work because it must be static -> AnchorPane can't be static
public void putCenter(FXMLView fxmlView) {
    center.getChildren().add(fxmlView.getView());
}

Presenter of the view I want to change to and pass value (e.g. selected person)

public class MainPresenter implements Initializable {

@Inject
PersonService personService;

/**
 * Initializes the controller class.
 */
@Override
public void initialize(URL url, ResourceBundle rb) {

}   

/**
 * Pseudo display of all persons
 * should switch here to PersoView and pass values
 * gets triggerd by button click
 */
@FXML
private void handlePersonsOverview() {
    personService.all().forEach(person -> {
        System.out.println(person.getVorname());
    });
}

All my views are empty but extend the FXMLView (is convention)

import com.airhacks.afterburner.views.FXMLView;

public class PersonView extends FXMLView{

}

Solution

  • If I understand your structure correctly, I think you can solve this with a ViewModel:

    public class ViewModel {
    
        private final ObjectProperty<Node> mainView = new SimpleObjectProperty(this, "mainView", null);
        public ObjectProperty<Node> mainViewProperty() {
            return mainView ;
        }
        public final Node getMainView() {
            return mainView.get();
        }
        public final void setMainView(Node mainView) {
            this.mainView.set(mainView);
        }
    }
    

    Now just inject the ViewModel wherever you need it. Bind the center of the root to the view model's mainView property, and update the mainView property from your other presenters:

    public class RootPresenter {
        @FXML 
        private BorderPane root ; // I think you have this?
        @FXML
        private AnchorPane center ; // possibly no longer need this?
    
        @Inject
        private ViewModel viewModel ;
    
        public void initialize() {
            root.centerProperty().bind(viewModel.mainViewProperty());
            MainView view = new MainView();
            viewModel.setMainView(view.getView());
        }
    }
    

    Now any presenter that needs to change the center of your root just needs to do:

    public class SomePresenter {
    
        @Inject
        private ViewModel viewModel ;
    
        @FXML
        public void someHandlerMethod() {
            SomeView someView = new SomeView();
            viewModel.setMainView(someView.getView());
        }
    }
    

    To pass values to the new presenter, just define the appropriate properties and methods in the presenter and invoke them when you create the new view:

    public class MainPresenter {
        private final ObjectProperty<Person> person = new SimpleObjectProperty<>(this, "person") ;
        public ObjectProperty<Person> personProperty() {
            return person ;
        }
        public final Person getPerson() {
            return person.get();
        }
        public final void setPerson(Person person) {
            this.person.set(person);
        }
    
        public void initialize() {
            // bind to person as needed ...
            // other stuff as before
        }
    
        // ...
    }
    

    and then you can do

    MainView mainView = new MainView();
    MainPresenter mainPresenter = (MainPresenter) mainView.getPresenter();
    mainPresenter.setPerson(selectedPerson);