Adding JavaFX2 Controls Dynamically

I am new to java and javafx and have a problem that I could not solve. I need to dynamically add new user controls to a javafx scene. Next, I need the interaction between the main control and the added controls. I found already useful information on the Internet, but could not collect it.

So, I am creating a small example to explain:

main class:

public class Test_TwoController extends Application { @Override public void start(Stage stage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("Fxml1.fxml")); Scene scene = new Scene(root); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } 

Main fxml file:

 <AnchorPane id="fxml1_anchorpane_id" fx:id="fxml1_anchorpane" prefHeight="206.0" prefWidth="406.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test_twocontroller.Fxml1Controller"> <children> <HBox id="fxml1_hbox_id" fx:id="fxml1_hbox" prefHeight="200.0" prefWidth="400.0"> <children> <Button id="fxml1_button_id" fx:id="fxml1_button" mnemonicParsing="false" onAction="#button_action" prefHeight="200.0" prefWidth="200.0" text="Button" /> </children> </HBox> </children> </AnchorPane> 

and its controller:

 public class Fxml1Controller implements Initializable { @FXML HBox hbox; @FXML Button button; @Override public void initialize(URL url, ResourceBundle rb) { } public void button_action(ActionEvent event) throws IOException { // 1. add an instance of Fxml2 to hbox // 2. change to tab2 in new Fxml2 // or // notify Fxml2Controller to change to tab2 in Fxml2 } } 

And now the control dynamically adds:

Its fxml:

 <AnchorPane id="fxml2_anchorpane_id" fx:id="fxml2_anchorpane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test_twocontroller.Fxml2Controller"> <children> <TabPane id="fxml2_tabpane_id" fx:id="fxml2_tabpane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE"> <tabs> <Tab id="fxml2_tab1_id" fx:id="fxml2_tab1" text="tab1"> <content> <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" /> </content> </Tab> <Tab id="fxml2_tab2_id" fx:id="fxml2_tab2" onSelectionChanged="#onSelectionChanged" text="tab2"> <content> <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" /> </content> </Tab> </tabs> </TabPane> </children> </AnchorPane> 

and controller:

 public class Fxml2Controller { @FXML TabPane tabpane; @FXML Tab tab1; @FXML Tab tab2; public Fxml2Controller() throws IOException { Parent root = FXMLLoader.load(getClass().getResource("Fxml2.fxml")); Scene scene = new Scene(root); Stage stage = new Stage(); stage.setScene(scene); } public void onSelectionChanged(Event e) throws IOException { FXMLLoader loader = new FXMLLoader(); // how can i get the current Fxml1 anchorpane instance? AnchorPane root = (AnchorPane) loader.load(getClass().getResource("Fxml1.fxml").openStream()); Button b = (Button)root.lookup("#fxml1_button_id"); b.setText("New Button Text"); // dont change the buttons text!!! } } 

Usage: fxml2 should be added to the hbox fxml1. Then after clicking the button in fxml1, the fxml2 tabs should change. Perhaps you look at this image http://s13.postimage.org/uyrmgylo7/two_controlls.png

So my questions are:

  • How can I add one or more fxml2 controllers to hbox fxml1?
  • How can I access one control from another or exchange data between controls? See the onSelectionChanged () method in Fxml2Controller for details.

Thanks in advance, solarisx

+6
source share
1 answer

You seem to have mixed up a few concepts that are different. First of all, Stage can be understood as a window on the screen. It has a Scene object that contains the actual SceneGraph. In your example, you create a new stage and a new scene populated with the contents of your second fxml file. This means that if you are working, a second window will appear containing your items. I do not think this is what you want to achieve.

In addition, when the FXMLLoader reads the file, it searches for the class that is specified as its controller and creates an instance of it through reflection. This means that when you call the load method in the constructor of the fxml controller of the file that you load with it, you call an infinite loop.

The last thing you need to understand is that the object returned by load() is an arbitrary node that can be placed in the SceneGraph of your application, like any other node.

So for your concept to work, you must do the following:

  • Move the download code that is currently in the constructor of your second controller to the button_Action method of your first controller.
  • Drop the code for the new scene in the new button_action button and take the node returned by FXMLLoader and add it to the HBox children.
  • For your second question, you can get an instance of the controller if you actually create an instance of FXMLLoader instead of calling the static method and use the load() method in it. After calling load() you can get the controller and the root object of the fxml file through getController() and getRoot() . You can use them just like any arbitrary object in your logic.
+5
source

All Articles