Reputation: 97
Use-Case
Parent-window contains menu-bar at top, that has one menu (e.g. Data), and that menu contains only one menu-item (e.g. Import). When user selects 'Import' menu-item, a dialog-window appears. There is also a comboBox in the parent-window.
Dialog-window has comboBox, textField and a button. Once user enter any text in textField and clicks the button, that text, say fruit-name, gets added into comboBox. There is another button to close the dialog (not important here).
I am trying to add new item in the parent-window's comboBox automatically when a new item is added into dialog-window's comboBox, but I am not able to get the desired result. I haven't found any comboBox property where binding can be of any help (not explored thoroughly).
I am new to JavaFX, so please help me out with right coding practices if you find any gaps in the code below (apart from the functionality that is not working).
Main.java (package: problem)
package problem;
import java.io.IOException;
import javafx.application.Application;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
MainWindowController mwc = new MainWindowController();
mwc.launchMainWindow(primaryStage);
}
public static void main(String[] args) {
launch(args);
}
}
MainWindow.fxml (package: problem)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.VBox?>
<VBox prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.102" xmlns:fx="http://javafx.com/fxml/1" fx:controller="problem.MainWindowController">
<children>
<MenuBar>
<menus>
<Menu text="Data">
<items>
<MenuItem fx:id="importMenuItem" onAction="#launchImportDialog" text="Import" />
</items>
</Menu>
</menus>
</MenuBar>
<ComboBox fx:id="fruitsComboBox" prefWidth="150.0" />
</children>
</VBox>
MainWindowController.java (package: problem)
package problem;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import problem.importdata.ImportDataController;
public class MainWindowController implements Initializable {
private Stage primaryStage;
@FXML
private MenuItem importMenuItem;
@FXML
private ComboBox fruitsComboBox;
@Override
public void initialize(URL location, ResourceBundle resources) {
}
public void launchMainWindow(Stage primaryStage) throws IOException {
this.primaryStage = primaryStage;
FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
VBox root = loader.load();
Scene scene = new Scene(root, 600, 400);
primaryStage.setTitle("Problem");
primaryStage.setScene(scene);
primaryStage.show();
}
@FXML
private void launchImportDialog() throws IOException {
new ImportDataController().launchImportDialog(primaryStage);
}
@FXML
public void addFruitsComboBox(String fruit) {
ObservableList<String> fruitsList = fruitsComboBox.getItems();
fruitsList.add(fruit);
fruitsComboBox.setItems(fruitsList);
}
}
ImportData.fxml (package: problem.importdata)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox prefHeight="300.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.102" xmlns:fx="http://javafx.com/fxml/1" fx:controller="problem.importdata.ImportDataController">
<children>
<HBox alignment="TOP_CENTER">
<children>
<ComboBox fx:id="fruitsComboBox" prefWidth="150.0" />
</children>
</HBox>
<HBox alignment="TOP_CENTER">
<children>
<TextField fx:id="fruitTextField" />
<Button fx:id="addFruitButton" onAction="#onClickAddFruitBtn" text="Add Fruit" />
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Button fx:id="closeButton" onAction="#onClickCloseBtn" text="Close" />
</children>
</HBox>
</children>
</VBox>
ImportDataController.java (package: problem.importdata)
package problem.importdata;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import problem.MainWindowController;
import problem.Main;
public class ImportDataController {
private Stage primaryStage;
@FXML
private ComboBox fruitsComboBox;
@FXML
private TextField fruitTextField;
@FXML
private Button addFruitButton;
@FXML
private Button closeButton;
public void launchImportDialog(Stage primaryStage) throws IOException {
this.primaryStage = primaryStage;
FXMLLoader loader = new FXMLLoader(Main.class.getResource("importdata/ImportData.fxml"));
VBox root = loader.load();
Scene scene = new Scene(root, 400, 300);
Stage stage = new Stage();
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(primaryStage);
stage.setTitle("Import");
stage.setScene(scene);
stage.showAndWait();
}
@FXML
private void onClickCloseBtn() throws IOException {
Stage stage = (Stage) closeButton.getScene().getWindow();
stage.close();
}
@FXML
private void onClickAddFruitBtn() throws IOException {
String fruit = fruitTextField.getText();
fruitsComboBox.getItems().add(fruit);
fruitTextField.clear();
// Trying to add fruit data in main windows combo box but it is not working
FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
VBox root = loader.load();
MainWindowController mwc = loader.<MainWindowController>getController();
mwc.addFruitsComboBox(fruit);
}
}
Upvotes: 0
Views: 858
Reputation: 1986
// Trying to add fruit data in main windows combo box but it is not working
FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
VBox root = loader.load();
MainWindowController mwc = loader.<MainWindowController>getController();
mwc.addFruitsComboBox(fruit);
It's not working because instead of accessing a controller that already exists, you're creating a new instance.
Sharing the data between the controllers can be done in multiple ways, in your case, I believe, it will be fine to simply pass the reference to the ComboBox
item list to your ImportDataController
, the same way you pass your Stage
around.
new ImportDataController().launchImportDialog(primaryStage, fruitsComboBox.getItems());
It makes sense to do it the simple way, because the role of the controller in question is clearly defined - it imports the fruits, so it needs the data model to update.
If your controller was more complex this approach would be terrible for obvious reasons. You don't really want to maintain a long and messy list of parameters.
Upvotes: 2