I have many FXML with different Controller and I want to access all Controller Instance in one class using static methods. The reason I am doing this because I want to change the UI of different FXML from different controller. I'm not sure if there is any better way to do it. My problem is in my SceenViews class because I don't know what datatype to use to hold FXML Controller Instance in my controllerMap variable.
Inside my Package: Main.java, ScreenViews.java, Frame.FXML, FrameController.java, Login.FXML, LoginController.java, Dashboard.FXML, DashboardController.java, Journal.FXML, and JournalController.java
Main.java
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
ScreenViews.loadFXML("Frame", "Frame.fxml");
ScreenViews.loadFXML("Login", "Login.fxml");
ScreenViews.loadFXML("Dashboard", "Dashboard.fxml");
ScreenViews.loadFXML("Journal", "Journal.fxml");
Scene scene = new Scene((Parent) ScreenViews.getView("Frame"));
scene.setFill(Color.TRANSPARENT);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
In my ScreenViews.java what datatype can I use to hold different controller instance in my controllerMap variable?
public class ScreenViews {
private static HashMap<String, Node> viewMap = new HashMap<>();
//HASHMAP FOR CONTROLLER INSTANCE
private static HashMap<String, datatype? > controllerMap = new HashMap<>();
public static void addView(String name, Node screen) {
viewMap.put(name, screen);
}
public static Node getView(String name) {
return viewMap.get(name);
}
public static void addController(String name, datatype? controller) {
controllerMap.put(name, controller);
}
public static datatype? getController(String name) {
return controllerMap.get(name);
}
public static boolean loadFXML(String name, String resource) {
try {
FXMLLoader fxLoader = new
FXMLLoader(ScreenViews.class.getResource(resource));
Parent loadedFXML = (Parent) fxLoader.load();
addView(name, loadedFXML);
addController(name, fxLoader.getController());
return true;
} catch (IOException e) {
System.out.println(e.getMessage());
return false;
}
}
}
Sample LoginController.java code
public class LoginController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
public void frameSetUI(ActionEvent event) {
ScreenViews.getController("Frame").getFramePane().getChildren().add(ScreenViews.get("Dashboard"));
}
}
Sample FrameController.java code
public class FrameController implements Initializable {
#FXML private StackPane rootPane;
#FXML private AnchorPane titleBar;
#FXML private AnchorPane framePane;
#FXML private Button toDashboard;
#FXML private AnchorPane mainPane;
public void initialize(URL url, ResourceBundle rb) {
}
public AnchorPane getFramePane(){
return framePane;
}
}
Related
I'm trying to push my data that I'm getting from a RethinkDB into a JavaFx TableView, however, the changes do not appear in the tableview and I can't figure out why.
I'm pretty new to JavaFx so I hope you can help me.
Here are my classes : (I didn't include my memory classes where I save the data from the DB)
RethinkDBConnect class
public class RethinkDBConnect {
public static final RethinkDB r = RethinkDB.r;
GsonConverter con = new GsonConverter();
JiraTicketBody body = new JiraTicketBody();
ViewController viewcon = new ViewController();
TicketDataProperty tickprop = new TicketDataProperty(null, null, null, null, null, null);
public void Connection(){
viewcon.list.add(newTicketDataProperty
("test","test","test","test","test","test"));
}
}
TicketDataProperty class
public class TicketDataProperty {
private final SimpleStringProperty key;
private final SimpleStringProperty prioritaet;
private final SimpleStringProperty erstellt;
private final SimpleStringProperty status;
private final SimpleStringProperty zustand;
private final SimpleStringProperty beschreibung;
public TicketDataProperty(String key, String prioritaet, String erstellt,
String status, String zustand, String beschreibung)
{
this.key = new SimpleStringProperty(key);
this.prioritaet = new SimpleStringProperty(prioritaet);
this.erstellt = new SimpleStringProperty(erstellt);
this.status = new SimpleStringProperty(status);
this.zustand = new SimpleStringProperty(zustand);
this.beschreibung = new SimpleStringProperty(beschreibung);
}
public String getKey() {
return key.get();
}
public void setKey(String value) {
key.set(value);
}
public String getPrioritaet() {
return prioritaet.get();
}
public void setPrioritaet(String value) {
prioritaet.set(value);
}
public String getErstellt() {
return erstellt.get();
}
public void setErstellt(String value) {
erstellt.set(value);
}
public String getStatus() {
return status.get();
}
public void setStatus(String value) {
status.set(value);
}
public String getZustand() {
return zustand.get();
}
public void setZustand(String value) {
zustand.set(value);
}
public String getBeschreibung() {
return beschreibung.get();
}
public void setBeschreibung(String value) {
beschreibung.set(value);
}
}
ViewController class
public class ViewController implements Initializable {
TicketDataProperty tickdat = new TicketDataProperty(null, null, null, null, null, null);
#FXML private TableView <TicketDataProperty> table;
#FXML private TableColumn <TicketDataProperty,String> key;
#FXML private TableColumn <TicketDataProperty,String> prioritaet;
#FXML private TableColumn <TicketDataProperty,String> erstellt;
#FXML private TableColumn <TicketDataProperty,String> status;
#FXML private TableColumn <TicketDataProperty,String> zustand;
#FXML private TableColumn <TicketDataProperty,String> beschreibung;
public ObservableList<TicketDataProperty> list = FXCollections.observableArrayList(
new TicketDataProperty("example","example","example","example","example","example")
);
#Override
public void initialize(URL location, ResourceBundle resources) {
key.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("key"));
prioritaet.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("prioritaet"));
erstellt.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("erstellt"));
status.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("status"));
zustand.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("zustand"));
beschreibung.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("beschreibung"));
table.setItems(list);
}
}
GsonConverter class
public class GsonConverter {
public JiraTicketBody gson(String json)
{
Gson gson = new Gson();
JiraTicketBody BodyObj = gson.fromJson(json,JiraTicketBody.class);
return BodyObj;
}
}
Main class
public class Main extends Application
{
//ViewXML
#Override
public void start(Stage primaryStage) throws IOException
{
Parent root = FXMLLoader.load(getClass().getResource("/view/ViewXML.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("Ticket System Application");
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public static void main(String[] args)
{
try {
//ViewXML
launch(args);
RethinkDBConnect obj = new RethinkDBConnect();
obj.Connection();
} catch(Exception e) {
}
}
}
There are two issues with the code you have posted.
As stated in the documentation, Application.launch() blocks until the application exits. So you don't even create the RethinkDBConnection class until the application is in the process of closing. You should consider the start() method to be the entry point to the application, and should have no code other than launch() in the main(...) method. Anything you do in a JavaFX application should be done in the start(...) or init(...) methods, or in methods invoked from there, etc.
In this case, since you don't seem to need RethinkDBConnection from outside the controller, I see no reason not to create RethinkDBConnect from the controller itself.
You need to update the list that belongs to the controller. Instead, you are creating a new object that happens to be the same class as the controller, and updating the list that belongs to that object. Obviously, that list has nothing at all to do with the table. You need to pass a reference to the actual list that is used as the backing list for the table to the RethinkDBController instance.
So your code should look like:
public class RethinkDBConnection {
// public static final RethinkDB r = RethinkDB.r;
// GsonConverter con = new GsonConverter();
// JiraTicketBody body = new JiraTicketBody();
private final ObservableList<TicketDataProperty> dataList ;
public RethinkDBConnection(ObservableList<TicketDataProperty> dataList) {
this.dataList = dataList ;
}
public void connect(){
dataList.add(new TicketDataProperty
("test","test","test","test","test","test"));
}
}
Then in the controller you can do:
public class ViewController implements Initializable {
#FXML private TableView <TicketDataProperty> table;
#FXML private TableColumn <TicketDataProperty,String> key;
#FXML private TableColumn <TicketDataProperty,String> prioritaet;
#FXML private TableColumn <TicketDataProperty,String> erstellt;
#FXML private TableColumn <TicketDataProperty,String> status;
#FXML private TableColumn <TicketDataProperty,String> zustand;
#FXML private TableColumn <TicketDataProperty,String> beschreibung;
private ObservableList<TicketDataProperty> list = FXCollections.observableArrayList(
new TicketDataProperty("example","example","example","example","example","example")
);
#Override
public void initialize(URL location, ResourceBundle resources) {
key.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("key"));
prioritaet.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("prioritaet"));
erstellt.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("erstellt"));
status.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("status"));
zustand.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("zustand"));
beschreibung.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("beschreibung"));
table.setItems(list);
RethinkDBConnection connection = new RethinkDBConnection(list);
connection.connect();
}
}
And your Main class should just be:
public class Main extends Application
{
//ViewXML
#Override
public void start(Stage primaryStage) throws IOException
{
Parent root = FXMLLoader.load(getClass().getResource("/view/ViewXML.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("Ticket System Application");
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you really do need access to your RethinkDBConnection instance outside the controller, then modify the controller as follows:
public class ViewController implements Initializable {
#FXML private TableView <TicketDataProperty> table;
#FXML private TableColumn <TicketDataProperty,String> key;
#FXML private TableColumn <TicketDataProperty,String> prioritaet;
#FXML private TableColumn <TicketDataProperty,String> erstellt;
#FXML private TableColumn <TicketDataProperty,String> status;
#FXML private TableColumn <TicketDataProperty,String> zustand;
#FXML private TableColumn <TicketDataProperty,String> beschreibung;
private ObservableList<TicketDataProperty> list = FXCollections.observableArrayList(
new TicketDataProperty("example","example","example","example","example","example")
);
#Override
public void initialize(URL location, ResourceBundle resources) {
key.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("key"));
prioritaet.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("prioritaet"));
erstellt.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("erstellt"));
status.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("status"));
zustand.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("zustand"));
beschreibung.setCellValueFactory(new PropertyValueFactory<TicketDataProperty,String>("beschreibung"));
table.setItems(list);
}
public ObservableList<TicketDataProperty> getDataList() {
return list ;
}
}
and use this version of Main:
public class Main extends Application
{
//ViewXML
#Override
public void start(Stage primaryStage) throws IOException
{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/ViewXML.fxml"));
Parent root = loader.load();
ViewController controller = loader.getController();
RethinkDBConnection connection = new RethinkDBConnection(controller.getDataList());
connection.connect();
Scene scene = new Scene(root);
primaryStage.setTitle("Ticket System Application");
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Note that I renamed some classes and methods to adhere to standard naming conventions.
I have been working on JavaFX and trying figure out how to connect classes contained withing the package. I want the "text1btn" button from MainController class to send a text from "scene1TextField" also in MainController class to TextArea in LeftTextArea class. I would appreciate any comments on that. Thank you.
package sample;
public class Main extends Application {
public static BorderPane root = new BorderPane();
public static BorderPane getRoot() {
return root;
}
#Override
public void start(Stage primaryStage) throws Exception {
URL url1 = getClass().getResource("../view/MainView.fxml");
BorderPane bp1 = FXMLLoader.load(url1);
URL url2 = getClass().getResource("../view/LeftTextArea.fxml");
AnchorPane bp2 = FXMLLoader.load(url2);
root.setTop(bp1);
root.setCenter(bp2);
primaryStage.setScene(new Scene(root, 500, 400));
primaryStage.setResizable(false);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
package Controller;
public class MainController {
#FXML
Button scene1btn;
#FXML
Button scene2btn;
#FXML
TextField scene1TextField;
#FXML
TextField scene2TextField;
#FXML
Button text1btn;
#FXML
Button text2btn;
#FXML
TextArea mainViewTextArea;
#FXML
public void initialize() {
}
#FXML
public void text1btnClicked() {
}
#FXML
public void text2btnClicked() {
}
#FXML
private void scene1btnClicked() {
try {
URL url1 = getClass().getResource("../view/LeftTextArea.fxml");
AnchorPane bp1 = FXMLLoader.load(url1);
BorderPane border = Main.getRoot();
border.setCenter(bp1);
} catch (IOException e) {
e.printStackTrace();
}
}
#FXML
private void scene2btnClicked() {
try {
URL url2 = getClass().getResource("../view/RightTextArea.fxml");
AnchorPane bp2 = FXMLLoader.load(url2);
BorderPane border = Main.getRoot();
border.setCenter(bp2);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package Controller;
public class LeftTextArea {
#FXML
public TextArea leftTextArea;
}
A quick and simple approach is just to expose a StringProperty in the MainController, and when it changes call a method in the LeftTextArea:
public class MainController {
private final StringProperty text = new SimpleStringProperty();
public StringProperty textProperty() {
return text ;
}
// existing code ...
#FXML
public void text1btnClicked() {
textProperty().set(scene1TextField.getText());
}
// ...
}
In LeftTextArea do
public class LeftTextArea {
#FXML
public TextArea leftTextArea;
public void setText(String text) {
leftTextArea.setText(text);
}
}
And then you can tie it all together with
#Override
public void start(Stage primaryStage) throws Exception {
URL url1 = getClass().getResource("../view/MainView.fxml");
FXMLLoader loader1 = new FXMLLoader(url1);
BorderPane bp1 = loader1.load();
MainController mainController = loader1.getController();
URL url2 = getClass().getResource("../view/LeftTextArea.fxml");
FXMLLoader loader2 = new FXMLLoader(url2);
AnchorPane bp2 = loader2.load();
LeftTextArea leftTextArea = loader2.getController();
mainController.textProperty().addListener((obs, oldText, newText) ->
leftTextArea.setText(newText));
root.setTop(bp1);
root.setCenter(bp2);
primaryStage.setScene(new Scene(root, 500, 400));
primaryStage.setResizable(false);
primaryStage.show();
}
If you end up needing multiple properties like this that are essentially shared between controllers, you probably need to define a "model" class to encapsulate them all in one place, and pass the model to the controllers. See, e.g. JavaFX controller to controller - access to UI Controls or Applying MVC With JavaFx
If you want to set any field in the class LeftTextArea just simply create a public setter method in Class LeftTextArea like
public void setTextArea(Text text){
//do what you want to do
}
Then call the method from MainController class with the object of LeftTextArea class. like
LeftTextArea leftTextArea = new LeftTextArea();
leftTextArea.setTextArea(text); //text is the desired you want to send
I have below code. the tableview does not display record on GUI,is empty.
How I can Pass value from the ServerHandler thread to JAVAFX UI thread.
Can you please suggest?
Thanks
UPDATE
The Main class
public class Main extends Application {
private static Stage stage;
#Override
public void start(Stage primaryStage){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("mainpane.fxml"));
fxmlLoader.load();
setStage(primaryStage);
Parent root = fxmlLoader.getRoot();
Scene scene = new Scene(root,800,800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
new Thread(() -> launch(Main.class, args)).start();
new MyServer().startDownload();
}
The Controller
public class SampleController {
private ObservableList<Model> tableData = FXCollections.observableArrayList();
#FXML
private TableView<Model> table;
#FXML
private TableColumn<Model, String> firstCol;
#FXML
private TableColumn<Model, String> secondCol;
#FXML
public void initialize() {
table.setEditable(false);
firstCol.setCellValueFactory(cellData -> cellData.getValue().getName());
secondCol.setCellValueFactory(cellData -> cellData.getValue().getCurrent());
table.setItems(tableData);
}
public void addModel(ChannelFuture sendFileFeture,Model model){
table.getItems().add(Model);
System.out.println("row model= "+model.getName().get());// it works fine;
sendFileFeture.addListener(model);
}
The Server class with Netty 4
public class ServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
#Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
//some codes
Model model=new Model(file.getName(),fileLength+"");
SampleController sc=new SampleController();
sc.addModel(sendFileFeture, model);
}
The Model class with ChannelProgressiveFutureListener of Netty
public class Model implements ChannelProgressiveFutureListener{
private SimpleStringProperty name=null;
private SimpleStringProperty current=null;
public Model(String name,String current){
this.name=new SimpleStringProperty(name);
this.current=new SimpleStringProperty(current);
}
#Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) throws Exception {
System.out.println("current: "+current+",progress: "+progress); //it works fine
current.set(progress+""); // can not update the TableView
}
#Override
public void operationComplete(ChannelProgressiveFuture future) throws Exception {
}
public void setName(String name) {
this.name.set(name);
}
public SimpleStringProperty getName() {
return name;
}
public void setCurrent(String current) {
this.current.set(current);
}
public SimpleStringProperty getCurrent() {
return current;
}
UPDATE
the tableview not updating with right size,the image i loaded is 2,407,257 bytes.you can find the errors in the images below.
image1
image2
secondCol.setCellValueFactory(cellData -> cellData.getValue().getCurrent());
secondCol.setCellFactory(column -> {return new TableCell<Model, String>() {
#Override
protected void updateItem(String item, boolean empty) {
System.out.println(item); //UPDATING NOT CURRECT
super.updateItem(item, empty);
setText(empty ? "" : getItem().toString());
}
};
The UI is not displaying anything because you are populating a different table to the one you are displaying, not because of threading (though you have threading issues too, or will do once you fix the initial problem).
In your start() method, you load the FXML, which creates a TableView and its columns, and creates a controller instance. Your ServerHandler class creates a new instance of the controller, which in turn creates a new instance of TableView (it is always a mistake to initialize variables that are annotated #FXML). That TableView instance is never displayed. So when your ServerHandler populates the table, it is populating a table that is not actually part of the UI, and you don't see anything.
Move the creation of the MyServer to the start() method, and pass it the existing controller instance:
public class Main extends Application {
private Stage stage;
#Override
public void start(Stage primaryStage){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("mainpane.fxml"));
fxmlLoader.load();
setStage(primaryStage);
Parent root = fxmlLoader.getRoot();
Scene scene = new Scene(root,800,800);
primaryStage.setScene(scene);
primaryStage.show();
SampleController controller = loader.getController();
new Thread(() -> new MyServer(controller).startDownload()).start();
}
public static void main(String[] args) {
launch(args);
}
}
Your MyServer class should in turn pass the controller to the ServerHandler instance(s). Since the ServerHandler methods are being invoked on a background thread, they need to use Platform.runLater(...) to update the UI:
public class ServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
private final SampleController sc ;
public ServerHandler(SampleController sc) {
this.sc = sc ;
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
//some codes
Model model=new Model(file.getName(),fileLength+"");
Platform.runLater(() -> {
sc.addModel(sendFileFeture, model);
sc.addRowModel(sendFileFeture, rowModel);
});
}
}
Finally, don't initialize fields that are supposed to be initialized by the FXMLLoader. This will only have the effect of suppressing any NullPointerExceptions that indicate your controller-FXML bindings are not properly set up:
public class SampleController {
private ObservableList<Model> tableData = FXCollections.observableArrayList();
#FXML
private TableView<RowModel> table ;
#FXML
private TableColumn<Model, String> firstCol ;
#FXML
private TableColumn<Model, String> secondCol ;
#FXML
public void initialize() {
table.setEditable(false);
firstCol.setCellValueFactory(cellData -> cellData.getValue().getName());
secondCol.setCellValueFactory(cellData -> cellData.getValue().getProgress());
table.setItems(tableData);
}
public void addModel(ChannelFuture sendFileFeture,Model model){
table.getItems().add(model);
System.out.println("row model= "+model.getName().get());// it works fine;
sendFileFeture.addListener(rowModel);
}
}
I am designing a JavaFX application and I need to call the Application class of one of the windows in the Controller of another window.
MainController.java:
public class MainController {
#FXML
public Button buttonLogin;
#FXML
public Button buttonNeuAnmelden;
#FXML
public void handleButtonLoginAction(ActionEvent event) {
((Node) (event.getSource())).getScene().getWindow().hide();
System.out.println("LoginButton geclickt!");
}
#FXML
public void handleButtonNeuAnmeldenAction(ActionEvent event) {
((Node) (event.getSource())).getScene().getWindow().hide();
System.out.println("NeuAnmeldenButton Geclickt!");
}
}
LoginApp.java:
public class LoginApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/design/Login.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Benutzerverwaltung");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
I specifically need to run all of the methods of LoginApp, meaning main(String[] args) and start(Stage primaryStage) class in handleButtonLoginAction() method as if the whole class as it is has been called exactly at that point.
How do I do this?
If I understand the question correctly, you need to refactor this quite a bit. Define a LoginView class that is independent of your Application subclass:
public class LoginView {
private final Stage displayStage ;
private final Scene scene ;
public LoginView(Stage displayStage) throws IOException {
this.displayStage = displayStage ;
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/design/Login.fxml"));
Parent root = loader.load();
scene = new Scene(root);
displayStage.setScene(scene);
displayStage.setTitle("Benutzerverwaltung");
}
public LoginView() throws IOException {
this(new Stage());
}
public void show() {
displayStage.show();
}
public void hide() {
displayStage.hide();
}
// ...
}
and then your Application class looks like:
public class LoginApp extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
LoginView loginView = new LoginView(primaryStage);
// ...
loginView.show();
}
}
Your question didn't show how MainController is related to the application, but all you need to do is pass a reference to the loginView you created to the MainController, and then call loginView.show() from the method in the MainController.
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{
}
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);