Javafx NPE when updating Label via Hotkey - java

For education purposes I am trying to add hotkeys to my javafx application. Using my sample code, I am unable to access my label via hotkey. Using a button I can call the very same method updating my label succesfully.
The View:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="62.0" prefWidth="91.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fx.probleme.SampleViewController">
<children>
<Label id="label" fx:id="label" layoutX="14.0" layoutY="45.0" text="Label" />
<Button layoutX="20.0" layoutY="14.0" mnemonicParsing="false" onAction="#updateText" text="Button" />
</children>
</AnchorPane>
And the controller:
package fx.probleme;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SampleViewController extends Application {
#FXML
Label label;
#FXML
void updateText() {
label.setText(label.getText() + "+");
}
#Override
public void start(Stage stage) throws Exception {
Parent parent = FXMLLoader.load(this.getClass().getResource("SampleView.fxml"));
Scene scene = new Scene(parent);
scene.setOnKeyPressed((final KeyEvent keyEvent) -> {
if (keyEvent.getCode() == KeyCode.NUMPAD0) {
updateText();
}
});
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

You get NullPointerException, because at that stage the Label is not initialized, the initialization is done in the initialize.
First of all you have mixed your main class with your controller class, you may want to separate them, setting a controller that implements Initializable, after that in the initialize method you can call any method of the components because in it all of the components annotated by #FXML are initialized. In your case, in start method is not yet initialized. Also you may don't want to use the scene's method, instead of you can add events, actions to your content pane, in your case to the AnchorPane.
I would suggest to separate the controller class from your main class, and implement Initializable. This helps you to have a better vision over your application, you cans see where exactly your components are initialized, were are you sure about using their methods, without NPE.
If you don't want to do it in a separate class(which is recommended) you can add an fx:id for AnchorPane in the .fxml file, then you can add the method to onKeyPressed like you did for the Button.

Related

JavaFX custom control use method

I made a custom control CustomControl in JavaFX.
The CustomControl is basically just a button and a text field. It is made of a CustomControl.fxml and a controller CustomControl.java.
I also have a view TestView.fxml which includes the CustomControl with a controller TestController.java. The TestView.fxml has a button. When that button is pressed it calls the method 'OnButtonPress' from the TestController.java. Now in that method I would like to call the method setText from the controller CustomControl.java.
Now I'm facing two problems.
First: I'm getting the exception 'Root hasn't been set. Use method setRoot() before load.'
Second: I don't know how to call the method setText from my custom control.
Here's the code:
TestView.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:controller="controller.TestController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1">
<children>
<fx:include source="../custom_control.fxml" fx:id="custom_control"/>
<Button onAction="#OnButtonPress" fx:id="button" layoutX="148.0" layoutY="117.0" mnemonicParsing="false" text="Button" />
</children>
</AnchorPane>
TestController.java:
package controller;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
public class TestController {
#FXML
private Button button;
#FXML
private VBox custom_control;
public TestController() {
}
#FXML
private void OnButtonPress() {
// that is the method I would like to call
custom_control.setText("This is the new text");
}
}
CustomControl.java:
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
public class CustomControl extends VBox {
#FXML private TextField textField;
public CustomControl() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("custom_control.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void setText(String text){
textField.textProperty().set(text);
}
#FXML
protected void doSomething() {
textField.textProperty().set("The button was clicked");
}
}
CustomControl.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml">
<TextField fx:id="textField"/>
<Button text="Click Me" onAction="#doSomething"/>
</fx:root>
Okey so I figured out why I didn't work so I though I'd share what problems I had.
the name's of the packages have to start with a lower case letter not upper case
The names of the Classes as well as the views (FXML files) have to start with a upper case letter.
instead of <fx:include> you should use the actual tag of the control (in my case <CustomControl>) and import the FXML file
When doing all that it finally worked.

Adding TextFlow to FXML controller makes GUI blank

So I made a basic application which normally looks like...
But if I add a reference to the FXML TextFlow component (fx:id="tofl") in the controller class, the GUI goes blank like...
Please explain why this is happening. My code is as follows:
main.FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.TextFlow?>
<fx:root prefHeight="389.0" prefWidth="732.0" styleClass="grey" stylesheets="#CSS.css" type="AnchorPane" xmlns:fx="http://javafx.com/fxml">
<TextFlow fx:id="tofl" layoutX="14.0" layoutY="14.0" prefHeight="299.0" prefWidth="703.0" />
<Button fx:id="addBtn" layoutX="596.0" layoutY="320.0" mnemonicParsing="false" text="Add new Text block" />
<TextField fx:id="txt" layoutX="14.0" layoutY="320.0" prefHeight="25.0" prefWidth="572.0" />
<CheckBox fx:id="italic" layoutX="14.0" layoutY="360.0" mnemonicParsing="false" styleClass="chckbox" text="Italic" />
<CheckBox fx:id="bold" layoutX="104.0" layoutY="360.0" mnemonicParsing="false" text="Bold" />
<CheckBox fx:id="underline" layoutX="180.0" layoutY="360.0" mnemonicParsing="false" text="Underline" />
<ChoiceBox fx:id="color" layoutX="270.0" layoutY="356.0" prefHeight="25.0" prefWidth="121.0" />
<ChoiceBox fx:id="size" layoutX="399.0" layoutY="356.0" prefHeight="25.0" prefWidth="121.0" />
</fx:root>
mainController.java
package textflow;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
public class mainController extends AnchorPane {
#FXML TextFlow tofl; //Problem here. If this line exists, the GUI is blank white. If I remove it, the GUI shows up. The program doesn't throw ANY errors, so it might just be a bug (either in NetBeans, or my head)
#FXML TextField txt;
#FXML Button addBtn;
#FXML CheckBox italic;
#FXML CheckBox bold;
#FXML CheckBox underline;
#FXML ChoiceBox color;
#FXML ChoiceBox size;
public mainController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("main.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
}
}
}
TextFlow.java - the main class
package textflow;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TextFlow extends Application {
#Override
public void start(Stage stage) throws Exception {
mainController customControl = new mainController();
stage.setScene(new Scene(customControl));
stage.setTitle("Custom Control");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The "#FXML TextFlow tofl;" in mainController.java is what is causing problems. I remove it, everything is fine. I add it, it's blank.
Take a look at the imports in mainController.java:
They don't contain an import for javafx.scene.text.TextFlow and textflow.TextFlow is used instead. You need to add an import to javafx.scene.text.TextFlow. In addition consider renaming your TextFlow class. Using the same type names as types in the API you use can easily lead to confusion.
When mainController's constructor is executed the fxml file is handled until FXMLLoader tries to inject the javafx.scene.text.TextFlow instance to the tofl field which results in a IOException because of the mismatched types.
Since you're simply ignoring the exception in the catch clause instead of handling it, the constructor completes normally and the partially loaded node is added to your scene. It's usually better to at least print the exception, unless you know the exception won't cause (or indicate) an issue, since this makes debugging much easier.

Why do I get a runtime exception while trying to load fxml file in my program

I am learning javafx and now I am trying to apply the techniques I learnt in my java applications. My program is called "WhatsTheTime" which is a simple program which consists of an AnchorPane with an Image of a clock in it. When the pane is clicked, it is supposed to set the text of the label behind the ImageView with the current time and the clock image is set to be invisible. When I try to run the application, I get a runtimeException in the loader.load() statement. While searching on the internet, I found that it is mostly due to incorrectly specifying the fileName, but I checked the fileName and it is absolutely correct.
This is my fxml code:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<fx:root type = "AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#getTheTime" prefHeight="198.0" prefWidth="208.0" type="AnchorPane"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="myPrototypes.WhatsTheTime">
<children>
<Rectangle arcHeight="5.0" arcWidth="5.0" height="200.0" stroke="BLACK" strokeType="INSIDE" width="208.0" />
<Label fx:id="timeLabel" layoutX="90.0" layoutY="90.0" text="Label" />
<ImageView fx:id="clockImage" fitHeight="186.0" fitWidth="193.0" layoutX="7.0" layoutY="7.0">
<image>
<Image url="#../../What'sTheTimeIcon.png" />
</image>
</ImageView>
</children>
</fx:root>
This is my Controller class:
package myPrototypes;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
public class WhatsTheTime extends AnchorPane{
#FXML
private ImageView clockImage;
#FXML
private Label timeLabel;
WhatsTheTime(){
FXMLLoader loader = new FXMLLoader
(getClass().getResource("WhatsTheTime.fxml"));
loader.setRoot(this);
loader.setController(this);
try{
loader.load();
}
catch(IOException e){
throw new RuntimeException();
}
}
#FXML
public void getTheTime(){
clockImage.setVisible(false);
SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm a");
Date date = new Date();
timeLabel.setText(timeFormat.format(date));
}
}
And this is my main class:
package myPrototypes;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class WhatsTheTimeMain extends Application {
#Override
public void start(Stage primaryStage) {
WhatsTheTime component = new WhatsTheTime();
Scene scene = new Scene(component);
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Please help me solve this problem. Tell me if you need any other information
If you specify a controller class in the FXML via the fx:controller attribute, you are instructing the FXMLLoader to instantiate that class during the load() process, and use the instance as the controller object.
However, in your case you are explicitly setting a controller on the loader prior to invoking load:
loader.setController(this);
Since the controller is already set when the FXML is loaded, this generates an exception. (If you read the stack trace, you will see it includes an error message along the lines of "Controller already specified".)
Remove the fx:controller attribute from the root element of the FXML:
<fx:root type = "AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#getTheTime" prefHeight="198.0" prefWidth="208.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" >
(Note: there may be other errors: this is the one that is immediately obvious. You should include the stack trace in your question for more complete answers.)

Java TextArea setText() and appendText() returning Null Pointer Exception [duplicate]

This question already has an answer here:
javafx 8 compatibility issues - FXML static fields
(1 answer)
Closed 8 years ago.
I am using JavaFX 8 and FXML in this project and trying to update my text area with the results from other classes within the program.
The Text Area is defined in the FXML document as such:
<TextArea fx:id="feedBack" editable="false" focusTraversable="false"
layoutX="203.0" layoutY="32.0" prefHeight="205.0" prefWidth="308.0"
wrapText="true"/>
It is called in the controller here, note that originally it was a "private" item but to make it work with the classes I made it public:
#FXML
public static TextArea feedBack;
EDIT: It is worth noting that when the TextArea is identified as "private" I have no issue getting the set/append text method to work but this does not allow me to use the text area in other classes, which is what I need to do.
However now when I try to do either appendText() or setText(), such as follows:
feedBack.setText("Connection Made");
I am given a null point exception. Why is this? I have made this work in JavaFX 7 with FXML by doing the same thing and it works fine. What am I missing to make this work?
EDIT, test/proof of brokenness with complete tiny program.
I did not make another class for this one as the textarea won't work in the control anyway.
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.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="textareatester.FXMLDocumentController">
<children>
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<TextArea fx:id="feedback" layoutX="61.0" prefHeight="200.0" prefWidth="200.0" wrapText="true" />
<Button fx:id="dostuff" layoutX="261.0" layoutY="62.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Button" />
</children>
</AnchorPane>
Main Method:
package textareatester;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TextAreaTester extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Controller Class:
package textareatester;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
#FXML
public static TextArea feedback;
#FXML
private Button dostuff;
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
feedback.setText("Hello World!"); ///<-- this is what gives me the NPE
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// not touching anything
}
}
Solution for those who are curious:
I ended up simply returning my results strings from my methods and then appending them to the TextArea.
The problem is the static at the definition of the TextArea. Since static attributes are bound to the class and not the object, variable feedback is never initiated and thus is null when accessed in the EventHandler.

JavaFX showing view make in scene builder with controller

I have this controller:
package cz.vutbr.feec.bmds.cv2;
import java.awt.Button;
import java.awt.TextField;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Slider;
public class TestGuiController {
private int buttonPressed = 0;
#FXML
private Button tlacitko;
#FXML
private TextField textovePole;
#FXML
private Slider slider;
public void buttonPressed(ActionEvent e) {
buttonPressed++;
textovePole.setText(Integer.toString(buttonPressed));
}
}
this fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<AnchorPane prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml" fx:controller="cz.vutbr.feec.bmds.cv2.TestGuiController">
<children>
<Button fx:id="tlacitko" layoutX="30.0" layoutY="40.0" mnemonicParsing="false" onTouchPressed="#buttonPressed" text="Button" />
<Slider fx:id="slider" layoutX="157.0" layoutY="17.0" orientation="VERTICAL" />
<TextField fx:id="textovePole" layoutX="14.0" layoutY="89.0" prefWidth="134.0" />
</children>
</AnchorPane>
and this is my main class:
package cz.vutbr.feec.bmds.cv2;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("TestGui.fxml"));
primaryStage.setTitle("Titulek");
primaryStage.setScene(new Scene(root,300,275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
When I run this through ant I get message box with error (exception during running application). I tried simple fxml without controller and it works so I am guesing I do something wrong with controller. What I must change to have it working?
I must answer my own question. Problem was in TestGuiController where I used java.awt.Button and java.awt.TextField instead of javafx.scene.control.Button and javafx.scene.control.TextField.
I'm not 100% sure but try:
in FXML: Button: onAction instead of onTouchPressed
Please provide the exact Exception message.

Categories

Resources