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);
}
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
Hi I'm very new to Java and Javafx so I hope you can help me with a problem. I'm trying to do a proper MVC Pattern with Scene Builder but my code doesn't work and I don't know why.
I have understood that the Model class have to get the data and the Controller class should use and handle the data but I have big problems with that the Scene builder does accept one controller class for one FXML file. That is why I tried it with getters and setters to have the connection between Model and Controller.
But also I think I am not doing it right.
Main class:
package application;
import javafx.application.Application;
import javafx.fxml.*;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application{
#Override
public void start(Stage primaryStage) throws Exception{
try {
Parent root = FXMLLoader.load(getClass().getResource("/login/LoginUI.fxml"));
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void startApp(Stage Stage) throws Exception{
try {
Parent root = FXMLLoader.load(getClass().getResource("/financeApp/UI.fxml"));
Scene scene = new Scene(root, 1022, 593);
Stage.setScene(scene);
Stage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Controller class:
package login;
import application.Main;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import login.ModelLogin;
public class ControllerLogin {
#FXML TextField userNameField;
#FXML PasswordField passwordField;
#FXML Button loginButton;
ModelLogin model = new ModelLogin();
public void setUserName() {
model.setUserNameField(userNameField);
}
public void setPassword() {
model.setPasswordField(passwordField);
}
public void login(ActionEvent event) {
if (model.getUserNameField().getText().equals("test") && model.getPasswordField().getText().equals("1234")) {
Stage stage = new Stage();
Main startUI = new Main();
try {
startUI.startApp(stage);
} catch (Exception e) {
e.printStackTrace();
}
}else {
System.out.println("Try again");
}
}
}
Model class:
package login;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
public class ModelLogin {
private TextField userNameField;
private PasswordField passwordField;
public TextField getUserNameField() {
return userNameField;
}
public void setUserNameField(TextField userNameField) {
this.userNameField = userNameField;
}
public PasswordField getPasswordField() {
return passwordField;
}
public void setPasswordField(PasswordField passwordField) {
this.passwordField = passwordField;
}
}
and this is the FXML file created with Scene builder:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="290.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="login.ControllerLogin">
<children>
<AnchorPane prefHeight="290.0" prefWidth="400.0">
<children>
<Label alignment="CENTER" layoutX="150.0" layoutY="38.0" prefHeight="30.0" prefWidth="100.0" text="Login">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<Label layoutX="159.0" layoutY="108.0" text="Benutzername">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<TextField fx:id="userNameField" layoutX="126.0" layoutY="125.0" onAction="#setUserName" />
<Label layoutX="175.0" layoutY="165.0" text="Passwort">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<PasswordField fx:id="passwordField" layoutX="126.0" layoutY="182.0" onAction="#setPassword" />
<Button fx:id="loginButton" layoutX="175.0" layoutY="233.0" mnemonicParsing="false" onAction="#login" text="Login" />
</children>
</AnchorPane>
</children>
</VBox>
Folders
I would be happy about some Feedback. Thank you!!
All UI elements should be in the view.
A model should have only information and logic that the view and controller use.
public class ModelLogin {
private final String userName;
private final String password;
ModelLogin(String userName, String password) {
this.userName = userName;
this.password = password;
}
boolean isCorrectCredentials(String userName, String password){
return this.userName.equals(userName)&&this.password.equals(password);
}
}
The controller "wires" the view and the model: it handles credential verification and
change of scene.
Note that it is modified to accept a reference of Main so it can change scene:
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
public class ControllerLogin {
#FXML TextField userNameField;
#FXML PasswordField passwordField;
private ModelLogin model;
private Main main;
#FXML
void initialize() {
model = new ModelLogin("test", "1234");
}
public void login(ActionEvent event) {
if (model.isCorrectCredentials(userNameField.getText(), passwordField.getText() )) {
try {
main.startApp();
} catch (Exception e) {
e.printStackTrace();
}
}else {
System.out.println("Try again");
}
}
void setMain(Main main) {
this.main = main;
}
}
The text field onAction is not used, so it was removed from the fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="290.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="login.ControllerLogin">
<children>
<AnchorPane prefHeight="290.0" prefWidth="400.0">
<children>
<Label alignment="CENTER" layoutX="150.0" layoutY="38.0" prefHeight="30.0" prefWidth="100.0" text="Login">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<Label layoutX="159.0" layoutY="108.0" text="Benutzername">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<TextField fx:id="userNameField" layoutX="126.0" layoutY="125.0"/>
<Label layoutX="175.0" layoutY="165.0" text="Passwort">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<PasswordField fx:id="passwordField" layoutX="126.0" layoutY="182.0" />
<Button fx:id="loginButton" layoutX="175.0" layoutY="233.0" mnemonicParsing="false" onAction="#login" text="Login" />
</children>
</AnchorPane>
</children>
</VBox>
The Main was modified to get a reference to the controller, and to change scene:
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{
private Stage primaryStage;
private Parent root;
#Override
public void start(Stage primaryStage) throws Exception{
try {
this.primaryStage = primaryStage;
FXMLLoader loader = new FXMLLoader(getClass().getResource("/login/LoginUI.fxml"));
root = loader.load();
ControllerLogin controller = loader.getController();
controller.setMain(this);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void startApp() throws Exception{
try {
root = FXMLLoader.load(getClass().getResource("/financeApp/UI.fxml"));
Scene scene = new Scene(root, 1022, 593);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
I know that there are a lot of questions already answered for this, but I just cant get my head around it. It is a possible duplicate of:
accessing a Pane from another class in javafx
JavaFX change Pane color from a different class
In my app I want to clear the changablePane (StackPane) in the MainWindowController from a mouseEvent in the NotesScreenController so that only the marked as done notes will be displayed.
MainWindowController.java
package gui;
import gui.mainWindow.issues.NotesScreenController;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Stack;
public class MainWindowController implements Initializable {
private Stage stage = null;
private StackPane paneNotes = null;
private NotesScreenController secondPane;
#FXML
private AnchorPane mainContainer;
#FXML
private VBox vBoxContainer;
#FXML
private MenuBar menuBarTop;
#FXML
private HBox hBoxContainer;
#FXML
private StackPane navigationSection;
#FXML
private TreeView<Button> treeView;
#FXML
private StackPane changablePane;
public static Button issuesNotes;
//TAB SO FILTRI
#Override
public void initialize(URL location, ResourceBundle resources) {
createTreeView();
}
private void createTreeView() {
Button treeViewHeader = new Button("Zdravo");
TreeItem<Button> treeViewHeaderItem = new TreeItem<>(treeViewHeader);
treeViewHeader.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
treeViewHeaderItem.setExpanded(true);
//ROOT FOR ISSUES TRACKING
Button rootForIssues = new Button("Issues Tracker");
Button issuesTable = new Button("Issues Table");
issuesNotes = new Button("Request Notes");
TreeItem<Button> rootForIssuesItem = new TreeItem<>(rootForIssues);
TreeItem<Button> issuesTableItem = new TreeItem<>(issuesTable);
TreeItem<Button> issuesNotesItem = new TreeItem<>(issuesNotes);
rootForIssues.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
issuesTable.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
issuesNotes.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
rootForIssuesItem.setExpanded(true);
rootForIssuesItem.getChildren().addAll(issuesTableItem, issuesNotesItem);
//ROOT ZA NEKOE DRUGO - PROBNO
Button buttonA = new Button("Proba");
Button buttonB = new Button("Proba");
Button buttonC = new Button("Proba");
TreeItem<Button> nodeA = new TreeItem<>(buttonA);
TreeItem<Button> nodeB = new TreeItem<>(buttonB);
TreeItem<Button> nodeC = new TreeItem<>(buttonC);
buttonA.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
buttonB.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
buttonC.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
nodeA.setExpanded(true);
nodeA.getChildren().addAll(nodeB, nodeC);
//ADDING ALL ROOTs OF THE TREEVIEW
treeViewHeaderItem.getChildren().addAll(rootForIssuesItem, nodeA);
issuesNotes.setOnAction(event ->{
clearPane();
URL paneOneUrl = getClass().getClassLoader().getResource("gui/mainWindow/issues/NotesScreen.fxml");
FXMLLoader loader = new FXMLLoader();
NotesScreenController nsc = new NotesScreenController();
loader.setController(nsc);
try {
paneNotes = loader.load(paneOneUrl);
changablePane.getChildren().add(paneNotes);
} catch (IOException e) {
e.printStackTrace();
}
});
issuesTable.setOnAction(event -> {
clearPane();
});
//TREE VIEW
treeView.setId("tree-view-issues");
treeView.getStylesheets().addAll("styles/Notes/TreeViewStyles/TreeView.css");
treeView.setRoot(treeViewHeaderItem);
}
public void clearPane() {
changablePane.getChildren().clear();
}
public void getMainScreenController() {
}
public static Button getIssuesNotes() {
return issuesNotes;
}
public void setStage(Stage stage) {
this.stage = stage;
stage.setResizable(true);
stage.setTitle("SoloStats - Welcome");
}
public void closeStage() {
if (this.stage != null) {
this.stage.close();
}
}
}
MainWindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TreeView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane fx:id="mainContainer" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.MainWindowController">
<children>
<VBox fx:id="vBoxContainer" layoutX="530.0" layoutY="230.0" prefHeight="25.0" prefWidth="1200.0" AnchorPane.bottomAnchor="572.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<MenuBar fx:id="menuBarTop" prefHeight="25.0">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</VBox>
<HBox fx:id="hBoxContainer" layoutX="384.0" layoutY="238.0" prefHeight="600.0" prefWidth="1200.0" style="-fx-background-color: rgb(247, 247, 247);" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="25.0">
<children>
<StackPane fx:id="navigationSection" prefHeight="150.0" prefWidth="300.0" style="-fx-background-color: #222;">
<children>
<TreeView fx:id="treeView" fixedCellSize="24.0" prefHeight="200.0" prefWidth="200.0">
<StackPane.margin>
<Insets left="-25.0" />
</StackPane.margin>
</TreeView>
</children>
</StackPane>
<StackPane fx:id="changablePane" prefHeight="575.0" prefWidth="950.0" stylesheets="#../styles/MainWindow/StackPaneChangable.css" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</children>
</AnchorPane>
NotesScreenController.java
package gui.mainWindow.issues;
import gui.MainWindowController;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class NotesScreenController extends AnchorPane implements Initializable {
private NotesDirectory notesDirectory = new NotesDirectory();
private MainWindowController mainController;
#FXML
private StackPane mainContainer;
#FXML
private VBox vBoxContainer;
#FXML
private HBox hBoxFilterContainer;
#FXML
private ScrollPane scrollPane;
#FXML
private TilePane tilePaneNotesScreen;
#FXML
private ComboBox<String> generalSortBox;
#FXML
private ComboBox<String> sortByNameBox;
#Override
public void initialize(URL location, ResourceBundle resources) {
loadScreen();
}
public void loadScreen() {
try {
notesDirectory.insertNotesToTilePane(tilePaneNotesScreen, notesDirectory.deserializedNotesList(notesDirectory.getFileName(new File("src/notesDirectory")), "src/notesDirectory/"));
} catch (IOException e) {
e.printStackTrace();
}
generalSortBox.setItems(FXCollections.observableArrayList("Flagged", "Date added", "Done Notes"));
sortByNameBox.setItems(FXCollections.observableArrayList("Priority", "Priority", "Priority", "Priority",
"Priority", "Priority", "Priority", "Priority", "Priority", "Priority", "Priority", "Priority",
"Priority", "Priority"));
generalSortBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> selected, String oldValue, String newValue) {
if (newValue != null) {
switch (newValue) {
case "Done Notes": try {
//THE ACTION NEED TO TAKE PLACE HERE
notesDirectory.insertNotesToTilePane(tilePaneNotesScreen, notesDirectory.deserializedNotesList(notesDirectory.getFileName(new File("src/notesRecycleBin")), "src/notesRecycleBin/"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
}
public void setMainController(MainWindowController controller) {
this.mainController = controller;
}
}
NotesScreen
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.TilePane?>
<?import javafx.scene.layout.VBox?>
<StackPane fx:id="mainContainer" prefHeight="575.0" prefWidth="950.0" stylesheets="#../../../styles/MainWindow/StackPaneChangable.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.mainWindow.issues.NotesScreenController">
<children>
<VBox fx:id="vBoxContainer" prefHeight="575.0" prefWidth="950.0">
<children>
<HBox fx:id="hBoxFilterContainer" stylesheets="#../../../styles/MainWindow/ChoiceBox/HBoxFilters.css">
<children>
<ComboBox fx:id="generalSortBox" prefHeight="25.0" prefWidth="220.0" promptText="Sort by..." stylesheets="#../../../styles/MainWindow/ChoiceBox/ComboBox.css" />
<ComboBox fx:id="sortByNameBox" prefHeight="25.0" prefWidth="220.0" promptText="Choose name" stylesheets="#../../../styles/MainWindow/ChoiceBox/ComboBox.css" />
</children>
</HBox>
<ScrollPane fx:id="scrollPane" fitToHeight="true" fitToWidth="true" hbarPolicy="NEVER" prefHeight="575.0" prefWidth="950.0" stylesheets="#../../../styles/MainWindow/StackPaneChangable.css" VBox.vgrow="ALWAYS">
<content>
<TilePane fx:id="tilePaneNotesScreen" hgap="25.0" prefColumns="4" prefHeight="575.0" prefTileWidth="228.0" prefWidth="950.0" stylesheets="#../../../styles/MainWindow/StackPaneChangable.css" vgap="25.0">
<padding>
<Insets bottom="25.0" left="25.0" right="25.0" top="35.0" />
</padding>
</TilePane>
</content>
</ScrollPane>
</children>
</VBox>
</children>
</StackPane>
Basically all you are missing is setting the main screen controller in the NotesScreenController instance:
FXMLLoader loader = new FXMLLoader();
NotesScreenController nsc = new NotesScreenController();
loader.setController(nsc);
nsc.setMainController(this);
And then from the NotesScreenController you can clear the pane simply by calling
mainController.clearPane();
i.e. you can do:
generalSortBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> selected, String oldValue, String newValue) {
if (newValue != null) {
switch (newValue) {
case "Done Notes": try {
//THE ACTION NEED TO TAKE PLACE HERE
mainController.clearPane();
notesDirectory.insertNotesToTilePane(tilePaneNotesScreen, notesDirectory.deserializedNotesList(notesDirectory.getFileName(new File("src/notesRecycleBin")), "src/notesRecycleBin/"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
Note you have one subtle bug: when you call
paneNotes = loader.load(paneOneUrl);
you are calling the static FXMLLoader.load(URL) method. Since it's a static method, it's not invoked on the FXMLLoader instance you created, and so the previous call to setController(...) is effectively ignored. You need to set the location of the FXMLLoader instance, and then call the no-arg load() method. So you should have:
issuesNotes.setOnAction(event ->{
clearPane();
URL paneOneUrl = getClass().getClassLoader().getResource("gui/mainWindow/issues/NotesScreen.fxml");
FXMLLoader loader = new FXMLLoader();
NotesScreenController nsc = new NotesScreenController();
nsc.setMainController(this);
loader.setController(nsc);
loader.setLocation(paneOneUrl);
try {
// note call to no-arg load() method:
paneNotes = loader.load();
changablePane.getChildren().add(paneNotes);
} catch (IOException e) {
e.printStackTrace();
}
});
Finally, since you are setting the controller from the Java code, you need to remove the fx:controller attribute from the NotesScreen.fxml root element:
<StackPane fx:id="mainContainer" prefHeight="575.0" prefWidth="950.0" stylesheets="#../../../styles/MainWindow/StackPaneChangable.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<!-- ... -->
</StackPane>
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?
I have a question.
I want to change the color of a pane from another controller class.
I am using this code:
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Menu.fxml"));
try {
Parent loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
MenuController controller = (MenuController) loader.getController();
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getRedPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
The loaded, controller and pane aren't null.
But the pane's color doesn't change, can someone help me with this problem?
Thank you very much.
[EDIT]
public class MenuController implements Initializable
{
#FXML
private GridPane MenuRoot;
#FXML
private Pane redPane;
#Override
public void initialize(URL location, ResourceBundle resources)
{
}
#FXML
private void changeGridSize(ActionEvent event){
new ChangeSizes();
}
public GridPane getMenuRoot(){
return this.MenuRoot;
}
public Pane getRedPane(){
return this.redPane;
}
}
[EDIT]
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="MenuRoot" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nl.voxworks.homeserver.client.MenuController">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<Pane fx:id="redPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" GridPane.rowIndex="1" />
<Pane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: black;" GridPane.columnIndex="1" GridPane.rowIndex="1" />
</children>
</GridPane>
[EDIT] (different project all files included)
package javafxapplication16;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
public class ChangeSize {
public ChangeSize(){
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loader.load();
} catch (IOException ex) {
Logger.getLogger(ChangeSize.class.getName()).log(Level.SEVERE, null, ex);
}
FXMLDocumentController controller = (FXMLDocumentController) loader.getController();
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
}
}
FXMLDocumentController.
package javafxapplication16;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
public class FXMLDocumentController implements Initializable {
#FXML
private Pane redPane;
#FXML
private void changeGridSize(ActionEvent event){
new ChangeSize();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
public Pane getPane(){
return this.redPane;
}
}
JavaFXApplication16
package javafxapplication16;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXApplication16 extends Application {
#Override
public void start(Stage stage) throws Exception {
// Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
// FXMLLoader loader
Parent loaded=null;
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(loaded);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
FXML
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="MenuRoot" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication16.FXMLDocumentController">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<Pane fx:id="redPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" GridPane.rowIndex="1" />
<Pane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: black;" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Button mnemonicParsing="false" onAction="#changeGridSize" text="Button" />
</children>
</GridPane>
This is my code: I hope helped you
FXMLDocumentController.class
public class FXMLDocumentController implements Initializable {
#FXML
private Pane redPane;
#FXML
private void changeGridSize(ActionEvent event){
// new ChangeSizes();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
public Pane getPane(){
return this.redPane;
}
}
JavaFXMLApplication3.class
public class JavaFXMLApplication3 extends Application {
#Override
public void start(Stage stage) throws Exception {
// Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
// FXMLLoader loader
Parent loaded=null;
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(loaded);
stage.setScene(scene);
stage.show();
FXMLDocumentController controller = (FXMLDocumentController) loader.getController();
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
FXMLDocument.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.*?>
<GridPane fx:id="MenuRoot" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxmlapplication3.FXMLDocumentController">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<Pane fx:id="redPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" GridPane.rowIndex="1" />
<Pane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: black;" GridPane.columnIndex="1" GridPane.rowIndex="1" />
</children>
</GridPane>
I test your code and the problem is that you create another Pane redPane that isn't show:
when you call FXMLLoader you create a new loader that isn't show in stage.
I suggested you a possible solution : create a static Stage ... example code:
public class JavaFXMLApplication3 extends Application {
static Stage staticstage;
// Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
// FXMLLoader loader
#Override
public void start(Stage stage) throws Exception {
// Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
// FXMLLoader loader
staticstage=stage;
Parent loaded=null;
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(loaded);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
and change class ChangeSize
public class ChangeSize {
public ChangeSize() {
Parent loaded=null;
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(loaded);
JavaFXMLApplication3.staticstage.setScene(scene);
JavaFXMLApplication3.staticstage.show();
FXMLDocumentController controller = (FXMLDocumentController) loader.getController();
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
}
}
another solution is to pass FXMLDocumentController to class ChangeSize ... example code :
public class ChangeSize {
public ChangeSize(FXMLDocumentController controller) {
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
}
and in FXMLDocumentController class change the changeGridSize
#FXML
private void changeGridSize(ActionEvent event){
new ChangeSize(this);
}