I'm trying to load my fxml file, which is fine and loaded (I have tried it with my main class). But, when I tried to set the content in the Controller, an error occurred saying:
incompatible types: java.lang.Object cannot be converted to javafx.scene.Node
at addNewCategorie.getDialogPane().setContent(fxmlLoader.load());
My Controller Class:
#FXML
private BorderPane mainBorder;
#FXML
public void handle_the_addition_of_newCategorie(){
Dialog<ButtonType> addNewCategorie = new Dialog<>();
addNewCategorie.setTitle("Add Categorie");
addNewCategorie.initOwner(mainBorder.getScene().getWindow());
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("/AddNewCategorie.fxml"));
try{
addNewCategorie.getDialogPane().setContent(fxmlLoader.load());
}catch (IOException E){
System.out.println("IOEXception : "+E.getMessage());
}
addNewCategorie.getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
addNewCategorie.show();
}
My fxml file:
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<BorderPane fx:id="mainBorder" fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" style="-fx-background-color:#485460">
<center>
<HBox spacing="20" alignment="CENTER">
<Button text="Add new Categorie" style="-fx-background-color:#2ecc71; -fx-text-fill:white" onMouseClicked="#handle_the_addition_of_newCategorie"/>
</HBox>
</center>
</BorderPane>
had to change this:
addNewCategorie.getDialogPane().setContent(fxmlLoader.load());
to:
addNewCategorie.getDialogPane().setContent((Node)fxmlLoader.load());
and:
fxmlLoader.setLocation(getClass().getResource("/AddNewCategorie.fxml"));
To:
fxmlLoader.setLocation(getClass().getClassLoader().getResource("/AddNewCategorie.fxml"));
Related
I was trying to make my first application on JavaFX but this frustrated me so much! These elements of the application are perfect in SceneBuilder, but now it's just misaligned!
I think it's because of this error when I run the app:
WARNING: Loading FXML document with JavaFX API of version 11.0.1 by JavaFX runtime of version 8.0.231
I have tried to change the AnchorPane attributes to:
<AnchorPane prefHeight="129.0" prefWidth="205.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"">
...
</AnchorPane>
but it just fixes the warning and not the misalignment.
Here is my full code:
Main.java
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.stage.Stage;
import javafx.scene.Scene;
//import javafx.scene.layout.BorderPane;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
//BorderPane root = new BorderPane();
Parent root = FXMLLoader.load(getClass().getResource("Root.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Root.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="129.0" prefWidth="205.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextField layoutX="28.0" layoutY="23.0" />
<Button layoutX="77.0" layoutY="65.0" mnemonicParsing="false" text="Button" />
</children>
</AnchorPane>
As #Slaw mentioned that AnchorPane is not a responsive layout. You may consider using VBox with CENTER alignment as you have two nodes positioned with vertically.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Pos?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?>
<VBox prefHeight="129.0" alignment="CENTER" prefWidth="205.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextField fx:id="INPUT_FIELD" />
<Button fx:id="SUBMIT" mnemonicParsing="false" text="Button" />
</children>
</VBox>
Generally, AnchorPane can be set as a parent layout and you can put VBox on it and controls(Button, TextField, etc) can be added on the VBox.
I think it's because of this error when I run the app:
WARNING: Loading FXML document with JavaFX API of version 11.0.1 by JavaFX runtime of version 8.0.231
No, it's just a warning! You can find a huge discussion over here.
I have a controller for an fxml file. The controller has a field public BorderPane mainBorderPane; which is supposed to be filled with the Border pane of the same fx:id found in the fxml file. When I try to access it from an inner class it gives a NullPointerExcetion
The clearBorderPaneCenter(); and the clearBorderPaneRight work just fine but when I run the cashSceneController.show() it crashes on the line mainBorderPane.setRight(rightLayout);
fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="mainBorderPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Program.gui.MainSceneController">
<top>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</top>
<left>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</left>
<center>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</center>
<right>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</right>
<bottom>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</bottom>
</BorderPane>
Simplified version of controller:
public class MainSceneController {
MainSceneController.CashSceneController cashSceneController = new MainSceneController.CashSceneController();
public BorderPane mainBorderPane;
public void switchLayout(byte ID){
//todo Make this work switchScene()
clearBorderPaneCenter();
clearBorderPaneRight();
cashSceneController.show();
}
public void clearBorderPaneRight(){
try {
mainBorderPane.setRight(null);
OutputHelper.log("cleared right of mainBorderPane");
} catch (Exception e){
OutputHelper.log("clearing right of mainBorderPane not required - already cleared");
}
}
public void clearBorderPaneCenter(){
try {
mainBorderPane.setCenter(null);
OutputHelper.log("cleared centre of mainBorderPane");
} catch (Exception e){
OutputHelper.log("clearing centre of mainBorderPane not required - already cleared");
}
}
public class CashSceneController{
VBox rightLayout;
public void show() {
setVBox();
mainBorderPane.setRight(rightLayout);
}
public void setVBox(){
rightLayout = new VBox();
//......
}
}
}
This is how the fxml file is loaded
SceneController = new MainSceneController(new Scene(FXMLLoader.load(getClass().getResource("gui/MainScreen.fxml"))));
I hope that I explained my problem well enough. I'm new to stack overflow and have no idea of what is a good question
Edit: it appears that the problem is caused by the mainBorderPane not being assigned at all. The clearBorderPaneCenter and clearBorderPaneRight seem to not crash cause they are caught by the try catch. Any ideas why the mainBorderPane might not be getting assigned correctly?
You are missing the fxml annotation. It is required for the FXMLLoader to inject the BorderPane into the code
#FXML
public BorderPane mainBorderPane;
I am a beginner and I am trying to build a simple dictionary application.
I have a controller class which has a button to open a new dialog to input the various details.
The dialog is controlled by a separate controller and this is where I am experiencing problems, my FXML elements are given the value of null, hence I get a nullpointerexception when I run the code. I've annotated the FXML vaiables with #FXML and have checked that the fx:id in the fxml file matches that of the java file.
Here is the Controller.java code:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.BorderPane;
import javafx.scene.control.Dialog;
import java.io.IOException;
import java.util.Optional;
public class Controller {
#FXML
private BorderPane mainBorderPane;
#FXML
private DialogController controller = new DialogController();
#FXML
public void initialize(){
}
#FXML
public void newItemDialog(){
Dialog <ButtonType> dialog = new Dialog<>();
dialog.initOwner(mainBorderPane.getScene().getWindow());
dialog.setTitle("Insert Word");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("newDialog.fxml"));
try{
dialog.getDialogPane().setContent(fxmlLoader.load());
}catch(IOException e) {
e.printStackTrace();
return;
}
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
Optional<ButtonType> result = dialog.showAndWait();
if(result.isPresent() && result.get() == ButtonType.OK){
boolean results = controller.processResults();
}else{
System.out.println("Cancelled");
return;
}
}
}
Here is the DialogController.java code:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import sample.control.Data;
import java.io.IOException;
import java.util.Optional;
public class DialogController {
#FXML
private TextField nameField;
#FXML
private TextField descriptionField;
#FXML
private TextField typeField;
#FXML
private TextField sentenceField;
#FXML
public boolean processResults() {
String name = nameField.getText();
String description = descriptionField.getText();
String type = typeField.getText();
String sentence = sentenceField.getText();
return Data.getInstance().addWord(name,type,description,sentence);
}
}
Here is the sample.fxml code:
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.ListView?>
<?import java.lang.String?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.VBox?>
<BorderPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml"
fx:id ="mainBorderPane">
<top>
<MenuBar>
<Menu fx:id="fileButton" text="File">
<MenuItem fx:id="newButton" onAction="#newItemDialog" text="New"/>
<MenuItem fx:id="updateButton" text="Update"/>
<MenuItem fx:id="deleteButton" text="Delete"/>
<MenuItem fx:id="saveButton" text="Save"/>
</Menu>
<Menu fx:id="viewButton" text="View">
<MenuItem text="Dark Mode"/>
</Menu>
</MenuBar>
</top>
<left>
<ListView fx:id="wordListView" BorderPane.alignment="TOP_LEFT" prefHeight="Infinity" prefWidth="250">
</ListView>
</left>
<center>
<VBox>
<TextArea fx:id = "wordDetails" prefWidth="Infinity" prefHeight="400">
</TextArea>
<TextArea prefWidth="Infinity" prefHeight="200">
</TextArea>
</VBox>
</center>
</BorderPane>
Here is the newDialog.fxml code:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.control.DialogPane?>
<DialogPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="sample.DialogController"
prefHeight="400.0" prefWidth="600.0">
<headerText>
Enter A Word
</headerText>
<content>
<VBox>
<TextField fx:id="nameField" promptText="Enter the word"/>
<TextField fx:id="typeField" promptText="Enter the type"/>
<TextField fx:id="descriptionField" promptText="Enter a description"/>
<TextField fx:id="sentenceField" promptText="Enter a sentence"/>
</VBox>
</content>
Thanks in advance!
The #FXML annotation indicates a field that should be initialized by the FXMLLoader to reference objects created corresponding to elements in an FXML file when the FXML file is loaded. Consequently:
It only makes sense to annotate fields #FXML if they correspond to elements in the FXML file
It never makes sense to initialize a field if it is annotated #FXML (because the FXMLLoader is supposed to initialize it)
Your DialogController field
#FXML
private DialogController controller = new DialogController();
doesn't make sense for both of these reasons: there is no DialogController element in the sample.fxml, and if there were, there would be no point in initializing the field.
A controller is a specific object associated with the UI loaded from an FXML file. The association is made by the FXMLLoader when it loads the FXML file. If you load the FXML file multiple times (as you appear to do here, since you are loading newDialog.fxml in an event handler), then (of course) you get new instances of all the elements in the FXML each time, and consequently a new instance of the controller class each time.
The object you create with
#FXML private DialogController controller = new DialogController();
is not the controller for any UI loaded any of the times you load newDialog.fxml; it is just another object of the same class. It is not clear whether you expect this field to somehow reference the controller created the first time the user chooses "New" from the menu, or the one created the second time they choose that menu item, etc. Or, of course, how you would expect it to refer to any of those controllers when you are initializing it before you ever load newDialog.fxml.
You get the controller from the FXMLLoader after loading the FXML. So you just need:
public class Controller {
#FXML
private BorderPane mainBorderPane;
#FXML
public void initialize(){
}
#FXML
public void newItemDialog(){
Dialog <ButtonType> dialog = new Dialog<>();
dialog.initOwner(mainBorderPane.getScene().getWindow());
dialog.setTitle("Insert Word");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("newDialog.fxml"));
try{
dialog.getDialogPane().setContent(fxmlLoader.load());
}catch(IOException e) {
e.printStackTrace();
return;
}
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
Optional<ButtonType> result = dialog.showAndWait();
DialogController controller = fxmlLoader.getController();
if(result.isPresent() && result.get() == ButtonType.OK){
boolean results = controller.processResults();
}else{
System.out.println("Cancelled");
return;
}
}
}
I'm trying to work with JavaFX and FXML files, but something goes wrong when I inject the MenuBar in the controller, compiler gives me a NullPointerException. I tried with buttons and textfields and it works.
This is mycode:
FXML file:`
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox fx:controller="it.fedgiac.projectmanager.controller.ControllerMain" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<MenuBar fx:id="menubar_mainmenu" />
</children>
</VBox>`
And this is my Controller
public class ControllerMain {
#FXML
public MenuBar menubar_mainmenu;
public void generateView(Stage stage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("main_layout.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Projects Manager");
menubar_mainmenu.getMenus().add(new Menu("File"));
stage.setScene(scene);
stage.show();
}
}
After debugging I saw that the variable menubar_mainmenu is null
This is the error:
Thank you in advance for your help.
Make your FXML Controller implement Initializable. You will then be prompted to implement the method initialize(URL url, ResourceBundle resourceBundle). In this method, you can be sure that the menubar_mainmenuis initialized. You can move your existing code into that method.
public void initialize(URL url, ResourceBundle resourceBundle){
menubar_mainmenu.getMenus().add(new Menu("File"));
}
I have a program created with an FXML file (made in SceneBuilder) that has four SubScenes in it:
#FXML
public SubScene p1sub;
#FXML
public SubScene p2sub;
#FXML
public SubScene p3sub;
#FXML
public SubScene p4sub;
Each of these subscenes is nearly identical to the rest.
I can get the root node (which contains these) to show up just fine, but when I try to add the SubScenes, they don't show up.
//This is the code I use to initialize one of the four.
Parent root2a = null;
try {
FXMLLoader loader2 = new FXMLLoader(getClass().getResource(
"PlayerConfigurationSubScreen.fxml"));
root2a = (Parent) loader2.load();
} catch (Exception e) {
/*code*/
}
/*code*/
if (root2a != null) {
System.out.println("root2 isn't null");
p1sub = new SubScene(root2a, 149, 260);
}
/*code*/
stage.show();
Any idea how to make them show up? I'm new at JavaFX.
Set the subscene dimensions in fxml and instead of "new" just add the parent to the subscene.
....
p1sub.setRoot(root2a);
....
I think you are approaching the problem the wrong way. From what I understand from your code, you want to load a subscene and then assign it to one of your predefined "slots".
This however will not work, as the pre-defined slots has nothing to do with what is actually rendered. Everything that is drawn in a window has to be assigned as child of a container of some kind.
I've made an example here that reproduces the problem you are facing:
public class ReplaceTest extends Application {
#FXML Button button;
#FXML Label oldLabel;
#Override
public void start(Stage primaryStage) throws IOException{
Parent root = FXMLLoader.load( getClass().getResource("ReplaceTest.fxml") );
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private static int i = 0;
#FXML protected void simpleClick(ActionEvent e){
Label newLabel = new Label("Hello! " + i++);
oldLabel = newLabel;
System.out.println("Nothing happens...");
}
}
And the FXML file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="200.0" spacing="10.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="replaceTest.ReplaceTest">
<children>
<Label fx:id="oldLabel" text="TEXT TO BE REPLACED" />
<Button fx:id="button" onAction="#simpleClick" text="Replace label" />
</children>
<padding>
<Insets top="10.0" />
</padding>
</VBox>
If you try this example, you will see that overwriting oldLabel does not affect the rendering window. Instead, you can try to create areas to which you add your new subscenes as children. This will update the rendering window and will (hopefully) produce the behavior you desire. Again, I've made an example you can consult:
public class ReplaceTest extends Application {
#FXML Button button;
#FXML VBox wrappingBox;
#Override
public void start(Stage primaryStage) throws IOException{
Parent root = FXMLLoader.load( getClass().getResource("ReplaceTest.fxml") );
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private static int i = 0;
#FXML protected void simpleClick(ActionEvent e){
Label newLabel = new Label("Hello! " + i++);
wrappingBox.getChildren().clear();
wrappingBox.getChildren().add(newLabel);
System.out.println("Someting happens!");
}
}
And the FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="200.0" spacing="10.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="replaceTest.ReplaceTest">
<children>
<VBox fx:id="wrappingBox" alignment="TOP_CENTER">
<children>
<Label text="TEXT TO BE REPLACED" />
</children>
</VBox>
<Button fx:id="button" onAction="#simpleClick" text="Replace label" />
</children>
<padding>
<Insets top="10.0" />
</padding>
</VBox>