Getting NullPointerException when button is clicked (JavaFX and FXML) [duplicate] - java

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
What's the difference between fx:id and id: in JavaFX?
(4 answers)
Closed 5 years ago.
After finally getting the gui to run without problems whenever i click on a designated button the IDE (Eclipse) putting out a long massage with this error in its end.
Caused by: java.lang.NullPointerException
at ui.IOTabController.handleSourceFolderPathSubmit(IOTabController.java:32)
... 62 more
Here is the IOTab.fxml (relevent part):
<AnchorPane fx:id="IOTab" minHeight="0.0" minWidth="0.0"
prefHeight="282.0" prefWidth="676.0" xmlns="http://javafx.com/javafx/9"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="ui.IOTabController">
<children>
<Pane layoutX="12.0" layoutY="50.0" prefHeight="37.0" prefWidth="625.0">
<children>
<TextField id="sourceFolderFullPath" layoutX="167.0" layoutY="1.0" prefHeight="26.0"
prefWidth="391.0"/>
<Button id="sourceFolderPathSubmit" layoutX="567.0" mnemonicParsing="false" text="Enter"
onAction="#handleSourceFolderPathSubmit"/>
<Text layoutY="18.0" strokeType="OUTSIDE" strokeWidth="0.0"
text="Source folder's full path:" />
</children>
</Pane>
...
</AnchorPane>
Its controller IOTabController.java:
public class IOTabController implements Initializable{ // IOTab.fxml controller
#FXML private MainController Main;
// variables from fxml file to inject.
#FXML private AnchorPane IOTab;
#FXML private TextField sourceFolderFullPath;
#FXML private Button sourceFolderPathSubmit;
#FXML private TextField csvFileName;
#FXML private Button csvFileNameSubmit;
#FXML private Button deleteExistingData;
#FXML private Button convertCsvToKml;
#FXML
protected void handleSourceFolderPathSubmit(ActionEvent event) { // handles path submit.
if (sourceFolderFullPath.getText().isEmpty()) { // if empty field
AlertHelper.showAlert(Alert.AlertType.ERROR, "Form Error!", "Please enter path.");
return;
}
AlertHelper.showAlert(Alert.AlertType.CONFIRMATION, "SUCCESS","Path inserted.");
}
// class for creating alerts.
public static class AlertHelper {
public static void showAlert(Alert.AlertType alertType, String title, String message) {
Alert alert = new Alert(alertType);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(message);
alert.showAndWait();
}
}
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub
}
}
The main controller:
public class MainController { // main.fxml controller.
#FXML private IOTabController IOTabController;
#FXML public void initialize() {
System.out.println("Application started");
IOTabController.initialize(null, null);
}
}
The gui is running fine until I click on "sourceFolderPathSubmit" button which pops the warning above every click (no matter if i put text in the TextField or not). I cant seem to find what to add or remove to make the button work.

Related

How to run RFID tag listener method in javafx project?

I am working on a project involves RFID technology, what i am trying to do at the moment, once the RFIDTagListener method runs, I basically pass a tag to a reader which its serial number will be sent to a server to get some relevant data back and pop them on a GUI screen. what I have done so far is getting the data upon sending reader's data manually without passing a tag becasue I don't know how to do it otherwise and here is the problem. where I am working on a javafx project and when I tried to put the RFIDTagListener method within the MainController class and on compiling, the taglistner method wouldn't be triggered and just ignored, it's only the GUI screen will be opened.However, I also tried to have RFIDTagListener within the main class but on compiling, the taglistner method would be run first and when it's finished in 5 seconds, my GUI window will be opened next. SO I Don't know where this method should be located exactly. Essentially What I want is to have them both running at the same time, the taglistener running in the background with the GUI window opened simulitniously.
Any recommendation guys would be much appricated.
MainController class :
public class MainController {
RFID rfid = new RFID();
String ReaderNo = null;
String walletJson = new String();
Gson gson = new Gson();
public static String sensorServerURL = "http://localhost:8080/PhidgetServer2019/SensorServerRFIDdata";
walletDAO dao = new walletDAO();
ArrayList<wallet> allwallets = new ArrayList<wallet>();
#FXML VBox ConsultHR;
#FXML private Label message;
#FXML private Label WalletName;
#FXML private ListView<ArrayList<wallet>> list;
#FXML private ListView<ArrayList<wallet>> RoomAList;
#FXML private TableView<wallet> tableViewData;
#FXML private TableColumn<wallet, String> NameColumn;
#FXML private TableColumn<wallet, String> LocationColumn;
#FXML private TableColumn<wallet, String> TagColumn;
public void getTags(ActionEvent event) throws SQLException {
allwallets = dao.getWalletTag();
try {
allwallets = dao.getWalletTag();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(allwallets);
list.getItems().add(allwallets);
}
public MainController() throws PhidgetException {
// Make the RFID Phidget able to detect loss or gain of an rfid card
rfid.addTagListener(new RFIDTagListener() {
// What to do when a tag is found
public void onTag(RFIDTagEvent e) {
try {
ReaderNo = String.valueOf(rfid.getDeviceSerialNumber());
} catch (PhidgetException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("Reader serial number is " + ' '+ReaderNo);
wallet walletData = new wallet("385055");
walletJson = gson.toJson(walletData);
String resultfromserver = sendToServer(walletJson);
System.out.println("DEBUG: data in json : " +resultfromserver);
wallet walletObject = gson.fromJson(resultfromserver, wallet.class);
System.out.println("DEBUG: The wallet's Data: "+' '+ walletObject);
WalletName.setText(walletObject.getWalletName());
}
});
rfid.addTagLostListener(new RFIDTagLostListener() {
// What to do when a tag is lost
public void onTagLost(RFIDTagLostEvent e) {
// optional print, used as debug here
System.out.println("DEBUG: Tag lost: " + e.getTag());
}
});
}
}
Main class :
public class Main extends Application {
//RFID rfid = new RFID();
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Wallet locator !");
try {
Parent root = FXMLLoader.load(getClass().getResource("/application/Main.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
public static void main(String[] args) throws PhidgetException {
new MainController();
launch(args);
}
}
Main.FXML :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="269.0" prefWidth="403.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
<Button layoutX="149.0" layoutY="251.0" mnemonicParsing="false" onAction="#getTags" prefHeight="46.0" prefWidth="82.0" text="tags" />
<Label fx:id="message" layoutX="139.0" layoutY="209.0" prefHeight="35.0" prefWidth="101.0" />
<ListView id="studentObservableList" fx:id="list" layoutY="209.0" prefHeight="131.0" prefWidth="139.0" />
<TableView fx:id="tableViewData" prefHeight="200.0" prefWidth="231.0" style="-fx-border-color: red;">
<columns>
<TableColumn fx:id="NameColumn" prefWidth="75.0" text="Name"/>
<TableColumn fx:id="LocationColumn" prefWidth="75.0" text="Location" />
<TableColumn fx:id="TagColumn" prefWidth="75.0" text="Tag" />
</columns>
</TableView>
<Button layoutX="251.0" layoutY="14.0" mnemonicParsing="false" onAction="#getWallets" prefHeight="56.0" prefWidth="82.0" text="wallets" />
</AnchorPane>
1st point
The main method is inside the MainController class and it's instantiating itself, which is possible but not conventional.
2nd point
Never put your main method into a controller! Put it into your Main class instead.
3rd point
You must define the application launch inside your main method, by calling Application.launch(). This method will call your overriden start method (among other things) and display the GUI:
public static void main(String[] args) throws PhidgetException {
launch(args);
new MainController();
}
4th point
You don't need to instantiate directly a controller in JavaFX. With your current code you're creating a MainController instance which is unlinked to your GUI; that's why you can see your GUI without interacting with it. You need to remove the new MainController(); line into your main method, then check if the fx:controller attribute is defined in the root of your FXML file.
You can call this controller instance using root.getController() in your start method.

Button EventHandler in Controller class is not working [duplicate]

This question already has an answer here:
Handle event on disabled Node
(1 answer)
Closed 4 years ago.
Hello I have two problems.
First one:
When I start my app, I can press my ToggleButton with spacebar.
Second one:
(Even without ToggleButton) My EventHandler on my button is not working, on pressing spacebar nothing is going on.
Main class:
public class Main extends Application {
#Override
public void start(Stage stage) throws IOException {
Parent parent = (Parent) FXMLLoader.load(getClass().getResource("/application/MainView.fxml"));
Scene scene = new Scene(parent);
scene.getRoot().setFocusTraversable(true);
stage.setScene(scene);
stage.setTitle("Login Page");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Fxml file:
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="501.0" prefWidth="597.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
<children>
<Button fx:id="button" layoutX="136.0" layoutY="184.0" mnemonicParsing="false" prefHeight="133.0" prefWidth="127.0" text="Button" />
<Label fx:id="label" layoutX="199.0" layoutY="106.0" prefHeight="61.0" prefWidth="198.0" text="Label" />
<ToggleButton fx:id="toggleButton" layoutX="318.0" layoutY="186.0" mnemonicParsing="false" prefHeight="133.0" prefWidth="127.0" text="ToggleButton" />
</children>
</AnchorPane>
Controller class:
public class MainController implements Initializable {
#FXML
private Button button;
#FXML
private Label label;
#FXML
private ToggleButton toggleButton;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
button.setDisable(true);
button.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.SPACE) {
System.out.println("space pressed");
button.setDisable(false);
}
}
});
button.addEventFilter(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.SPACE) {
System.out.println("space pressed");
button.setDisable(true);
}
}
});
}
}
At first as #c0der mentioned you hasn't been assined event handler
as the button is disabled via button.setDisabled(true) so it can't receive any events such as mouse and key events see that javafx doc
Edit with some search i found another similar question in stackoverflow

How do I update the center node of a BorderPane using FXML Controller

I am trying to update the center node of a BorderPane using FXML. I have created a VBox on the left with Buttons and when clicked they are supposed to update the center node however the center node does not update. Can someone shed some light on what I am doing incorrectly?
I know the buttons events work (they print to the screen usiong println) but it will not update the UI.
The root nodes .fxml (the BorderPane):
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:id="rootPane">
<left>
</left>
<center>
</center>
</BorderPane>
The menu
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<VBox fx:controller="" xmlns:fx="http://javafx.com/fxml" >
<children>
<Button text="Dashboard" fx:id="dashboardButton" onAction="#dashboardButtonEvent" />
<Button text="Sales" fx:id="salesButton" onAction="#salesButtonEvent" />
</children>
</VBox>
The MenuController
public class MenuController implements Initializable {
#FXML
private BorderPane rootPane;
#FXML
private Button dashboardButton; //same name as in the menu.fxml file
#FXML
private Button salesButton; //same name as in the menu.fxml file
#FXML
private void dashboardButtonEvent(ActionEvent event) {
try {
VBox dashboard = FXMLLoader.load(getClass().getResource("../../../fxml/dashboard.fxml"));
rootPane = FXMLLoader.load(getClass().getResource("../../../fxml/root.fxml"));
rootPane.setCenter(dashboard);
} catch (IOException e) { System.out.println(e); }
}
#FXML
private void salesButtonEvent(ActionEvent event) {
try {
VBox sales = FXMLLoader.load(getClass().getResource("../../../fxml/sales.fxml"));
rootPane = FXMLLoader.load(getClass().getResource("../../../fxml/root.fxml"));
rootPane.setCenter(sales);
} catch (IOException e) { System.out.println(e); }
}
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
I assume where I am going wrong is the way I am going about assigning the root pane using rootPane = FXMLLoader.load(getClass().getResource("../../../fxml/root.fxml"));. If thats the case, how do I get the current rootPane from the existing scene?

JavaFx actions between controllers

How i can do button action for editing TableView. I need to put text from TextArea to table when i touch button. And if put System.out.println in inputToTable() it is work.
public class InputController {
public TextArea inputArea;
public Button inputButton;
private TableController tableController;
public void initialize() {
tableControllerInit();
}
public void inputToTable() {
if(inputArea.getText() != "") {
tableController.tableInfo.setItems(FXCollections.observableArrayList(new InputObject(inputArea.getText())));
}
}
private void tableControllerInit() {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("table.fxml"));
fxmlLoader.load();
tableController = fxmlLoader.getController();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class TableController {
#FXML TableView<InputObject> tableInfo;
#FXML TableColumn<InputObject, String> col1;
public void initialize() {
col1.setCellValueFactory(new PropertyValueFactory<>("text"));
}
}
public class Controller implements Initializable {
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
public class InputObject {
String text;
public InputObject(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
<BorderPane fx:controller="sample.Controller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<left>
<fx:include source="table.fxml"/>
</left>
<center>
<fx:include source="input.fxml"/>
</center>
</BorderPane>
<TableView fx:controller="sample.TableController" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:id="tableInfo" prefHeight="400.0" prefWidth="330.0">
<columns>
<TableColumn fx:id="col1" prefWidth="75.0" text="Output" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
<VBox fx:controller="sample.InputController" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" alignment="TOP_CENTER" prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER">
<children>
<TextArea fx:id="inputArea" prefHeight="188.0" prefWidth="270.0" />
<Button fx:id="inputButton" onAction="#inputToTable" mnemonicParsing="false" text="Input">
<VBox.margin>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
</VBox.margin>
</Button>
</children>
</VBox>
You load table.fxml twice: once via the fx:include in the main FXML file, and once in InputController, via the FXMLLoader you create in the tableControllerInit() method. Consequently, two instances of TableController are created, one associated with the first UI you load from table.fxml, and one associated with the second UI you load from table.fxml.
The UI you load via the fx:include is displayed in the VBox defined in the main FXML file. The UI you load with the FXMLLoader is never displayed (in fact, you never even keep a reference to it, you just call loader.load() and discard the result). When you try to update the table's items (do you really intend to replace all the existing items, by the way?), you refer to the second controller instance, which is associated with the UI which is never displayed. Consequently, you are updating a table that is not displayed, and you never see any results.
What you really need to do is share the same data between the two controllers associated with the two fx:includes. You can do this simply by injecting those two controllers into the main controller, as described in the "Nested Controllers" section in the documentation.
First, give the fx:include elements fx:id attributes:
<BorderPane fx:controller="sample.Controller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<left>
<fx:include fx:id="table" source="table.fxml"/>
</left>
<center>
<fx:include fx:id="input" source="input.fxml"/>
</center>
</BorderPane>
Then you can inject the controllers into the main controller by creating fields with the word "Controller" appended to the fx:id. Create a single observable list, which will represent the list of items displayed in the table, and pass it to each controller:
public class Controller implements Initializable {
#FXML
private TableController tableController ;
#FXML
private InputController inputController ;
#Override
public void initialize(URL location, ResourceBundle resources) {
ObservableList<InputObject> items = FXCollections.observableArrayList();
tableController.setTableItems(items);
inputController.setTableItems(items);
}
}
Finally, just define the obvious methods in each of the other two controllers:
public class TableController {
#FXML
private TableView<InputObject> tableInfo;
#FXML
private TableColumn<InputObject, String> col1;
public void initialize() {
col1.setCellValueFactory(new PropertyValueFactory<>("text"));
}
public void setTableItems(ObservableList<InputObject> tableItems) {
tableInfo.setItems(tableItems);
}
}
Now the table is displaying the contents of the items list created in the main controller's initalize() method, and the InputController has a reference to the same list. So all you need to do is update that list in the InputController. I assume you just want to add items to the table (not replace them all):
public class InputController {
#FXML
private TextArea inputArea;
#FXML
private Button inputButton;
private ObservableList<InputObject> tableItems ;
public void setTableItems(ObservableList<InputObject> tableItems) {
this.tableItems = tableItems ;
}
public void inputToTable() {
if(! inputArea.getText().isEmpty()) {
tableItems.add(new InputObject(inputArea.getText()));
}
}
}
More generally, if you have more data to share among the different controllers, you would create one or more "model" classes and share a model instance with the controllers. Then you can observe the properties of the model and update them. See Applying MVC With JavaFx for a more comprehensive example.

Javafx button event needs double clicking

I have a javafx scene with several buttons within. The only way that the events of the button will be activated is by double cliking. In fxml the button is using the following action method onAction="#Button1Action". How can I change the functionality of the button1Action event from double click to just one click?
The function onAction:
#FXML
private void Button1Action(ActionEvent event) {
}
and the fxml code:
<Button id="button1" fx:id="button1" maxHeight="1.79.." maxWidth="1.79.." mnemonicParsing="false" onAction="#Button1Action" text="Answer" GridPane.columnIndex="3" GridPane.columnSpan="3" GridPane.halignment="CENTER" GridPane.rowIndex="7" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
</GridPane.margin>
</Button>
You did not posted the body of Button1Action, but most probably it is looking like:
#FXML
private void Button1Action(ActionEvent event) {
button1.setOnAction(e -> System.out.println("Button clicked"));
}
What happens here, that you assign the listener inside the listener, so the actual listener body will be executed on the second click.
Trivial fix is:
#FXML
private void Button1Action(ActionEvent event) {
System.out.println("Button clicked");
}

Categories

Resources