So I have to build this JavaFX application really fast, my code compiles yet the GUI doesn't start and I get exceptions. The problem starts as soon as the FileChooser code is implemented.
public class Main extends Application {
#FXML // fx:id="openButton"
private Button openButton; // Value injected by FXMLLoader
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("Plot.fxml"));
openButton.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent arg0) {
FileChooser fileChooser = new FileChooser();
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt");
fileChooser.getExtensionFilters().add(extFilter);
File file = fileChooser.showOpenDialog(primaryStage);
System.out.println(file);
}
});
primaryStage.setTitle("Plotter");
primaryStage.setScene(new Scene(root, 1024 , 768));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The FXML file is as such:
<BorderPane prefHeight="400.0" prefWidth="723.0" xmlns="http://javafx.com/javafx/null" xmlns:fx="http://javafx.com/fxml/1">
<top>
<HBox alignment="TOP_CENTER" prefHeight="50.0" spacing="10.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="openButton" mnemonicParsing="false" prefHeight="31.0" prefWidth="150.0" text="Open Dataset" />
<Button mnemonicParsing="false" prefHeight="31.0" prefWidth="150.0" text="Button" />
<Button mnemonicParsing="false" prefHeight="31.0" prefWidth="150.0" text="Button" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<BorderPane.margin>
<Insets />
</BorderPane.margin>
</HBox>
</top>
</BorderPane>
I am completely novice to JavaFX. Any tips is appreciated. P.S. I am using the Gluon scene builder.
Thanks.
The Exceptions:
Exception in Application start method Exception in thread "main"
java.lang.RuntimeException: Exception in Application start method at
com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at
com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:745) Caused by:
java.lang.NullPointerException at sample.Main.start(Main.java:29) at
com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at
com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at
com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method) at
com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at
com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at
com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
... 1 more
Process finished with exit code 1
Answer is to separate the Controller and Application class, so that you don't end up with two instances of the Application class. Otherwise one instance of the Application class will not have some members initialized and will end up throwing null pointer exceptions.
package plot;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.stage.FileChooser;
import java.io.File;
public class Controller {
#FXML // fx:id="openButton"
private Button openButton; // Value injected by FXMLLoader
#FXML
public void open(ActionEvent e) {
FileChooser fileChooser = new FileChooser();
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt");
fileChooser.getExtensionFilters().add(extFilter);
File file = fileChooser.showOpenDialog(openButton.getScene().getWindow());
System.out.println(file);
}
}
package plot;
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 stage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("Plot.fxml"));
Parent root = loader.load();
stage.setTitle("Plotter");
stage.setScene(new Scene(root, 1024 , 768));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<BorderPane prefHeight="400.0" prefWidth="723.0" xmlns="http://javafx.com/javafx/null"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="plot.Controller"
>
<top>
<HBox alignment="TOP_CENTER" prefHeight="50.0" spacing="10.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="openButton" mnemonicParsing="false" prefHeight="31.0" prefWidth="150.0" text="Open Dataset" onAction="#open"/>
<Button mnemonicParsing="false" prefHeight="31.0" prefWidth="150.0" text="Button"/>
<Button mnemonicParsing="false" prefHeight="31.0" prefWidth="150.0" text="Button"/>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<BorderPane.margin>
<Insets/>
</BorderPane.margin>
</HBox>
</top>
</BorderPane>
See related (I advise the first link be studied to understand why this solution works).
Javafx - Can application class be the controller class
What is a NullPointerException, and how do I fix it?
Related
I'm working on a desktop application using javaFX, I'm using scene builder version 11 to create my interface that contains TextFields and ChoiceBox, my inputs are supposed to be set in Arabic. The problem is when I retrieve the text from the TextFiled or the ChoiceBox and print it in the console it shows characters like that "بننلنلن" and it also generates a problem to store the inputs in database, this is the SQLException:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'بننلنلن,نبلنبنلب,2021-06-30,أمر جزائي,تم التبليغ
When I tried another project without scene builder I got the Arabic outputs correctly, could scene bulider be the problem's origin?
here is my fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane id="AnchorIns" prefHeight="529.0" prefWidth="523.0" stylesheets="#newinsc.css" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="newInsc.NewInscController">
<children>
<VBox fx:id="boxContainer" layoutX="139.0" layoutY="99.0" prefHeight="273.0" prefWidth="245.0">
<children>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<TextField fx:id="firstNameTxtField" alignment="CENTER_RIGHT" />
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="71.0" stylesheets="#newinsc.css" text="الاسم" />
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<TextField fx:id="lastNameTxtField" alignment="CENTER_RIGHT" />
<Label prefHeight="17.0" prefWidth="71.0" text="اللقب" />
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<ChoiceBox fx:id="docTypeChoice" prefWidth="150.0" />
<Label prefHeight="17.0" prefWidth="71.0" text="نوع التبليغ" />
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<DatePicker fx:id="dateField" prefHeight="25.0" prefWidth="149.0" />
<Label prefHeight="17.0" prefWidth="71.0" text="التاريخ" />
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<ChoiceBox fx:id="tablighCase" prefWidth="150.0" />
<Label prefHeight="17.0" prefWidth="71.0" text="حالة التبليغ" />
</children>
</HBox>
<HBox alignment="CENTER" onMouseClicked="#cancelBtnClicked" prefHeight="46.0" prefWidth="245.0">
<children>
<Button fx:id="cancleBtn" mnemonicParsing="false" onMouseClicked="#cancelBtnClicked" text="الغاء">
<HBox.margin>
<Insets right="16.0" />
</HBox.margin>
</Button>
<Button fx:id="saveInscBtn" mnemonicParsing="false" onMouseClicked="#registerBtnClicked" text="تسجيل" />
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
and this here is my controller file:
package newInsc;
import DB.dbConnection;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDate;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* FXML Controller class
*
* #author asus
*/
public class NewInscController implements Initializable {
#FXML
private ChoiceBox<String> docTypeChoice;
#FXML
private ChoiceBox<String> tablighCase;
#FXML
private DatePicker dateField;
#FXML
private Button saveInscBtn;
#FXML
private TextField firstNameTxtField;
#FXML
private TextField lastNameTxtField;
#FXML
private Button cancleBtn;
private Connection c;
private Statement s;
#FXML
private VBox boxContainer;
#Override
public void initialize(URL url, ResourceBundle rb) {
docTypeChoice.getItems().add("أمر جزائي");
docTypeChoice.getItems().add("حكم جزائي" );
docTypeChoice.getItems().add("تكليف بالحضور" );
docTypeChoice.getItems().add("قرار جزائي" );
tablighCase.getItems().add("تم التبليغ");
tablighCase.getItems().add("ترك اشعار");
tablighCase.getItems().add("عدم التمكن من التبليغ");
}
#FXML
private void cancelBtnClicked(MouseEvent event) {
Stage s = (Stage) cancleBtn.getScene().getWindow();
}
#FXML
private void registerBtnClicked(MouseEvent event) {
try {
String query;
String fname = firstNameTxtField.getText();
String lname = lastNameTxtField.getText();
LocalDate date = dateField.getValue();
String docType = docTypeChoice.getValue();
String state = tablighCase.getValue();
query = "insert into infotable values " + fname + "," + lname + "," + date+ ","+ docType+"," +state ;
dbConnection dbc = new dbConnection();
s = dbc.createConnection().createStatement();
s.execute(query);
s.close();
} catch (SQLException ex) {
Logger.getLogger(NewInscController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I could find a solution, before I run the program I first compile it with F9 key then I run it with a key combination SHIFT + F6
I'm having trouble running JavaFX Program which runs on Java version 1.8. I noticed that even if I can run this program on Intellij IDE, it throws
java.lang.reflect.InvocationTargetException
error when I try running it in command line. There are no errors when I use "javac Main.java" but it throws the error after I compile it then type "java Main.java"
Here are the files
src folder
controller folder
Controller.java
model folder
Database.java
view folder
loginview.fxml
registerview.fxml
mainmenu.fxml
Main.java
Main.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import model.Database;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("view/mainmenu.fxml"));
primaryStage.setTitle("Test Program");
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.show();
}
public static void main(String[] args) {
Database db = new Database();
db.testmethod();
launch(args);
}
}
Controller.java
package controller;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Controller {
public void exitProgram() {
System.exit(0);
}
public void openRegister(ActionEvent event) {
Parent root;
try {
root = FXMLLoader.load(getClass().getClassLoader().getResource("view/registerview.fxml"));
javafx.stage.Stage stage = new Stage();
stage.setTitle("Register User");
stage.setScene(new Scene(root, 600, 600));
stage.setResizable(false);
stage.show();
close(event);
} catch (IOException e) {
e.printStackTrace();
}
}
public void openLogin(ActionEvent event) {
Parent root;
try {
root = FXMLLoader.load(getClass().getClassLoader().getResource("view/loginview.fxml"));
javafx.stage.Stage stage = new Stage();
stage.setTitle("Login User");
stage.setScene(new Scene(root, 600, 600));
stage.setResizable(false);
stage.show();
close(event);
} catch (IOException e) {
e.printStackTrace();
}
}
public void close(ActionEvent event) {
((Node) (event.getSource())).getScene().getWindow().hide();
}
}
Database.java
package model;
public class Database {
public void testmethod(){
System.out.println("TEST METHOD");
}
}
loginview.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.Controller">
<children>
<Label layoutX="134.0" layoutY="145.0" prefHeight="165.0" prefWidth="332.0" text="LOGIN" />
</children>
</Pane>
mainmenu.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.Controller">
<children>
<Button fx:id="buttonReg" layoutX="32.0" layoutY="60.0" mnemonicParsing="false" onAction="#openRegister" prefHeight="104.0" prefWidth="521.0" text="OPEN REGISTER" />
<Button fx:id="buttonLogin" layoutX="32.0" layoutY="211.0" mnemonicParsing="false" onAction="#openLogin" prefHeight="104.0" prefWidth="521.0" text="OPEN LOGIN" />
<Button fx:id="buttonExit" layoutX="32.0" layoutY="356.0" mnemonicParsing="false" onAction="#exitProgram" prefHeight="104.0" prefWidth="521.0" text="EXIT" />
</children>
</Pane>
registerview.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.Controller">
<children>
<Label layoutX="130.0" layoutY="145.0" text="REGISTER" />
</children>
</Pane>
The error in command line
TEST METHOD
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$1(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:748)
Caused by: javafx.fxml.LoadException:
/C:/Users/Bryan/Desktop/TESTRUN/src/view/mainmenu.fxml:6
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:922)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at Main.start(Main.java:13)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$3(WinApplication.java:177)
... 1 more
Caused by: java.lang.ClassNotFoundException: controller.Controller
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:920)
... 22 more
Exception running application Main
I noticed that Database runs before throwing the Error. I don't understand what's the cause of this error
on Main.java,
add
import controller.Controller
Instead of having buttons like "Buttons" try to put them with the class
"JFXButton"
You have this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.Controller">
<Button fx:id="buttonReg" layoutX="32.0" layoutY="60.0" mnemonicParsing="false" onAction="#openRegister" prefHeight="104.0" prefWidth="521.0" text="OPEN REGISTER" />
<Button fx:id="buttonLogin" layoutX="32.0" layoutY="211.0" mnemonicParsing="false" onAction="#openLogin" prefHeight="104.0" prefWidth="521.0" text="OPEN LOGIN" />
<Button fx:id="buttonExit" layoutX="32.0" layoutY="356.0" mnemonicParsing="false" onAction="#exitProgram" prefHeight="104.0" prefWidth="521.0" text="EXIT" />
</Pane>
Try this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.Controller">
<JFXButton fx:id="buttonReg" layoutX="32.0" layoutY="60.0" mnemonicParsing="false" onAction="#openRegister" prefHeight="104.0" prefWidth="521.0" text="OPEN REGISTER" />
<JFXButton fx:id="buttonLogin" layoutX="32.0" layoutY="211.0" mnemonicParsing="false" onAction="#openLogin" prefHeight="104.0" prefWidth="521.0" text="OPEN LOGIN" />
<JFXButton fx:id="buttonExit" layoutX="32.0" layoutY="356.0" mnemonicParsing="false" onAction="#exitProgram" prefHeight="104.0" prefWidth="521.0" text="EXIT" />
</Pane>
The InvocationTargetException is occurring because the call to method getResource() – in method openRegister() of class Controller – is returning null. You can check this by simply printing out the value returned by method getResource(), for example
System.out.println(getClass().getClassLoader().getResource("view/registerview.fxml"));
It is returning null because method getResource() builds an absolute path to the file registerview.fxml and then checks to see whether such a file exists. The absolute path that method getResources() builds is not the actual path to the file. Hence you need to change the method argument, i.e. "view/registerview.fxml"
I'm guessing that the below solution is not the only solution, but it worked for me.
In order to prevent getting the InvocationTargetException I did the following.
I put class Main in a package which I named jfxtests.
(It is not clear to me, from your question, whether Main is in a package or not.)
I made the controller folder and the view folder sub-packages of jfxtests.
I call method getClass().getResource() and not getClass().getClassLoader().getResource().
In class Controller, I changed the argument that I pass to method getResource().
The only change I made was to class Controller. Here it is with my changes:
package jfxtests.controller; // changed package
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Controller {
public void exitProgram() {
System.exit(0);
}
public void openRegister(ActionEvent event) {
Parent root = null;
try {
root = FXMLLoader.load(getClass().getResource("/jfxtests/view/registerview.fxml")); // changed this line
javafx.stage.Stage stage = new Stage();
stage.setTitle("Register User");
stage.setScene(new Scene(root, 600, 600));
stage.setResizable(false);
stage.show();
close(event);
} catch (IOException e) {
e.printStackTrace();
}
}
public void openLogin(ActionEvent event) {
Parent root;
try {
root = FXMLLoader.load(getClass().getResource("/jfxtests/view/loginview.fxml")); // changed this line
javafx.stage.Stage stage = new Stage();
stage.setTitle("Login User");
stage.setScene(new Scene(root, 600, 600));
stage.setResizable(false);
stage.show();
close(event);
} catch (IOException e) {
e.printStackTrace();
}
}
public void close(ActionEvent event) {
((Node) (event.getSource())).getScene().getWindow().hide();
}
}
Note that since I changed the package for class Controller, I also had to change the FXML files.
fx:controller="jfxtests.controller.Controller"
I have an issue since I do how know, how to add new components to fx:root container child.
This is what I have at the moment.
Root element called PopupContainer
<fx:root type="StackPane" alignment="CENTER" xmlns:fx="http://javafx.com/fxml"
styleClass="popup">
<VBox alignment="CENTER">
<HBox alignment="CENTER">
<VBox fx:id="content" alignment="CENTER" spacing="5" styleClass="whiteBackground, blackborder"
fillWidth="false" StackPane.alignment="CENTER">
<!-- this is where I would like to add components -->
</VBox>
</HBox>
</VBox>
</fx:root>
I have controller for it as well.
Now, I would like to use it like this in some other fxml:
<PopupContainer xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.bank.editbank.EditBankPresenter"
styleClass="popup"
fx:id="container">
<!-- those components should go to VBOX up there -->
<ViewTitle label="%editBankUC"/>
<Button fx:id="someButton" text="Click me"/>
</PopupContainer>
Of course, when I add components they go directly under StackPane since it is root of the layout. I tried to override getChildren() method to return VBox children but I got children cycle detected. I do not want to add them programatically since it is more then 300 such cases in application but I can add new tag (instead of for example something else). Thanks!
Answering my own question because I think someone else would like to know this too.
So, as I already had before, this is PopupContainer.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<fx:root type="StackPane" alignment="CENTER" xmlns:fx="http://javafx.com/fxml"
styleClass="popup">
<VBox fx:id="child1" alignment="CENTER">
<HBox alignment="CENTER">
<VBox fx:id="content" alignment="CENTER" spacing="5" styleClass="whiteBackground, blackborder"
fillWidth="false" StackPane.alignment="CENTER">
<padding>
<Insets topRightBottomLeft="10.0" />
</padding>
</VBox>
</HBox>
</VBox>
</fx:root>
And controller PopupContainer.java:
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import java.io.IOException;
public class PopupContainer extends StackPane {
//refference to VBox from layout
#FXML private VBox content;
public PopupContainer() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("PopupContainer.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
//note this getter, this is the key that allow you to add childred to child of this component
public ObservableList<Node> getItems() {
return content.getChildren();
}
}
And at the end usage goes like this:
<PopupContainer xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.bank.editbank.EditBankPresenter"
styleClass="popup"
fx:id="container"
>
<!-- this is what was acceptable to do in question so instead of children I am using items (setter in PopupContainer.java) -->
<items>
<ViewTitle label="%editBankUC"/>
<HBox VBox.vgrow="ALWAYS">
<Pane minWidth="20"/>
<VBox alignment="CENTER" spacing="5">
<HorizontalTextInput fx:id="name" label="%nameUC" alignment="CENTER_RIGHT" />
<HorizontalTextInput fx:id="bic" label="%bicUC" alignment="CENTER_RIGHT" />
<AddressInput fx:id="address" />
<HorizontalCheckboxInput fx:id="active" label="%activeUC" />
</VBox>
<Pane minWidth="20"/>
</HBox>
<HBox alignment="CENTER" spacing="5">
<JFXButton fx:id="close" onAction="#closeView" text="%closeUC" />
<JFXButton fx:id="edit" onAction="#editClicked" />
<padding>
<Insets top="10.0" bottom="10.0" />
</padding>
</HBox>
</items>
</PopupContainer>
I hope it is clear, how to add it. I did not find nothing familiar to this elsewhere but looking at the source of BorderPane can give you a hint how to do it. Cheers
I created a circuit using Arduino and a couple of components and also a small test application in JavaFX (code shown). The issue is I can't get
COM Ports (using Windows 10) displayed in the combobox however I can see them in the output console (Arduino on COM5). When I run code inspection
in intellij i get
"Problem synopsis - Unchecked call to 'addListener(ChangeListener? super T>)' as a member of raw type 'javafx.beans.value.ObservableValue' (at line 92)"
which seems useful somehow. I thought it meant that the listener is not listening anymore but I honestly don't know.
Code for fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="538.0" prefWidth="734.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="labrat.Controller">
<top>
<VBox prefHeight="148.0" prefWidth="723.0" style="-fx-background-color: #1f3641;" BorderPane.alignment="CENTER">
<children>
<HBox prefHeight="25.0" prefWidth="723.0" style="-fx-background-color: #d2d4df;">
<children>
<Label text="LabRat Version R" textFill="#5b5b5b">
<font>
<Font size="14.0" />
</font>
<HBox.margin>
<Insets bottom="5.0" left="3.0" right="3.0" top="3.0" />
</HBox.margin>
</Label>
</children>
</HBox>
<HBox>
<children>
<Button fx:id="changeText" mnemonicParsing="false" onAction="#setChangeText" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #ffffff;" text="Change text" textFill="#4a4a4a">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<font>
<Font size="16.0" />
</font>
</Button>
<Label fx:id="dynamicText" text="Default Text" textFill="WHITE">
<font>
<Font size="24.0" />
</font>
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Label>
</children>
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</HBox>
<HBox layoutX="10.0" layoutY="10.0">
<children>
<Button fx:id="addElement" mnemonicParsing="false" onAction="#setAddElement" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #ffffff;" text="Add element" textFill="#4a4a4a">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<font>
<Font size="16.0" />
</font>
</Button>
<TextField fx:id="typeToAdd" prefHeight="25.0" prefWidth="231.0" promptText="type to add to combobox">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</TextField>
<ComboBox fx:id="element" prefHeight="25.0" prefWidth="238.0" promptText="select element" style="-fx-background-color: #ffcc99;">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</ComboBox>
</children>
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</HBox>
</children>
</VBox>
</top>
<center>
<VBox prefHeight="200.0" prefWidth="100.0" style="-fx-background-color: #1f3641;" BorderPane.alignment="CENTER">
<children>
<HBox VBox.vgrow="ALWAYS">
<children>
<ImageView fx:id="imgVw" fitHeight="319.0" fitWidth="421.0" pickOnBounds="true" preserveRatio="true" />
<VBox prefHeight="200.0" prefWidth="100.0" style="-fx-background-color: #cc0000;" HBox.hgrow="ALWAYS">
<children>
<Label fx:id="labelValue" text="Label Value" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<VBox.margin>
<Insets bottom="20.0" />
</VBox.margin>
</Label>
<ComboBox fx:id="comboBoxPorts" prefHeight="25.0" prefWidth="277.0" promptText="COM PORTS" style="-fx-background-color: #bdc3c7;" styleClass="comboBox" stylesheets="#testSS.css" />
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
</children>
</HBox>
</children>
</VBox>
</center>
<bottom>
<HBox prefHeight="66.0" prefWidth="723.0" style="-fx-background-color: #222222;" BorderPane.alignment="CENTER">
<children>
<Button fx:id="nextScene" mnemonicParsing="false" onAction="#setNextScene" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #d2d4df;" text="Next Scene">
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
<font>
<Font size="16.0" />
</font>
</Button>
<Button fx:id="exit" mnemonicParsing="false" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #ff0000;" text="Exit Lab" textFill="WHITE">
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
<font>
<Font size="16.0" />
</font>
</Button>
<Button fx:id="version" layoutX="190.0" layoutY="20.0" mnemonicParsing="false" onAction="#setVersion" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #ffffff;" text="Alert Version">
<font>
<Font size="16.0" />
</font>
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
</Button>
<Button fx:id="showTheCar" layoutX="360.0" layoutY="20.0" mnemonicParsing="false" onAction="#setShowTheCar" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #ffffff;" text="Show the car!">
<font>
<Font size="16.0" />
</font>
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</bottom>
</BorderPane>
Code for JavaFX class:
package labrat;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortException;
import jssc.SerialPortList;
import java.io.IOException;
public class Controller extends Application
{
#FXML
Button changeText;
#FXML
Button showTheCar;
#FXML
Label dynamicText;
#FXML
Button addElement;
#FXML
TextField typeToAdd;
#FXML
ComboBox<String> element;
#FXML
Button nextScene;
#FXML
Button exit;
#FXML
Button version;
#FXML
ImageView imgVw;
#FXML
private Image img;
// for serial com
SerialPort arduinoPort = null;
ObservableList<String> portList;
#FXML
private Label labelValue;
#FXML
ComboBox comboBoxPorts;
#Override
public void start(Stage primaryStage)
{
Parent rootParent = null;
try
{
rootParent = FXMLLoader.load(getClass().getResource("firstScene.fxml"));
primaryStage.setTitle("Test Lab version 3200");
primaryStage.setScene(new Scene(rootParent, 1100, 600));
primaryStage.show();
System.out.println("First Stage now showing");
}
catch (IOException e)
{
e.printStackTrace();
}
labelValue = new Label();
detectPort();
comboBoxPorts = new ComboBox(portList);
comboBoxPorts.valueProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
System.out.println("\nJust making sure this was executed!");
disconnectArduino();
connectArduino(newValue);
}
});
/*
comboBoxPorts.getItems().addAll(portList);
if(comboBoxPorts.getItems().addAll(portList))
{
System.out.println("\nAdded port-list(from observable list) to the CB!");
}
if(!(comboBoxPorts.getItems().addAll(portList)))
{
System.out.println("\nPort-list not added to CB!");
}
*/
}
#Override
public void stop() throws Exception
{
disconnectArduino();
super.stop();
}
// port detector method
private void detectPort(){
System.out.println("\n1/3 Now detecting port...");
portList = FXCollections.observableArrayList();
String[] serialPortNames = SerialPortList.getPortNames();
for(String name: serialPortNames){
System.out.println("\nDetected Port: ");
System.out.println(name);
portList.add(name);
}
}
// connect the Arduino
public boolean connectArduino(String port)
{
System.out.println("\n2/3 Connect Arduino now running...");
boolean success = false;
SerialPort serialPort = new SerialPort(port);
try {
serialPort.openPort();
serialPort.setParams(
SerialPort.BAUDRATE_9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setEventsMask(SerialPort.MASK_RXCHAR);
serialPort.addEventListener((SerialPortEvent serialPortEvent) -> {
if(serialPortEvent.isRXCHAR()){
try {
String st = serialPort.readString(serialPortEvent
.getEventValue());
System.out.println("\nSPE Listener: ");
System.out.println(st);
//Update label in ui thread
Platform.runLater(() -> {
System.out.println("\nAttempted to update label in ui thread");
labelValue.setText(st);
});
} catch (SerialPortException ex) {
ex.printStackTrace();
}
}
});
arduinoPort = serialPort;
success = true;
} catch (SerialPortException ex) {
ex.printStackTrace();
System.out.println("SerialPortException: " + ex.toString());
}
return success;
}
// disconnect the Arduino
public void disconnectArduino()
{
System.out.println("\n3/3 Now disconnecting Arduino...");
if(arduinoPort != null)
{
try
{
arduinoPort.removeEventListener();
if(arduinoPort.isOpened())
{
arduinoPort.closePort();
}
}
catch (SerialPortException e)
{
e.printStackTrace();
}
}
}
#FXML
public void setChangeText()
{
dynamicText.setText("Text changed successfully!");
}
#FXML
public void setShowTheCar()
{
img = new Image("labrat/images/megane.jpg");
imgVw.setImage(img);
imgVw.isPreserveRatio();
}
#FXML
public void setVersion()
{
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("LabRat Version");
alert.setContentText("Version after the previous one! v0.001");
alert.showAndWait();
}
#FXML
public void setNextScene(ActionEvent ev)
{
try
{
Parent secondParent = FXMLLoader.load(getClass().getResource("secondScene.fxml"));
Scene secondScene = new Scene(secondParent);
Stage ourStage = (Stage) ((Node) ev.getSource()).getScene().getWindow();
ourStage.setTitle("Test Lab Page II");
ourStage.setScene(secondScene);
ourStage.show();
}
catch (IOException e)
{
e.printStackTrace();
}
}
#FXML
public void setAddElement()
{
String bufferText = typeToAdd.getText();
element.getItems().addAll(bufferText);
}
}
Console output upto when the scene is shown:
"C:\Program Files\Java\jdk1.8.0_73\bin\java" (cut this short to minimize length)
First Stage now showing
1/3 Now detecting port...
Detected Port:
COM5
How can I get the ComboBox to display the ports? Edit - I'm using the jSSc plugin version 2.8.0
Edit - Corrective changes to the Controller after #RubioRic and #Jose Pereda's suggestion - Port now showing (final code):
package labrat;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortException;
import jssc.SerialPortList;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable
{
#FXML
Button changeText;
#FXML
Button showTheCar;
#FXML
Label dynamicText;
#FXML
Button addElement;
#FXML
TextField typeToAdd;
#FXML
ComboBox<String> element;
#FXML
Button nextScene;
#FXML
Button exit;
#FXML
Button version;
#FXML
ImageView imgVw;
#FXML
private Image img;
// for serial com
SerialPort arduinoPort = null;
ObservableList<String> portList;
#FXML
private Label labelValue;
#FXML
ComboBox comboBoxPorts;
#Override
public void initialize(URL location, ResourceBundle resources)
{
detectPort();
}
// port detector method
private void detectPort(){
System.out.println("\n1/3 Now detecting port...");
portList = FXCollections.observableArrayList();
String[] serialPortNames = SerialPortList.getPortNames();
for(String name: serialPortNames){
System.out.println("\nDetected Port: ");
System.out.println(name);
portList.add(name);
}
// No need to create a new combo instance
// No need to add a change listener to refresh ports
comboBoxPorts.setItems(portList);
comboBoxPorts.valueProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue)
{
System.out.println("\nChangeListener executed!");
disconnectArduino();
connectArduino(newValue);
System.out.println("\nOld Value was: " + oldValue);
System.out.println("\nNew Value is: " + newValue);
labelValue.setText(newValue);
}
});
}
// connect the Arduino
public boolean connectArduino(String port)
{
System.out.println("\n2/3 Connect Arduino now running...");
boolean success = false;
SerialPort serialPort = new SerialPort(port);
try {
serialPort.openPort();
serialPort.setParams(
SerialPort.BAUDRATE_9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.setEventsMask(SerialPort.MASK_RXCHAR);
serialPort.addEventListener((SerialPortEvent serialPortEvent) -> {
if(serialPortEvent.isRXCHAR()){
try {
String st = serialPort.readString(serialPortEvent
.getEventValue());
System.out.println("\nSPE Listener: ");
System.out.println(st);
//Update label in ui thread
Platform.runLater(() -> {
System.out.println("\nAttempted to update label in ui thread");
labelValue.setText(st);
});
} catch (SerialPortException ex) {
ex.printStackTrace();
}
}
});
arduinoPort = serialPort;
success = true;
} catch (SerialPortException ex) {
ex.printStackTrace();
System.out.println("SerialPortException: " + ex.toString());
}
return success;
}
// disconnect the Arduino
public void disconnectArduino()
{
System.out.println("\n3/3 Now disconnecting Arduino...");
if(arduinoPort != null)
{
try
{
arduinoPort.removeEventListener();
if(arduinoPort.isOpened())
{
arduinoPort.closePort();
}
}
catch (SerialPortException e)
{
e.printStackTrace();
}
}
}
#FXML
public void setChangeText()
{
dynamicText.setText("Text changed successfully!");
}
#FXML
public void setShowTheCar()
{
img = new Image("labrat/images/megane.jpg");
imgVw.setImage(img);
imgVw.isPreserveRatio();
}
#FXML
public void setVersion()
{
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("LabRat Version");
alert.setContentText("Version after the previous one! v0.001");
alert.showAndWait();
}
#FXML
public void setNextScene(ActionEvent ev)
{
try
{
Parent secondParent = FXMLLoader.load(getClass().getResource("secondScene.fxml"));
Scene secondScene = new Scene(secondParent);
Stage ourStage = (Stage) ((Node) ev.getSource()).getScene().getWindow();
ourStage.setTitle("Test Lab Page II");
ourStage.setScene(secondScene);
ourStage.show();
}
catch (IOException e)
{
e.printStackTrace();
}
}
#FXML
public void setAddElement()
{
String bufferText = typeToAdd.getText();
element.getItems().addAll(bufferText);
}
}
I'm no JavaFx expert, but I think that you are mixing two concepts Application and Controller. Change suggested by José Pereda may cause a NullPointerException if controller is not initialized properly.
I've launched successfully a little demo using your fxml file and changing your controller to not invoke arduino. But I've used and extra class for launching the scene. That way the #FMX elements are injected properly and the combobox shows ports.
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ComboMain extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("combo.fxml"));
primaryStage.setTitle("Combo");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller
public class ComboController implements Initializable {
// #FXML elements here
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
detectPort(); // Include all the code that you need for initializing elements here
}
// port detector method
// Dummy method - Include arduino calls here
private void detectPort(){
System.out.println("\n1/3 Now detecting port...");
portList = FXCollections.observableArrayList();
String[] serialPortNames = {"COM1", "COM2", "COM3"}; // SerialPortList.getPortNames();
for(String name: serialPortNames){
System.out.println("\nDetected Port: ");
System.out.println(name);
portList.add(name);
}
// No need to create a new combo instance
// No need to add a change listener to refresh ports
comboBoxPorts.setItems(portList);
}
// Arduino methods here
}
As I said, I'm no javafx expert, but maybe you can apply some of these changes to your code.
Based on your code:
#FXML
ComboBox comboBoxPorts;
#Override
public void start(Stage primaryStage)
{
...
comboBoxPorts = new ComboBox(portList);
}
Inside the start() method you are creating a second instance of comboBoxPorts. This is the one that get the list of ports, but this is not added to the scene graph.
On the contrary, you don't add anything to the first instance, the one on the scene graph, that is created by the FXMLLoader thanks to the #FXML annotation.
You only need to add the list:
#FXML
ComboBox comboBoxPorts;
#Override
public void start(Stage primaryStage)
{
...
comboBoxPorts.setItems(portList);
}
EDIT
And as #RubioRic has stated in his answer, while it is possible to merge Application and Controller class content like you have done, it won't allow you accessing injected nodes from the start() method, and any attempt to call comboBoxPorts will throw a NPE, since you will be dealing with two non-related instances of the class (one created by the launcher, the other by FXMLLoader).
The usual approach is just creating a proper Controller class, with an initialize method, while loading the fxml from the Application.start() method.
Controller class
#FXML
ComboBox comboBoxPorts;
public void initialize() {
...
comboBoxPorts.setItems(portList);
}
EDIT 2
In case you still want to use your original single class approach, this will work:
Remove the fx:controller tag from the fxml file, and set the controller on the start() method, referring to this, so you will have just one single instance:
#FXML
ComboBox comboBoxPorts;
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("firstScene.fxml"));
loader.setController(this);
Parent root = loader.load();
...
comboBoxPorts.setItems(portList);
}
package Data_Project;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
public Stage window;
#Override
public void start(Stage primaryStage) throws Exception{
window = primaryStage;
//Scene1
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Parent root1 = FXMLLoader.load(getClass().getResource("Admin.fxml"));
Controller a1 = new Controller();
a1.getSubmitButton().setOnAction(e -> {
window.setScene(new Scene(root1,500,500));
});
window.setTitle("Log in");
window.setScene(new Scene(root,500,500));
window.show();
}
public static void main(String[] args) throws IOException {
launch(args);
}
}
Hey there, im getting error with this code, I can't figure out what's wrong.
Exception in Application start method Exception in thread "main"
java.lang.RuntimeException: Exception in Application start method at
com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:875)
at
com.sun.javafx.application.LauncherImpl.lambda$launchApplication$147(LauncherImpl.java:157)
at
com.sun.javafx.application.LauncherImpl$$Lambda$1/989110044.run(Unknown
Source) at java.lang.Thread.run(Thread.java:745) Caused by:
java.lang.NullPointerException at
Data_Project.Main.start(Main.java:20)
XML:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Data_Project.Controller">
<children>
<Label text="Username" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<TextField fx:id="userField" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<Label text="Password" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<PasswordField fx:id="passField" GridPane.columnIndex="2" GridPane.columnSpan="1" GridPane.rowIndex="3" />
<Button fx:id="submitButton" onAction="#submitForm" text="Log in" GridPane.columnIndex="2" GridPane.columnSpan="2" GridPane.rowIndex="4" />
<Label fx:id="errorLabel" textFill="#c30808" GridPane.columnIndex="2" GridPane.columnSpan="2" GridPane.rowIndex="6" />
</children>
</GridPane>
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Data_Project.Admin">
<children>
<Label text="Username" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<TextField fx:id="userField" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<Label text="Password" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<PasswordField fx:id="passField" GridPane.columnIndex="2" GridPane.columnSpan="1" GridPane.rowIndex="3" />
<Button fx:id="submitButton" text="Log in" GridPane.columnIndex="2" GridPane.columnSpan="2" GridPane.rowIndex="4" />
<Label fx:id="errorLabel" textFill="#c30808" GridPane.columnIndex="2" GridPane.columnSpan="2" GridPane.rowIndex="6" />
</children>
</GridPane>
The XML are both Different Files, but shown here as 1 file, they have the same attributes and all because it was for testing the scene switcher, but for some reason i can't get it to work!
Controller class:
package Data_Project;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.*;
public class Controller{
Scene window;
#FXML Button submitButton;
#FXML TextField userField;
#FXML PasswordField passField;
#FXML Label errorLabel;
public void submitForm(ActionEvent actionEvent) {
authorizedUser user = new authorizedUser();
if(!user.checkCredentials(userField.getText(), passField.getText()))
{
errorLabel.setText("Invalid credentials");
}
}
public Button getSubmitButton() {
return submitButton;
}
}
Admin:
package Data_Project;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.*;
public class Admin{
Scene window;
#FXML Button submitButton;
#FXML TextField userField;
#FXML PasswordField passField;
#FXML Label errorLabel;
public Button getSubmitButton() {
return submitButton;
}
}
The FXMLLoader parses the FXML file, creates an instance of the controller class (if one is specified) and injects any #FXML-annotated fields into that controller instance.
If you create your own controller instance, as you do with
Controller a1 = new Controller();
then the FXMLLoader knows nothing of that instance (how would it?) and so the #FXML-annotated fields are not initialized. Hence when you call
a1.getSubmitButton()
it returns null and so you get a NullPointerException.
To fix this, replace
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
and
Controller a1 = new Controller();
with
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = loader.load();
Controller a1 = loader.getController();
This gives you a reference to the controller instance that the FXMLLoader created, so it has its #FXML-annotated fields properly initialized.