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);
}
}
Related
I currently have 3 classes.
ScreenController (controller class):
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.layout.AnchorPane;
import java.net.URL;
import java.util.ResourceBundle;
public class ScreenController implements Initializable
{
private AnchorPane window;
public ScreenController()
{
super();
}
public ScreenController(AnchorPane window)
{
setWindow(window);
}
public void setWindow(AnchorPane window)
{
this.window = window;
}
public void setScreen(String screen)
{
try
{
Parent root = FXMLLoader.load(getClass().getResource("/com/app/client/resources/fxml/" + screen + ".fxml"));
window.getChildren().setAll(root);
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Override
public void initialize(URL location, ResourceBundle resources)
{
}
}
LoginScreen (primary screen):
import com.app.client.java.controllers.ScreenController;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
public class LoginScreen extends ScreenController
{
#FXML
private AnchorPane loginWindow;
#FXML
private Button goButton;
public LoginScreen()
{
super();
setWindow(loginWindow);
}
#FXML
public void goButtonPressed(ActionEvent event) throws IOException
{
setScreen("Home");
System.out.println("Success.");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="loginWindow" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" opacity="0.5" prefHeight="500.0" prefWidth="850.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.app.client.java.classes.LoginScreen">
<children>
<Button fx:id="goButton" layoutX="205.0" layoutY="60.0" mnemonicParsing="false" onAction="#goButtonPressed" text="Button" />
</children>
</AnchorPane>
HomeScreen (secondary screen):
import com.app.client.java.controllers.ScreenController;
import javafx.fxml.FXML;
import javafx.scene.layout.AnchorPane;
public class HomeScreen extends ScreenController
{
#FXML
private static AnchorPane homeWindow = new AnchorPane();
public HomeScreen()
{
super (homeWindow);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="homeWindow" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.app.client.java.classes.HomeScreen">
<children>
<TextArea layoutX="200.0" layoutY="100.0" prefHeight="200.0" prefWidth="200.0" text="aksajkasjkasja" />
</children>
</AnchorPane>
I would like to be able to move from the primary screen to the secondary screen using the setScreen() function. However, I'm finding that the process doesn't complete successfully.
Another approach I've found that works is (Although it resizes the window, rather than filling the initial window with the contents of the new one):
Parent root = FXMLLoader.load(getClass().getResource("/com/app/client/resources/fxml/" + screen + ".fxml"));
Stage stage = (Stage) loginWindow.getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
However, I'd prefer to use the initial implementation due to it being more concise, readable and, theoretically, provides the exact behaviour I would like.
There are a couple issues with what you currently have:
In your LoginScreen constructor you call setWindow with the value of a yet-to-be-injected field:
public LoginScreen()
{
super();
setWindow(loginWindow);
}
No FXML fields will have been injected while the constructor of the controller is executing—meaning loginWindow is null. The reason for this self-evident: The FXMLLoader has to first construct the controller instance before it can start injecting the appropriate fields.
The order of events are: (1) Controller instantiated, (2) fields injected, (3) initialize method invoked; I believe linking any event handlers/change listeners is included in step two. What this means is any initialization that needs to happen regarding FXML fields should be done in the initialize method.
You have the same problem in your HomeScreen constructor with super(homeWindow), though there are other problems there which are addressed in the next point.
In addition to trying to access a yet-to-be-injected field in the constructor, there are two other problems with the following:
#FXML
private static AnchorPane homeWindow = new AnchorPane();
The first problem is you initialize a field that is meant to be injected. Never do this. A good rule of thumb is: If the field is annotated with #FXML then don't manually assign a value to it. The FXML field will eventually be injected which means any value you assign to it beforehand will simply be replaced. This can lead to subtle problems since any code with a reference to the previous value won't be using the object that was actually added to the scene graph.
The other problem is your field is static. Injecting static fields is not supported in JavaFX 8+. It used to be possible in older versions, from what I understand, but that behavior was never officially supported (i.e. was an implementation detail). Besides, it doesn't make sense to have something inherently instance-based (FXML+controllers) set a static field which would affect all instances.
A bonus problem: When you make homeWindow non-static you can no longer use super(homeWindow) because you can't reference it before the super constructor is invoked.
Using the two modified classes should allow your code to run:
LoginScreen.java:
public class LoginScreen extends ScreenController {
#FXML private AnchorPane loginWindow;
#FXML private Button goButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location, resources);
setWindow(loginWindow); // set window in initialize method
}
#FXML
public void goButtonPressed(ActionEvent event) throws IOException {
setScreen("Home");
System.out.println("Success.");
}
}
HomeScreen.java:
public class HomeScreen extends ScreenController {
#FXML private AnchorPane homeWindow;
#Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location, resources);
setWindow(homeWindow); // set window in initialize method
}
}
However don't use:
window.getChildren().setAll(root);
In your ScreenController#setScreen method—it causes a subtle problem. You're adding a root as a child of the window node. But when this happens, the new instance of ScreenController (associated with the new root) has its window == root. In other words, the window created with LoginScreen is now the parent of the window created with HomeScreen. Depending on how a more complex application is designed, this can lead to progressively deeper nesting of "roots".
That said, you already have another approach where you actually replace the entire Scene. The issue you're having there, as you stated, is that the Stage resizes to fit the new Scene. This can be fixed by replacing the root of the Scene, rather than the Scene itself:
window.getScene().setRoot(root);
Some potentially helpful resources:
Introduction to FXML
JavaFX FXML Tutorial (javacodegeeks.com)
JavaFX FXML (jenkov.com)
what does initialize() mean in javafx?
JavaFX : Pass parameters while instantiating controller class
How to swap screens in a javafx-application in the controller-class?
Loading new fxml in the same scene
Passing Parameters JavaFX FXML
Switch between panes in JavaFX
afterburner.fx
mvvmFX
Curated list of JavaFX-related things
You can get the main stage of a JavaFX Application during initialization. Other scene classes should have a Stage field with getter and setter and so you will be able to pass the main stage through their Controller. As for the window resize, you can fix that by adding getStage().getWidth() and getStage().getHeight() in the setScene() statement.
A small example of what I am trying to point:
public class MainClass extends Application {
#Override
public void start(Stage stage) throws Exception {
InputStream sceneStream = MainClass.class.getResourceAsStream("/fxml"+
"/newScene/main.fxml");
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(sceneStream);
Scene scene = new Scene(root);
stage.setTitle("App title");
NewScene controller = loader.getController();
controller.setMainStage(stage);
stage.setScene(scene, stage.getWidth(), stage.getHeight());
stage.show();
}
So the above function starts from MainClass where the main stage is created. Notice the part in the middle which is a bit separeted from the rest of the code, where by getting the controller of the loaded Scene I am passing the stage to it. You can pass the stage that way to all of your scenes. Also notice the part where the scene is set, where I use two more parameters extracted from the stage; the width and the height. Other than that, there are more ways to get the stage in pretty much every scene that runs on the primary stage, just by doing:
#FXML private Button aButton;
public Button getAButton(){
return aButton;
}
Stage stage = (Stage) getAButton().getScene().getWindow();
This will work in all scenes based in the primary stage and it only requires you to have a registered in the Scene Graph Node no matter the type.
I'm trying to set a JavaFx scene where a nested FlowPane can be changed during the runtime. I want to be able to new elements to the Pane, and have them rendered out.
Main
package renderable;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class Main extends Application implements EventHandler<ActionEvent{
Button button;
#FXML public FlowPane flowPane;
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(getClass().getResource("/renderable/ClientRender.fxml"));
Scene scene = new Scene(root, 1000, 720);
primaryStage.setTitle("The Game");
primaryStage.setScene(scene);
primaryStage.show();
loader.getController().updateFlowPanel();
primaryStage.show();
}
public void updateFlowPanel(){
flowPane.getChildren().add(button);
}
#Override
public void handle(ActionEvent event) {
if (event.getSource() == button)
System.out.println("The first button was pushed.");
}
}
RenderManager
public class RenderManager implements EventHandler<ActionEvent>{
cCard tableCards[];
cHand thisPlayerHand;
#FXML public FlowPane flowPane;
Button button;
public RenderManager() {
}
public void updateFlowPanel(){
flowPane.getChildren().add(button);
}
#Override
public void handle(ActionEvent event) {
if (event.getSource() == button)
System.out.println("The first button was pushed.");
}
}
ClientRender.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?package renderable?>
<?import javafx.geometry.*?>
<FlowPane id="flowPane" fx:id="flowPane" hgap="4.0" nodeOrientation="LEFT_TO_RIGHT" prefHeight="480.0" prefWidth="600.0" prefWrapLength="1400.0" style="-fx-background-color: #006600;" vgap="4.0" BorderPane.alignment="CENTER" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="renderable.Main"/>
I am unable to correctly reference the RenderManager object associated with my current root to then run it's `updateFlowPanel()' method.
How do I correctly add elements to the Pane during runtime?
The reason you are getting a null pointer exception is that the #FXML-injected field flowPane is only initialized in the controller. You are calling updateFlowPanel() on an instance of Main that is not the controller, hence flowPane is null in that instance, and consequently flowPane.getChildren() throws a null pointer exception.
Specifically: Application.launch() creates an instance of the Application class and calls start() on that instance (among other things).
Calling FXMLLoader.load(), by default, creates an instance of the class specified by the fx:controller attribute in the FXML root element. Any #FXML-injected fields are initialized in that instance, event handler methods are called on that instance, and the initialize() method is called on that instance.
Since you use the same class Main for both the Application and the controller class - which is always a mistake, you end up with two instances of Main. You call updateFlowPanel() from start(), i.e. you call it on the instance created by Application.launch(); however flowPane is only initialized in the instance created by the FXMLLoader.
You should use a separate controller class. I.e. do
package renderable;
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 {
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/renderable/ClientRender.fxml"));
Scene scene = new Scene(root, 1000, 720);
primaryStage.setTitle("The Game");
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.show();
}
}
and then define a controller class:
package renderable ;
import javafx.fxml.FXML ;
import javafx.scene.layout.FlowPane ;
import javafx.scene.control.Button ;
public class Controller {
#FXML
private FlowPane flowPane ;
public void updateFlowPanel(){
Button button = new Button("...");
flowPane.getChildren().add(button);
}
}
and update the FXML to refer to it:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?package renderable?>
<?import javafx.geometry.*?>
<FlowPane id="flowPane" fx:id="flowPane" hgap="4.0"
nodeOrientation="LEFT_TO_RIGHT" prefHeight="480.0" prefWidth="600.0"
prefWrapLength="1400.0" style="-fx-background-color: #006600;" vgap="4.0"
BorderPane.alignment="CENTER" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="renderable.Controller"/>
Now you can either just call updateFlowPanel() in the initialize() method:
package renderable ;
import javafx.fxml.FXML ;
import javafx.scene.layout.FlowPane ;
import javafx.scene.control.Button ;
public class Controller {
#FXML
private FlowPane flowPane ;
public void initialize() {
updateFlowPanel();
}
public void updateFlowPanel(){
Button button = new Button("...");
flowPane.getChildren().add(button);
}
}
or you can call it on the correct controller instance from your start() method:
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/renderable/ClientRender.fxml"));
Parent root = loader.load();
Controller controller = loader.getController();
controller.updateFlowPanel();
Scene scene = new Scene(root, 1000, 720);
primaryStage.setTitle("The Game");
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.show();
}
Edit:
The update you made to your question actually prevents the code from compiling. If you fix the compile error by replacing
loader.getController().updateFlowPanel();
with
loader.<Main>getController().updateFlowPanel();
then the (entirely different) issue you have created is that you create an instance of FXMLLoader:
FXMLLoader loader = new FXMLLoader();
but then instead of using that FXMLLoader instance to load the FXML, you call the static method load(URL):
Parent root = loader.load(getClass().getResource("/renderable/ClientRender.fxml"));
Since you are calling the static method, you never call load() on the FXMLLoader instance, and so its controller property is never initialized. Consequently, loader.<Main>getController() is null, and loader.<Main>getController().updateFlowPanel() throws a null pointer exception (entirely different to the null pointer exception you had in the previous version of your question; it is not even thrown from the same method).
If you want to reference the controller, use the code in the second version of the start() method that I posted above.
I want to create new label in another fxml when a button is clicked. I used the following code but the following exception is thrown
java.lang.RuntimeException:
java.lang.reflect.InvocationTargetException
The code:
Controller.java
public class Controller {
public AnchorPane anchorPane;
public void OpenSecond() throws Exception{
Stage primaryStage = new Stage();
Parent root = FXMLLoader.load(getClass().getResource("sample1.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public void AddLabe(){
Label label = new Label("Label");
anchorPane.getChildren().add(label);
}
}
second.java
public class Second {
public void AddLiabel()
{
Controller controller = new Controller();
controller.AddLabe();
}
}
I am using IntelliJ IDEA and Scene builder
You should be getting this exception because Java couldn't find the specified file or it is empty. Search for
Caused by: javafx.fxml.LoadException:
in the exception.
Adding the "sample1.fxml" and initializing it with a pane should fix the problem.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="275.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" />
Most probably you miss annotation for anchorPane and JavaFX didn't initialize it. Try next:
#FXML
public AnchorPane anchorPane;
and make sure anchorPane is listed in your FXML file.
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.
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