Preface: I am pretty new to JavaFX
Made an simple image resizing application and need to build an artifact of the application.
Using IntelliJ and Eclipse (tried both), i built normal JAR artifacts and JavaFX artifacts. Both are executable, but only show an empty window.
When starting the application out of the IDE, there is no problem; the window containing all subpanes get displayed as they should.
Any ideas how to solve this problem? Thanks in advance!
Attached code of the application initialization part and a picture of the resulting windows - maybe it helps.
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private SettingsViewController settingController;
private MainViewController mainViewController;
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("SimpleImageResizer");
this.primaryStage.getIcons().add(new Image("file:icon.png"));
this.primaryStage.setOnCloseRequest(we -> ConfigurationCache.getInstance().pushConfig());
targetResolutions.addAll(Arrays.asList(ResolutionPreset.values()));
supportedFileFormats.addAll(Arrays.asList(SupportedFileFormat.values()));
initRootLayout();
showMainView();
showSettingsView();
primaryStage.setResizable(false);
}
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml"));
rootLayout = loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
.
.
.
public static void main(String[] args) {
launch(args);
}
You didn't provide enough information to solve your problem, so here's an example that does work:
Create a package application and put this class into it:
application/Main.java
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/application/RootLayout.fxml"));
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Create a "RootLayout.fxml" in the package application.
application/RootLayout.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<children>
<Pane layoutX="-125.0" layoutY="-143.0" prefHeight="200.0" prefWidth="200.0">
<children>
<Button layoutX="134.0" layoutY="161.0" mnemonicParsing="false" text="Button" />
</children>
</Pane>
</children>
</AnchorPane>
In Eclipse select
Export -> Runnable JAR file -> Extract required libraries into
generated JAR
(of course you need to specify the proper launch configuration)
The generated JAR can be executed and has the nodes from the fxml.
loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml"));
try with
loader.setLocation(MainApp.class.getResource("/view/RootLayout.fxml"));
NetBeans the first variant will not compile in IDE
I faced the similar issue.It works well with the IDE but when I create a jar and try to run it was not able to load the fxml files. Following worked me.You can try and check if its getting the fxml files.
String fxml = "/com/test/fxmls/gui.fxml";
InputStream in = MycLass.class.getResourceAsStream(fxml);
if(in!=null){
FXMLLoader loader = new FXMLLoader();
loader.setBuilderFactory(new JavaFXBuilderFactory());
loader.setLocation(MycLass.class.getResource(fxml));
BorderPane rootLayout = (BorderPane)loader.load(in);
}else{
//log or output the error
}
I think Resource files cannot be accessed from the jar file. So in this case your trying to load the fxml files from the jar which is not possible. other wise follow the method that #Roland has suggested.
Related
This question already has an answer here:
javafx 8 compatibility issues - FXML static fields
(1 answer)
Closed 5 years ago.
I am new to JavaFX. Trying to follow a tutorial to generate a scene and associate eventhandler with a button.
I created a Main.FXML and edited in SceneBuilder. Since I added SceneBuilder's path in my IDE, it is able to detect my main controller. I wrote a function to generate random number.
public class MainController {
public static void generateRandom(ActionEvent event) {
Random rand = new Random();
int myrand = rand.nextInt(500) + 1;
System.out.print(Integer.toString(myrand));
}
}
In scenebuilder, it detects this method in controller which can be easily added as eventhandler for OnAction of the button. Main.FXML is updated after the operations.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="300" prefWidth="500" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111" fx:controller="application.MainController">
<children>
<Button layoutX="204.0" layoutY="204.0" mnemonicParsing="false" onAction="#generateRandom" text="Button" />
<Label layoutX="138.0" layoutY="36.0" prefHeight="144.0" prefWidth="210.0" />
</children>
</AnchorPane>
My main application class is as below:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/application/Main.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("My Title");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
When I run the app, I got error:
javafx.fxml.LoadException: Error resolving onAction='#generateRandom',
either the event handler is not in the Namespace or there is an error
in the script.
/C:/Users/Oscar/Workspace/Sunoco/bin/application/Main.fxml:10
Error resolving “onAction” while loading FXML suggests it may have to do with wrong import for ActionEvent which is not the case. Plus everything is set up automatically using SceneBuilder and Eclipse. So why am I getting this error?
I think the problem will be solved if you use an #FXML annotation on the eventMethod. Besides, try not to make methods static in the controller, as it may be confusing/misleading. If you need that method to be accesible from elsewhere, consider declaring it in a separate (utility like) class.
So I'm trying to move from Swing to JavaFX and I just declare the start() and launch() methods without knowing how they work. But below code prints false and false to the console. However when I click the button in the GUI, built with Scene Builder, that executes myMethod(), this time it prints true. Why does it say that primaryStage isn't instantiated?
addition information:
I also made this class my Controller, for the same reason - it needs access to the Stage reference. The full version of Main, which I didn't post, implements Initializable if that matters.
As a bonus question I was wondering if I need the field of primaryStage to reference the Application Stage, which there would only be one of?, in myMethod().
public class Main extends Application {
private Stage primaryStage;
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
try {
Scene scene = new Scene(FXMLLoader.load(getClass().getResource("Sample.fxml")),600,400);
primaryStage.setScene(scene);
} catch(Exception e) {
e.printStackTrace();
}
primaryStage.show();
//both lines below print false; As they should.
System.out.println(this.primaryStage == null);
myMethod();
}
public static void main(String[] args) {
launch(args);
}
public void myMethod() {
System.out.println(primaryStage == null);
}
}
EDIT
placing this FXML document in the same folder as above class will let you run Main to see that the button does indeed print true.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Main">
<children>
<Button mnemonicParsing="false" onAction="#myMethod" text="Button" />
</children>
</HBox>
That is because the FXMLLoader will create new instance of application.Main class, in where the start() method is not invoked and thus private Stage primaryStage is null.
It is better to separate the main class and the controller for the FXML, and pass the primary stage later if it is necessary:
...
try
{
FXMLLoader loader = new FXMLLoader( getClass().getResource( "Sample.fxml" ) );
Scene scene = new Scene( loader.load(), 600, 400 );
( (MyController) loader.getController() ).setPrimaryStage(primaryStage);
primaryStage.setScene( scene );
}
catch ( Exception e )
{
e.printStackTrace();
}
...
where the MyController class can be as simple as:
public class MyController {
private Stage primaryStage;
public void setPrimaryStage(Stage primaryStage) {
this.primaryStage = primaryStage;
}
}
but also can implement Initializable interface. Refer to Introduction to FXML :: Controllers.
Also note that you can get the scene and its stage from any node that is part of that constructed scene graph (i.e. a stage that is shown) by:
Scene scene = anynode.getScene();
Stage primaryStage = (Stage) anynode.getScene().getWindow();
Of course, for the secondary stages created by you the getWindow() will return that stage and not the primary stage.
There is no need at all to jump through any of these hoops to get access to the window. You can just call getScene().getWindow() on any node to get the window in which it is displayed (and of course you can just inject any node into your controller in the usual way).
Don't use the Application subclass as the controller class: you will have (at least) two different instances (one created by the launch() method, because it's the Application subclass, and one created by the FXMLLoader, because it's the controller class). Different fields will be initialized in the different instances.
Create a controller class, and inject at least one node into it:
public class Controller {
#FXML
private Parent root ;
#FXML
private void myMethod() {
Window window = root.getScene().getStage();
// assuming you are running as a standalone application, the window
// will actually be a Stage instance.
window.hide(); // for example...
}
}
Use this as your controller class and inject the node into it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller" fx:id="root">
<children>
<Button mnemonicParsing="false" onAction="#myMethod" text="Button" />
</children>
</HBox>
I have a small code of javaFX.
I want to draw in canvas but I have some problem of beginner I really don't understand well javaFX.
This is my Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
Controller controller;
#Override
public void start(Stage primaryStage) throws Exception{
controller= new Controller();
controller.Pane = FXMLLoader.load(getClass().getResource("sample.fxml"));
System.out.printf("kk"+controller.canvas.isResizable());
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(controller.Pane, controller.Pane.getPrefWidth(), controller.Pane.getPrefHeight()));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
this is sample.FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.canvas.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="Pane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="284.0" prefWidth="484.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<Canvas fx:id="canvas" height="267.0" layoutX="13.0" layoutY="9.0" width="459.0" AnchorPane.bottomAnchor="8.0" AnchorPane.leftAnchor="13.0" AnchorPane.rightAnchor="12.0" AnchorPane.topAnchor="9.0" />
</children>
</AnchorPane>
For the controller.java there is only canvas and pane declaration.
My question :
Pane is the parent and canvas is the children after doing FXMLloader.load etc, pane is not null but the children are null in the method start (outside like an event of button the children aren't null) why is children null?
To make the canvas resizable there is no method to do such thing, the only solution is to extends from Canvas and #Override method isResizable make it true. But Canvas I get it from FXML if I do
Canvas MyCanvas= new CanvasResizable();
this dosen't work I don't know why.
is there a way like android to make for example canvas=(Canvas) findbyid(FXML.id.canvas); (something similar)
and my last question how can we change the color of canvas there is no method to do that.
I'm sorry if my question is already asked by a diffirent why, I searched so much in google there is a lack of documentation of javaFX.
FXML controller should not be created directly. It will be initialized for you by FXMLLoader:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Pane root = loader.load(); // controller was initialized
controller = loader.getController();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, root.getPrefWidth(), root.getPrefHeight()));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You can find more details in Oracle tutorials: http://docs.oracle.com/javafx/2/fxml_get_started/fxml_tutorial_intermediate.htm#CACFEHBI
I have a JavaFX Application. I have a button that when clicked calls an action and loads another fxml file. This works perfectly.
I decided to place this functionality from within the menu of the application.
So, I created a Menu and I added Menu Items from within the Scene builder. I properly assign the 'On Action' event, the same way I did with my other button. However I get the following error when I click:
Glass detected outstanding Java exception at -[GlassViewDelegate sendJavaMouseEvent:]:src/com/sun/mat/ui/GlassViewDelegate.m:541
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
Caused by: java.lang.ClassCastException: javafx.scene.control.MenuItem cannot be cast to javafx.scene.Node
at plataformavalidezpredictiva.MainController.handleAction(MainController.java:60)
... 38 more
This is the code for the handler. Once again, this works for a button I placed within the UI and doesn't work from the menu bar:
public void handleAction(ActionEvent event) throws Exception{
Node node = (Node)event.getSource();
Stage stage=(Stage) node.getScene().getWindow();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("fxml/GUIFile.fxml"));
Parent root = (Parent)fxmlLoader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
The line that seems to give me the problem is:
Node node = (Node)event.getSource();
Any ideas?
Edit: I saw the post here Unable to get Scene from MenuItem in JavaFX but that didn't work for me, because it didn't find the getScene() method for the menu bar.
Inject some node (e.g. the MenuBar, but it really can be any node in the same scene) into the controller. Call getScene() on that node and getWindow() on the Scene.
E.g.
Main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="exitfrommenu.MainController">
<top>
<MenuBar fx:id="menuBar">
<Menu text="File">
<MenuItem text="Exit" onAction="#exit"/>
</Menu>
</MenuBar>
</top>
</BorderPane>
MainController.java
package exitfrommenu;
import javafx.fxml.FXML;
import javafx.scene.control.MenuBar;
public class MainController {
#FXML
private MenuBar menuBar ;
#FXML
private void exit() {
Stage stage = (Stage) menuBar.getScene().getWindow() ;
// This exits the application, but of course you can do anything
// you like with the stage, such as showing a new scene in it:
stage.hide();
}
}
Main.java
package exitfrommenu;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("Main.fxml"));
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
I suppose it's a very simple thing but I just can't get behind it.
All I want is to show an image over an ImageView linked to fxml.
Here is my code:
package application;
import java.io.File;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
public class Main extends Application
{
#FXML
private ImageView imageView;
#Override
public void start(Stage primaryStage)
{
try
{
AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("Sample.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("Hello World");
File file = new File("src/Box13.jpg");
Image image = new Image(file.toURI().toString());
imageView = new ImageView(image);
//root.getChildren().add(imageView);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
And my fxml file
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="316.0" prefWidth="321.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.SampleController">
<children>
<ImageView fx:id="imageView" fitHeight="150.0" fitWidth="200.0" layoutX="61.0" layoutY="83.0" pickOnBounds="true" preserveRatio="true" >
</ImageView>
</children>
</AnchorPane>
There should be no problem with the file linking as it works fine when I include the outcommented line. This would be the way it's done in java only but I want to use fxml here as I am using fxml for all other components but it just doesn't work for the ImageView and I don't know why. I have also tried to create a new controller class and link the ImageView there but that neither works. Can anyone help me?
Thanks
If you want to use FXML, you should separate the controller (like you were doing with the SampleController). Then your fx:controller in your FXML should point to that.
Probably you are missing the initialize method in your controller, which is part of the Initializable interface. This method is called after the FXML is loaded, so I recommend you to set your image there.
Your SampleController class must be something like this:
public class SampleController implements Initializable {
#FXML
private ImageView imageView;
#Override
public void initialize(URL location, ResourceBundle resources) {
File file = new File("src/Box13.jpg");
Image image = new Image(file.toURI().toString());
imageView.setImage(image);
}
}
I tested here and it's working.
You don't need an initializer, unless you're dynamically loading a different image each time. I think doing as much as possible in fxml is more organized. Here is an fxml file that will do what you need.
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<AnchorPane
xmlns:fx="http://javafx.co/fxml/1"
xmlns="http://javafx.com/javafx/2.2"
fx:controller="application.SampleController"
prefHeight="316.0"
prefWidth="321.0"
>
<children>
<ImageView
fx:id="imageView"
fitHeight="150.0"
fitWidth="200.0"
layoutX="61.0"
layoutY="83.0"
pickOnBounds="true"
preserveRatio="true"
>
<image>
<Image
url="src/Box13.jpg"
backgroundLoading="true"
/>
</image>
</ImageView>
</children>
</AnchorPane>
Specifying the backgroundLoading property in the Image tag is optional, it defaults to false. It's best to set backgroundLoading true when it takes a moment or longer to load the image, that way a placeholder will be used until the image loads, and the program wont freeze while loading.
The Code part :
Image imProfile = new Image(getClass().getResourceAsStream("/img/profile128.png"));
ImageView profileImage=new ImageView(imProfile);
in a javafx maven:
#FXML
ImageView image;
#Override
public void initialize(URL url, ResourceBundle rb) {
image.setImage(new Image ("/about.jpg"));
}
Please find below example to load image using JavaFX.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class LoadImage extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Load Image");
StackPane sp = new StackPane();
Image img = new Image("javafx.jpg");
ImageView imgView = new ImageView(img);
sp.getChildren().add(imgView);
//Adding HBox to the scene
Scene scene = new Scene(sp);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Create one source folder with name Image in your project and add your image to that folder otherwise you can directly load image from external URL like following.
Image img = new Image("http://mikecann.co.uk/wp-content/uploads/2009/12/javafx_logo_color_1.jpg");
It's recommended to put the image to the resources, than you can use it like this:
imageView = new ImageView("/gui.img/img.jpg");
src/sample/images/shopp.png
Parent root =new StackPane();
ImageView ımageView=new ImageView(new Image(getClass().getResourceAsStream("images/shopp.png")));
((StackPane) root).getChildren().add(ımageView);