I wrote a code that display a window in JavaFX,
and I loaded XML file that gives me a number of Buttons that I need to create in run-time.
I used Parent as the root and I can't do Parent.getChildren().add(...)
as Pane.getChildren().add(...)
public void start(Stage primaryStage) throws Exception
{
FXMLLoader fxmlLoader = new FXMLLoader();
URL url =
this.getClass().getResource("/resources/UI.fxml");
fxmlLoader.setLocation(url);
Parent root = (Parent)fxmlLoader.load(url.openStream());
primaryStage.setTitle("N In A Row");
primaryStage.setScene(new Scene(root, 1000, 800));
m_GameController =
(MainController)fxmlLoader.getController();
primaryStage.show();
}
Use scene builder to add a container to your application then add the container variable in your application controller class. Now use the created container and add as much child as you want in it through the controller.
Related
I would like to communicate with a FXML controller class at any time, to update information on the screen from the main application or other stages.
Is this possible? I havent found any way to do it.
Static functions could be a way, but they don't have access to the form's controls.
Any ideas?
You can get the controller from the FXMLLoader
FXMLLoader fxmlLoader = new FXMLLoader();
Pane p = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
FooController fooController = (FooController) fxmlLoader.getController();
store it in your main stage and provide getFooController() getter method.
From other classes or stages, every time when you need to refresh the loaded "foo.fxml" page, ask it from its controller:
getFooController().updatePage(strData);
updatePage() can be something like:
// ...
#FXML private Label lblData;
// ...
public void updatePage(String data){
lblData.setText(data);
}
// ...
in the FooController class.
This way other page users do not bother about page's internal structure like what and where Label lblData is.
Also look the https://stackoverflow.com/a/10718683/682495. In JavaFX 2.2 FXMLLoader is improved.
Just to help clarify the accepted answer and maybe save a bit of time for others that are new to JavaFX:
For a JavaFX FXML Application, NetBeans will auto-generate your start method in the main class as follows:
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Now, all we need to do to have access to the controller class is to change the FXMLLoader load() method from the static implementation to an instantiated implementation and then we can use the instance's method to get the controller, like this:
//Static global variable for the controller (where MyController is the name of your controller class
static MyController myControllerHandle;
#Override
public void start(Stage stage) throws Exception {
//Set up instance instead of using static load() method
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = loader.load();
//Now we have access to getController() through the instance... don't forget the type cast
myControllerHandle = (MyController)loader.getController();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Another solution is to set the controller from your controller class, like so...
public class Controller implements javafx.fxml.Initializable {
#Override
public void initialize(URL location, ResourceBundle resources) {
// Implementing the Initializable interface means that this method
// will be called when the controller instance is created
App.setController(this);
}
}
This is the solution I prefer to use since the code is somewhat messy to create a fully functional FXMLLoader instance which properly handles local resources etc
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
}
versus
#Override
public void start(Stage stage) throws Exception {
URL location = getClass().getResource("/sample.fxml");
FXMLLoader loader = createFXMLLoader(location);
Parent root = loader.load(location.openStream());
}
public FXMLLoader createFXMLLoader(URL location) {
return new FXMLLoader(location, null, new JavaFXBuilderFactory(), null, Charset.forName(FXMLLoader.DEFAULT_CHARSET_NAME));
}
On the object's loading from the Main screen, one way to pass data that I have found and works is to use lookup and then set the data inside an invisible label that I can retrieve later from the controller class. Like this:
Parent root = FXMLLoader.load(me.getClass().getResource("Form.fxml"));
Label lblData = (Label) root.lookup("#lblData");
if (lblData!=null) lblData.setText(strData);
This works, but there must be a better way.
I would like to communicate with a FXML controller class at any time, to update information on the screen from the main application or other stages.
Is this possible? I havent found any way to do it.
Static functions could be a way, but they don't have access to the form's controls.
Any ideas?
You can get the controller from the FXMLLoader
FXMLLoader fxmlLoader = new FXMLLoader();
Pane p = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
FooController fooController = (FooController) fxmlLoader.getController();
store it in your main stage and provide getFooController() getter method.
From other classes or stages, every time when you need to refresh the loaded "foo.fxml" page, ask it from its controller:
getFooController().updatePage(strData);
updatePage() can be something like:
// ...
#FXML private Label lblData;
// ...
public void updatePage(String data){
lblData.setText(data);
}
// ...
in the FooController class.
This way other page users do not bother about page's internal structure like what and where Label lblData is.
Also look the https://stackoverflow.com/a/10718683/682495. In JavaFX 2.2 FXMLLoader is improved.
Just to help clarify the accepted answer and maybe save a bit of time for others that are new to JavaFX:
For a JavaFX FXML Application, NetBeans will auto-generate your start method in the main class as follows:
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Now, all we need to do to have access to the controller class is to change the FXMLLoader load() method from the static implementation to an instantiated implementation and then we can use the instance's method to get the controller, like this:
//Static global variable for the controller (where MyController is the name of your controller class
static MyController myControllerHandle;
#Override
public void start(Stage stage) throws Exception {
//Set up instance instead of using static load() method
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = loader.load();
//Now we have access to getController() through the instance... don't forget the type cast
myControllerHandle = (MyController)loader.getController();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Another solution is to set the controller from your controller class, like so...
public class Controller implements javafx.fxml.Initializable {
#Override
public void initialize(URL location, ResourceBundle resources) {
// Implementing the Initializable interface means that this method
// will be called when the controller instance is created
App.setController(this);
}
}
This is the solution I prefer to use since the code is somewhat messy to create a fully functional FXMLLoader instance which properly handles local resources etc
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
}
versus
#Override
public void start(Stage stage) throws Exception {
URL location = getClass().getResource("/sample.fxml");
FXMLLoader loader = createFXMLLoader(location);
Parent root = loader.load(location.openStream());
}
public FXMLLoader createFXMLLoader(URL location) {
return new FXMLLoader(location, null, new JavaFXBuilderFactory(), null, Charset.forName(FXMLLoader.DEFAULT_CHARSET_NAME));
}
On the object's loading from the Main screen, one way to pass data that I have found and works is to use lookup and then set the data inside an invisible label that I can retrieve later from the controller class. Like this:
Parent root = FXMLLoader.load(me.getClass().getResource("Form.fxml"));
Label lblData = (Label) root.lookup("#lblData");
if (lblData!=null) lblData.setText(strData);
This works, but there must be a better way.
I am trying to pass a stored preference value to a text box in a settings window that can be opened from a user login window. I am planning to do this by setting the value in the controller prior to open. As you can see, I am also trying to make the settings window a child of the login window. However, I am getting javafx.scene.layout.AnchorPane cannot be cast to javafx.fxml.FXMLLoader for reasons that I don't understand and am completely at a loss as to what to do.
My code for opening the settings window on the press of a button is as follows:
#FXML
void OpenSettingsWindow(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader = FXMLLoader.load(SettingsWindowController.class
.getResource("Settings.fxml"));
AnchorPane page = (AnchorPane) FXMLLoader.load(SettingsWindowController.class
.getResource("Settings.fxml"));
Scene scene = new Scene(page);
root = new Stage();
root.initModality(Modality.WINDOW_MODAL);
root.initOwner(Main.primaryStage);
root.setScene(scene);
SettingsWindowController controller = fxmlLoader.getController();
String databaseAddressValue = "databaseAddressValue";
controller.setDatabaseAddressValue(Preferences
.systemRoot()
.node("preferences.SystemPreferences")
.get(SystemPreferences.databaseAddress, databaseAddressValue));
root.show();
} catch (Exception e) {
e.printStackTrace();
}
Any advice as to how to fix this is much appreciated.
You are assigning the return value of FXMLLoader.load() to a FXMLLoader reference.
FXMLLoader.load() returns the highest object in you FXML file and that is for sure not a FXMLLoader object.
If you want to use a controller class for event handling and proper intialization you have to set it first and load the FXML in an other way (I assume that the SettingsWindowController is your controller class and has a default constructor):
SettingsWindowController controller = new SettingsWindowController();
FXMLLoader loader = new FXMLLoader(SettingsWindowController.class
.getResource("Settings.fxml"));
loader.setController(controller);
AnchorPane page = (AnchorPane)loader.load();
Try this :
FXMLLoader fxmlLoader = FXMLLoader(SettingsWindowController.class.getResource("Settings.fxml"));
AnchorPane page = (AnchorPane) fxmlLoader.load();
So I have been working on a JavaFX project where I have a pretty simple work flow. I have several different AnchorPanes that I use, on each the user will fill out some information and go on to the next AnchorPane. Whenever they move on to the next AnchorPane I load the new AnchorPane using the following code.
private Initializable replaceSceneContent(String fxml) throws Exception {
FXMLLoader loader = new FXMLLoader();
InputStream in = MyClass.class.getResourceAsStream(fxml);
loader.setBuilderFactory(new JavaFXBuilderFactory());
loader.setLocation(Caster.class.getResource(fxml));
AnchorPane page;
try {
page = (AnchorPane) loader.load(in);
} finally {
in.close();
}
Scene scene = new Scene(page, APP_WIDTH, APP_HEIGHT);
stage.setScene(scene);
stage.sizeToScene();
return (Initializable) loader.getController();
}
This loads everything fine. But I also have the ability to go back to the previous AnchorPane. Currently this uses the same method, but this is not ideal as it loads a brand new AnchorPane and all the information that user had previously entered is gone. I would like to persist the anchorpanes and reload them and have tried to reload them using code similar to the following
private void replaceSceneContent(AnchorPane page) throws Exception {
Scene scene = new Scene(page, APP_WIDTH, APP_HEIGHT);
stage.setScene(scene);
stage.sizeToScene();
}
However, this results in a totally white screen on my application, maybe because I am not loading the FXML again? I need some ideas on how to persist the data the users entered if they want to go back. Any ideas on how to do this well?
Is there a way to keep my scenes in separate Java files in a JavaFx application?
I tried something like this:
public class MyApp extends Application
{
private void init(Stage primaryStage)
{
Group root = new Group();
primaryStage.setResizable(false);
Login login = new Login(root, primaryStage); // from another file
primaryStage.setScene(login);
}
I have to close my login scene after authentication and load another scene from another file, so I'm passing the primaryStage as a parameter for my login Scene to use stage.close()
Is there a better way for doing that?
My Login scene file
public class Login extends Scene
{
public Login(Group root, final Stage stage)
{
super(root, 265, 390, Color.web("EBE8E3"));
Is there another way to reference the current scene stage?
You don't have to pass the stage as a parameter. The stage is always available from the nodes of the current scene !
scene.getWindow()
This returns the current stage/window of the scene !
Javadocs : http://docs.oracle.com/javafx/2/api/javafx/scene/Scene.html#getWindow%28%29
Example : How to get parent Window in FXML Controller?
http://blog.crisp.se/2012/08/29/perlundholm/window-scene-and-node-coordinates-in-javafx