I'm new to javaFX and I'm trying to run a simple app. it's UI is created with javaFX scenebuilder and the Main class is supposed to display the UI, nothin else.
public class Main extends Application {
public static void main(String[] args) {
launch(Main.class, (String[])null);
}
#Override
public void start(Stage primaryStage) {;
try {
AnchorPane root=(AnchorPane)FXMLLoader.load(Main.class.getResource("Main.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Issue Tracking Lite Sample");
primaryStage.show();
} catch (IOException e) {System.err.println(e);}
}
}
I got this error when running the app:
No resources specified.
/D:/workspace/FileSharing_ServerSide/bin/com/Shayan/FileSharing/Server/Main.fxml:16
at javafx.fxml.FXMLLoader$Element.processPropertyAttribute(FXMLLoader.java:305)
at javafx.fxml.FXMLLoader$Element.processInstancePropertyAttributes(FXMLLoader.java:197)
at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:588)
at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2430)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2136)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2028)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2742)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2721)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2707)
javafx.fxml.LoadException: No resources specified.
It says that the file doesn't exists, but it exists in that folder with the exact same name! it's in the same package as the code is. anybody knows what's going on?!
thanks in advance
JavaFX throws the exception javafx.fxml.LoadException: No resources specified. when the FXMLLoader could not fully build the scene graph because of a missing resource.
This could happen for a variety reasons. I've encountered it because of the following:
There was an error loading the controller specified in the fxml file.
The fxml file tries to reference a resource in a ResourceBundle but the FXMLLoader did not have the ResourceBundle properly configured.
There may be other reasons why this exception is thrown from within JavaFX, but the root cause is that for some reason or another, the FXMLLoader encountered an exception while trying to create the scene graph from the fxml file.
To get the resource, you'll have to specify the full (!) base name. That is, with all the packages before.
If the resource file has the same bas name as the controller class (which is quite reasonable as it helps keeping things together), you can do this in the following way:
String className = this.getClass().getCanonicalName();
// #formatter:off
ResourceBundle languageResource =
ResourceBundle.getBundle(className, Locale.GERMAN);
// formatter:on
Object objPane = FXMLLoader.load(fxmlUrl, languageResource);
I have written a private resource loader helper, that will do the trick by getting an Object and a Locale. Of course, I use a locale constructed from my settings, not a constant, but I wanted to keep things simple.
For the name of the resource file: As my class is named MainWindow, the resource file (in the same package) is MainWindow_de.properties (where "de" is the part of the language, so I also have a MainWndow_en.properties in the package.
The extension is required, as this is the way the file name is being constructed. Without the extension, the file will not be recognized, leading to your well-known exception.
Hope that prevents others from spending hours in doing research...
Related
I apologize as I understand that the question is a bit broad in nature. What I want to achieve is having the ability to load different FXML files (located in different packages) when specific conditions are met, for example when a button is pressed or when a certain condition is satisfied. So far I've managed to load a file when a button is pressed.
#FXML
private AnchorPane rootPane;
#FXML
private Button btn;
#FXML
private void loadLoginWindow(javafx.event.ActionEvent event) throws IOException {
AnchorPane pane = FXMLLoader.load(getClass().getResource("login/MainWindow.fxml"));
rootPane.getChildren().setAll(pane);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
And it works fine but for one button and one handler only, as soon as another is added it stops working, it seems that only one can work at the time. So clearly I'm missing a bunch of important info but every tutorial I've had a look at doesn't address this point because they don't even get there (They all revolve around a single file, or they rely on hiding and showing panes from the same file)
Does anyone have any good tutorial or comprehensive guide to do this kind of things?
Thanks in advance.
What can happen is the link to the controller within the FXML file can be incorrect. Even though the file location may not exist, the application will still build.
<AnchorPane id="AnchorPane" fx:controller="main.MainController">
The pathway in the fx:controller need to be correct.
Cheers!
Recently I started learning JavaFX and now something is bothering me and I can’t find a solution to my “problem”. I have found similar questions and couple of solutions to problems like mine, but I couldn’t find one that’s working for me or simply I am doing something wrong. What I want to do is to have one main FXML file with its own FXML Controller Class. Then I want to add (import) other FXML files, which also have controllers, in the main FXML. I tried couple of things, but nothing worked, so I decided to describe what I am doing. First I am creating the Main FXML file with Scene Builder and then I am creating the Controller for the Main FXML. Then I am setting in Scene Builder the controller class for the Main FXML to be the Main Controller (of course…). After that I am doing the same for the second FXML. Then I am trying to import the second FXML to the Main FXML and it works fine, if I haven’t set a controller for the second FXML. If I have however selected a controller for the second FXML before importing it to the Main FXML, I am still able to import the FXML file and save it, but after I try to run the program, I am getting an error. So basically what I am trying to do is to have multiple FXML files with their own controllers in one Main FXML file, which also has a Controller Class. I am not exactly sure that this is possible at all, so please tell me is that possible at all, and if it’s possible, what am I doing wrong. This is my code :
public class MainSceneController implements Initializable {
#FXML
private TextField mainTxtField;
public MainSceneController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainScene.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
try {
fxmlLoader.load();
} catch (IOException exc) {
} }
#FXML
public void buttonActionMethod(ActionEvent event) {
mainTxtField.setText("Button1 is clicked");
}
#Override
public void initialize(URL location, ResourceBundle resources) {
} }
I called the second FXML and the second controller LeftScene and LeftSceneController, so here is the code for the second controller :
public class LeftSceneController implements Initializable {
#FXML
private TextField leftTxtField;
public LeftSceneController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainScene.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
try {
fxmlLoader.load();
} catch (IOException exc) {
}
}
#FXML
public void button2Action(ActionEvent event) {
leftTxtField.setText("Button 2 is clicked");
}
#Override
public void initialize(URL location, ResourceBundle resources) {
} }
And finally, this is the MainClass, in which are the main method and the start method :
public class MainClass extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("MainScene.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Multiple FXMLs in one");
primaryStage.show();
} }
I hope you are getting what I want to do. As I said, I have tried a lot of things and none of them worked how I wanted it to. This version is compiling and it’s running, if I don’t set a controller class for the second FXML before importing it, but as you can expect, the second button from the imported FXML is not doing anything. I would post screenshots, if I could, but I am new here and usually I am only reading, so I am not allowed to post screenshots. Also I tried to post my FXML code, but I was having problems with the system and I couldn't post more than one line of the code.
So… Is it possible to make this work how I want it to or not?
And also if you read all this mess, thanks at least for your time! :)
It has been a while, but finally I found an answer to my question. I found this video on YouTube and it is showing exactly what I needed. Although I found a couple of problems while I was doing the things from the video step by step.
First of all, if I import another FXML file into the main FXML, like in this tutorial, SceneBuilder is importing the FXML like the things from the imported FXML are in the main FXML and this causes problems. What I mean is for example if you have a Button in the imported FXML, when you import it in the main FXML with SceneBuilder, the imported Button appears in the main FXML like a new Button with all the information for it (postion, onClickMethod, etc.) and that it's not how it's supposed to be. This causes errors, because Java is looking for the onClickMethod for the imported button in the Main Controller and not in the Controller of the imported FXML. I don't know why it's different by me and it is not like in the video, but the solution is simple. If you want to import a FXML file into another FXML, you should do it with an editor and you just have to add the following line in the content of the main FXML :
<fx:include fx:id="importedFXML" source="ImportedFXML.fxml" />
The important thing in this case is that the fx:id should be with the same name as the .FXML file, but with a small first letter.
And the other thing, which was shown in the video and which caused problems by me was if you want to have a multiple imported FXML files and you want them to communicate with each other. The video is showing how to do that, but it is not mentioning that the Controller objects of the imported FXML files, which you have to create in the MainController, must have the same names like the fx:id + the word Controller. For example with the fx:id from above, the object should look like this :
#FXML private ImportedFXMLController importedFXMLController
if the ImportedFXMLController is the controller of the importedFXML
So, I hope that this is going to be helpful to someone.
I'm trying to open multiple windows with JavaFX, I have an eventlistener that opens a new window when a button is clicked it looks like this:
#FXML
private void joinAction() {
Parent root;
try {
Stage stage = (Stage) joinButton.getScene().getWindow();
stage.close();
root = FXMLLoader.load(getClass().getResource("main.fxml"));
stage = new Stage();
stage.setTitle("TuneUs");
stage.setScene(new Scene(root));
stage.show();
} catch (IOException e) {e.printStackTrace();}
}
the first window opens and the new one opens, but my problem is getting events to work with my second window
in main.fxml I have this line:
<TextField id="chat_bar" onAction="#sendChat" layoutX="14.0" layoutY="106.0" prefHeight="22.0" prefWidth="403.0"/>
Then in my controller class I have this method:
#FXML
private void sendChat() {
System.out.println("test");
}
but Intellij is telling me that; no controller specified for top level element
So, my question is: Do I need to create multiple controller classes or can I use just one for multiple windows if so how?
The recommended approach is to define a controller for each FXML. Since controllers are very lightweight this shouldn't add much overhead. The controller for your main.fxml file might be as simple as
import javafx.fxml.FXML ;
public class MainController {
#FXML
private void sendChat() {
// ...
}
}
I have used this approach with fairly large numbers of FXML files and corresponding controllers in a single project, and have had no issues with managing the code etc. I recommend using a naming convention of the form Main.fxml <-> MainController.
If your controllers need to share data, use the techniques outlined in Passing Parameters JavaFX FXML
As #Vertex points out in the comments, there is an alternative approach provided by the FXMLLoader.setController(...) method. So in your example above, you could do
#FXML
private void joinAction() {
Parent root;
try {
Stage stage = (Stage) joinButton.getScene().getWindow();
stage.close();
FXMLLoader loader = new FXMLLoader (getClass().getResource("main.fxml"));
loader.setController(this);
root = loader.load();
stage = new Stage();
stage.setTitle("TuneUs");
stage.setScene(new Scene(root));
stage.show();
} catch (IOException e) {e.printStackTrace();}
}
#FXML
private void sendChat() {
// ...
}
This approach is fine if you are not setting any fields (controls) via FXML injection (i.e. with an fx:id attribute in the fxml and a corresponding #FXML annotation in the controller). If you are, it will be very difficult to keep track of when those fields have been set. Moreover, if your joinAction handler is invoked multiple times, you will have multiple instances of the node created by main.fxml, but all sharing a single controller instance (and consequently overwriting the same injected fields). Also note that with this approach, your initialize() method will be invoked both when the original fxml file is loaded, and when the main.fxml file is loaded, which will almost certainly cause undesired effects.
One last note: if you have many FXML files, and corresponding controllers, you might want to look at the afterburner.fx framework. This is a very lightweight framework that mandates a naming convention on FXML files and their corresponding controllers, and also provides a (very) easy mechanism for sharing data between them.
You need to add top level element fx:controller. Look at this answer:https://stackoverflow.com/a/41316536/4247308
I create Borderpane, and inside it vbox at left and scene at the center and also implement initializable . Every time i click diff button in vbox, it changes only scene. For every scene, i create scene.fxml file.
The problem I'm having is that when I create a new JavaFX project in NetBeans the main method is ignored, and somehow start() is somehow called and everything is just fine, but any time I try to call start I wind up with an exception. The class I used:
public final class JFXDriver extends Application {
public JFXDriver() {
Application.launch();
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("GUI.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
I've attempted to start it using the constructor, but it fails (Throws an Exception) for some reason saying that it is being called more than once, which should be impossible because I've constructed this class from a main method with only the new JFXDriver(); in it.
You are doing it wrong in the code. You should not call launch in your constructor. You should call it in your main and pass the name of the class that extends Application.
This causes the system to call init and then start and thus begins the lifecycle of your applicaton. For a more detailed explanation have a look here: http://codelatte.wordpress.com/2013/11/15/getting-started-with-javafx-hello-world-2/
Are you attempting a Swing and FX interop ?
Alright, I've found a solution to the problem. I added:
public static void start() {
Application.launch();
}
and took out the call to Application.launch() in the constructor. This approach worked. I guess that the JavaFX thread created its own instance of the class leading to the Application.launch() being called more than once. Interestingly, without the one application limit, I wonder if this would have led to a StackOverflowException due to the recursive nature of the call.
Background: I've created a JavaFX application, embedded in a Swing frame using JFXPanel. I've been using Eclipse as an IDE. The "Main application" is another class which only serves to create an instance of a class which extends JFXPanel to load my .fxml file when it is instantiated. When executing the main class from Eclipse, all is well, the fx:controller specified in my .fxml file has its initialize() method called (I can tell from changes it makes to the UI on load) and there are no problems.
However, when I package everything into a JAR and try to add my JFXPanel extension class to a Swing JFrame instance, it manages to load the .fxml file just fine-read images, style sheets, etc, and the rest of the code is functioning as expected however the fx:controller's initialize() method is never called. I have no problem accessing the class from other classes inside or outside the jar and I've even tried setting up a ControllerFactory that will return an instance of the Controller as well as trying all sorts of combinations of setting the FXMLLoader's classloader and using both the static and non-static methods of invoking load(). The result is always the same: it will work when launching from the IDE but does not when launching from my packaged jar. I know the jar isn't missing any files because like I said there is no issue finding the class from the Java code and the bundled fxml/css files seem to be loading fine, minus the controller issue.
Anybody ever encounter this before or have any idea what might be going on with the FXMLLoader failing to set the Controller? Could this be a bug of some sort?
I had a similar problem when packaging my JavaFX software into a .jar file. Turned out it was a problem regarding relative path. You're IDE has no issues with this, but then when compiled within a jar it is having issues.
This was resolved using following code to call my .fxml file.
getClass().getClassloader().getResource("/my/view/selector.fxml")
To say that this is the "reason" for your bug, I'm not sure, but this sure stumped me for a while and seems to be pretty much the problem I had.
Original question : Executable Jar limited to one window with JavaFX
I was unable to solve this problem. While the fxml/css files are loading fine and referencing the right controller class, I was still unable to see the initialize() method of the controller class get invoked once everything was packaged up into a jar.
Since the only thing I needed the controller for was to grab the various UI objects defined in the fxml file so that I could do real programming with them, I opted instead to just create a recursive search to look for these individual widgets by their fxml ID [seems to look up 'id' first then 'fx:id' if an 'id' isn't found] in the Scene tree..
//grabs fxml file relative to root of the jar
FXMLLoader loader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("app.fxml"));
Parent javaFXRoot = (Parent) loader.load();
public Node findWidgetByID(String id, Parent javaFXRoot)
{
return findObject(root, id);
}
private Node findObject(Parent root, String id)
{
for (Node node : root.getChildrenUnmodifiable())
{
if (node.getId() != null && node.getId().equals(id))
{
return node; // found the node, return it
}
Node retValue = null;
if (node instanceof Parent)
{
retValue = findObject(((Parent) node), id); // recursive search
}
if (retValue != null) //if our node was found by the recursive search, return that
{
return retValue;
}
}
return null;
}
I had the same problem where the initialize() method was called from the IDE, but not from a (shaded) jar.
The problem was that we used ProGuard which was configured to keep protected and public methods. However, the initialize() method was declared private. Therefore it obfuscated the method name, JavaFX couldn't find any appropriately named method and initialize() was never called.
To stop ProGuard from obfuscating your JavaFX annotated methods and fields, include this rule into your proguard.conf:
-keepattributes javafx.fxml.FXML
-keepclassmembers class * {
#javafx.fxml.FXML *;
}
The first line will keep the #FXML annotations, the other rule keeps #FXML annotated class member names.