JavaFX lssue when loading fxml file and seting its Label text - java

I made a similar question yesterday but I think it wasnt well explained, so I wanted to ask it again but with some changes I made in my code. I apologise if i write too much but i want to make everything understandable.
So, Im making a pokemon simulator where you can catch and train pokemon.
I have one main fxml file which contains buttons to access to the diferent fxml files like catch, battle, shop, bag...
Yesterday i was doing the bag where all your items will be stored.
Everything is working fine and the windows are switching between them properly. The problem comes when i was trying to add a Label to each item in the bag, which was suposed to show the user the cuantity he has of each item. So i created all the Labels with no text so they are empty.
They will get filled from the information i get from a database, this thing also works properly, i connect to the db and get the item cuantity. The problem comes when i want to show that item cuantity in my bag window.
Why? Because as you can imagine, i want that when you click on the bag button, the bag file loads with all the Labels filled with the cuantity of each item. The Labels are defined on the bag fxml controller, so if i want to fill them with some text, i cant do it from my main windows which uses another controller, i need to do it throught the bag controller.
This is the code i tried to make it work(Located in main controller):
#FXML
void mochila (ActionEvent event) throws IOException, SQLException {
AnchorPane pane = FXMLLoader.load(getClass().getResource("mochila.fxml"));
anchorPaneContent.getChildren().setAll(pane);
anchorPane2.setStyle("-fx-background-color: #3f3f3f;");
cm.getCantidad();
}
getCantidad is a function that i have in my bag controller and this is it:
public void getCantidad() {
lblpokeballCount.setText("Cantidad: "+pokeballcount);
lblsuperballCount.setText("Cantidad: "+superballcount);
lblultraballCount.setText("Cantidad: "+ultraballcount);
lblmasterballCount.setText("Cantidad: "+masterballcount);
}
So when i try to run this function from the main controller, it returns me null pointer exception. That means the labels are not initialized but when i type first AnchorPane pane = FXMLLoader.load(getClass().getResource("mochila.fxml"));Shoudlnt all the resources from the file be loaded?
Because i creaded a button in my bag file, when on clicked runs the same function, and it works correctly because im calling it from the same controller/file.
So now i dont really know what to do, this is a proyect for school but my programing teachers have never touched javafx so they dont even know what im doing. You are my only hope. I tried to understand this post: post
But i dont understand it at all as im new to all this stuff. So guys if you can help me i would be really gratefull, thanks!
edit:
#FXML
void mochila (ActionEvent event) throws IOException, SQLException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("mochila.fxml"));
anchorPaneContent.getChildren().setAll(loader);
controladorMochila controller = loader.<controladorMochila>getController();
controller.getCantidad();
}
anchorPaneContent is an anchorpane thats inside the main pane. All the buttons are in the main pane, and depending on the button you click, anchorpanecontent will change for another fxml file. I tried to do it like in the post i mentioned above. But i cant do anchorPaneContent.getChildren().setAll(loader); because it says: the node setAll is not aplicable for the arguments(FXMLLoader)

You are trying to add an FXMLLoader to an anchor pane, which will not work, since an FXMLLoader is not a visual component (it is a thing that loads FXML files).
Additionally, you are trying to get the controller from the FXMLLoader without actually loading the FXML file; this won't work because the controller class is specified in the FXML file (so the FXMLLoader doesn't know what kind of controller to create until it loads the file).
You need to load the FXML file and add the result to the anchor pane:
#FXML
void mochila (ActionEvent event) throws IOException, SQLException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("mochila.fxml"));
anchorPaneContent.getChildren().setAll(loader.load());
controladorMochila controller = loader.<controladorMochila>getController();
controller.getCantidad();
}
or, if you want to be a bit more explicit:
#FXML
void mochila (ActionEvent event) throws IOException, SQLException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("mochila.fxml"));
Parent pane = loader.load();
anchorPaneContent.getChildren().setAll(pane);
controladorMochila controller = loader.<controladorMochila>getController();
controller.getCantidad();
}

Related

How do you create a custom popup using fxml in javafx?

to create a new release the user would be prompted to click on the plus button in the bottom left of the GUI, when they click on this I want a pane overlayed on top of the center of the GUI allowing users to enter settings and specify options for a new release, I've tried this:
private void addRelease(Event event) throws IOException {
Popup popup = new Popup();
NewReleasePopupController controller = new NewReleasePopupController();
FXMLLoader loader = new FXMLLoader(getClass().getResource("Resources/NewReleasePopup.fxml"));
loader.setController(controller);
loader.load();
popup.getContent().add((Parent)loader.load());
}
however it seems to throw errors while loading, I would like to avoid loading a separate stage if at all possible and would like to have the controller for the popup to be nested within the controller for the main stage.
I tried using the popup class if anyone can help me to get that working or has any better ways to achieve this help would be much appreciated !!
the error:
Caused by: javafx.fxml.LoadException: Controller value already specified.
/D:/DropDayAIO/out/production/DropDayAIO/DropDayAIO/Resources/newReleasePopup.fxml:6
at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2621)
at javafx.fxml/javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:922)
at javafx.fxml/javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:980)
at javafx.fxml/javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:227)
at javafx.fxml/javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:752)
at javafx.fxml/javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
at DropDayAIO.HomeSceneController.addRelease(HomeSceneController.java:151)
at DropDayAIO.HomeSceneController.addNewRelease(HomeSceneController.java:128)
... 57 more
Based on the error you mentioned, I think you already have a controller declaration in the FXML file. like with attribute.. fx:controller
Usually while having this attribute declaration in fxml , if you try to set controller again, it throws Caused by: javafx.fxml.LoadException: Controller value already specified
And I believe this should be the case, because you can notice the error is raised at processAttribute method.
javafx.fxml/javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:980)
You can either remove it from the fxml or dont need to set in the code (through setController()). If you say, you want the reference of the controller, you can always get through loader.getController().
And top of that, if you manage to resolve Controller value already specified error, I think next you will encounter Caused by: javafx.fxml.LoadException: Root value already specified.Because you are trying to call the load() method of the FXMLLoader two times. Assign the node to a variable and use that variable to set in popup.
I believe the below code should solve the issue. Give a try!!
private void addRelease(Event event) throws IOException {
Popup popup = new Popup();
FXMLLoader loader = new FXMLLoader(getClass().getResource("Resources/newReleasePopup.fxml"));
Parent parent = (Parent)loader.load(); // I am not sure you need a cast here
newReleasePopupController controller = loader.getController();
popup.getContent().add(parent);
}
Suggestion: Please use proper naming conventions of class.

Setting stage icon

My first intention was to set TextInputDialog icon. But I started from setting stage icon. I saw couple SO questions with marvelous answers containing usually 2 lines of code.
First I tried to put this icon to /resources/icons but exception "Invalid URL or resource not found" appeared. To be sure I don't make any mistake writing file path I moved this icon to /source/sample directory. I use code (I will post whole code):
public void start(Stage stage) throws Exception {
FXMLLoader loaderModyfikacjaKonfiguracji = new FXMLLoader(getClass().getResource("FXMLModyfikacjaKonfiguracji.fxml"));
Parent root = loaderModyfikacjaKonfiguracji.load();
stage.setTitle("Modyfikacja konfiguracji");
Image image = new Image("file:icon.png");
//stage.getIcons().removeAll();
stage.getIcons().add(image);
ControllerModyfikacjaKonfiguracji controllerModyfikacjaKonfiguracji = loaderModyfikacjaKonfiguracji.getController();
stage.setScene(new Scene(root, 510, 700));
stage.show();
}
Everywhere it looks so simple to set icon. I also tried .jpg. not using file: throws exception, using file: compiles but I see no effect of changed icon. What am I doing wrong or where is the problem?
I've successfully used this to set an icon before
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("AppIcon.png")));
In my case, the application fxml file and AppIcon.png are in the same directory.
If you dont want to go that route, i would suggest trying
Image image = new Image("file:./icon.png");
But that's a guess.

Switching Scenes with several FXML files

I am new to Java FX and trying to build up an "easy" application which consists of a header button bar and a "content area" below.
I've managed a big part like that:
MainWindow.fxml with a Borderpane: MenuBar in the Top Area
And a Pane with fx:id: content in the center area.
Several X.fxml files for the content ()
One Controller which creates the obj content:
#FXML
private Pane content;
and switches the content:
content.getChildren().clear();
content.getChildren().add(FXMLLoader.load(getClass().getResource("Navi.fxml")));`
Main file which initializes the parent and scene:
Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
Stage Window = primaryStage;
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
Window.setTitle("ICIS - In Car Interactive System");
Window.setScene(scene);
Window.show();`
So far everything works fine!
But now I want to apply a SplitPane and do the "content change" in each side of the Split Pane (TwoWindows.fxml): So I've extended the
Controller with obj. for every Pane of the Split Pane, assigned the fx:id to that pane and want to control them analog to the example before.
#FXML
private Pane SecondWindow1;
SecondWindow1.getChildren().add(FXMLLoader.load(getClass().getResource("Navi.fxml")));
Well, during compilation everything is fine, but while running I get the Null error exception, so that I assume SecondWindow1 (left half of SlitPane) is not known to the controller.
I also assume, it is because I initialize at the beginning only MainWindow.fxml (which includes the content area) but not the TwoWindows.fxml (SplitPane) which inlcude the SecondWindow1 Object.
Well I've tried since hours now to solve it, but apparently I am overlooking sth. Somebody knows how to fix that problem? Do I need one Controller for every FXML File?

Internal graphics not initialized yet: javafx

I'm trying to write a javaFx application whit multiple images inside a window.
The short story is that I have an enum class named Candy and each candy has some properties and a path to the image file representing it.
In the constructor of my javafx.application class (Table) I want to fill an array list with those images, so I wrote this so far:
public class Table extends Application {
ArrayList<Image> images;
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("CandyFx");
primaryStage.show();
}
public Table() {
images = new ArrayList<Image>();
for (Candy candy : Candy.values()) {
File file = new File (candy.getImagePath());
Image image = new Image(file.toURI().toString());
images.add(image);
}
}
}
Now every time I want to create an instance of Table class, the application throws a java.lang.RuntimeException: Internal graphics not initialized yet.
How can I initial graphics which it seems I did not?
First of all if you are using linux ,GTK 2.18 is required to run JavaFX .try to install
libswt-gtk-3-java
This exception will thrown whenever your screen is null .Try to create your images inside start method. Just before the primaryStage.show();.
Take a look at this link too
http://cr.openjdk.java.net/~vadim/RT-33475/webrev.00/modules/graphics/src/main/java/com/sun/glass/ui/Screen.java.html
I have no idea how it exactly works, but when we first create a JFXPanel in our start we don't get the errors anymore.
JFXPanel jfxPanel = new JFXPanel();
Actually, JavaFX Stage class is the top level JavaFX container which should be constructed and modified on the JavaFX Application Thread.
Here you are using Stage class but have not embed JavaFx content into Swing application which may show you a 'java.lang.RuntimeException with message Internal graphics not initialized yet.
Here you may use-
JFXPanel jfxPanel = new JFXPanel();
Or you may use in this way too.
JFrame frame = new JFrame("Java Swing And JavaFX");
JFXPanel jfxPanel = new JFXPanel();
frame.add(jfxPanel);
JFXPanel is a component to embed JavaFX content into Swing applications. The content to be displayed is specified with the setScene(javafx.scene.Scene) method that accepts an instance of JavaFX Scene. After the scene is assigned, it gets repainted automatically. All the input and focus events are forwarded to the scene transparently to the developer.
References:
JFXPanel: https://docs.oracle.com/javase/8/javafx/api/javafx/embed/swing/JFXPanel.html
Stage: https://docs.oracle.com/javase/8/javafx/api/javafx/stage/Stage.html

JLabel does not update when using setText method

In the project I am currently working on I have several pieces of information that I would like to make visible via Jlabel. There are a few buttons and textfields elsewhere in the GUI that allow for altering said information I would like to update the JLabel but the text never changes, or updates upon startup.
I have attempted to use concurrency to update the labels, as suggested in other questions on this site, but I have had no luck with the labels updating. The concurrency does work with updating textfields and comboBoxes as needed.
The current iteration of my code looks as follows,
The JFrame
//// This is a snippet from the JFrame
public void start()
{
this.setSize(900, 700);
this.setVisible(true);
devicePanel.populateDeviceDefinitions();
updateServiceInfo();
updateCommandInfo();
startUpdateTimer();
}
public void updateServiceInfo()
{
EventService service = JetstreamApp.getService();
generalPanel.updateServiceInfo(service.getBaseUri(),
service.getAccessKey(), String.valueOf(service.getWindowTime()));
}
public void updateCommandInfo()
{
JetstreamServiceClient client = JetstreamApp.getClient();
generalPanel.updateCommandInfo(client.getBaseUri(), client.getAccessKey());
}
The JPanel named generalPanel
//// This is a snippet from the generalPanel
//// All of the variables in the following code are JLabels
public void updateServiceInfo(String baseUrl, String accessKey,
String windowTime)
{
serviceUrl.setText(baseUrl);
serviceAccessKey.setText(accessKey);
serviceWindowTime.setText(windowTime);
}
public void updateCommandInfo(String baseUrl, String accessKey)
{
commandUrl.setText(baseUrl);
commandAccessKey.setText(accessKey);
}
The labels start with an Empty string for their text and upon window start it is intended that they be updated by grabbing the information from the relevant sources. Can I please have some insight as to why the JLabels never update and display their information?
How did you create the JLabel? If the text starts out as "", and you've created it with new JLabel(""), the width of the JLabel may be initialized to 0 and then none of your text would show up when you update it. I believe I've had that sort of problem in the past. As a test, try using new JLabel("aaaaaaaaaa") or some longer string to create the label, then setText(""); then later, when you setText(somethingElse), see if that causes text to show up. If it does, then the width is probably the problem and you can work on it from there. – ajb 19 mins ago
This comment is the actual answer, when creating a JLabel with an empty string as the text the label's dimensions do not get set properly when using WindowBuilderPro. My labels did exist, and were being updated with the code provided in my question but the labels were not visible.
Starting with a label that has text in it, then setting the text to an empty string works properly.
The method paintImmediately() can be used to cause a Swing component to get updated immediately. after setText(), you should call paintImmediately() like below.
jLabel.setText("new text")
jLabel.paintImmediately(jLabel.getVisibleRect());
You should try to call revalidate() or repaint() on the component that contains your JLabels.
Cheers

Categories