尽管在 JavaFX 应用程序线程中声明了我的 JavaFX 标签,但为什么它被标记为空?
Why is my JavaFX label being marked as null despite declaring it within the JavaFX Application thread?
我正在尝试创建一个时钟,它通过使用每秒变化的动态 UI 标签来监视程序的运行时间。我试过使用以下代码,但一直收到空指针异常。此异常源于 "clock" 标签,该标签在 JavaFX 应用程序线程上似乎为空,尽管已在控制器 class 中声明了它。我还实现了 Platform.runlater 以确保标签更新在 JavaFX 线程上为 运行,因为这是声明标签的地方,但是,它仍然抛出此异常。关于为什么会发生这种情况的任何指示?
控制器:
package GUI;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
public class Controller implements Initializable {
int secondspassed = 0;
int minutespassed = 0;
int hourspassed = 0;
@FXML
private Label XPTrackerlabel;
@FXML
private ProgressBar XPTracker;
@FXML
private ComboBox Minelocation;
@FXML
private Label clock;
Timer timer = new Timer();
TimerTask ticktime = new TimerTask(){
public void run(){
secondspassed++;
if (secondspassed == 60){ secondspassed = 0; minutespassed++;}
else if (minutespassed == 60){ minutespassed = 0; hourspassed++;}
Platform.runLater(() -> clock.setText(hourspassed + ":" + minutespassed + ":" + secondspassed));
}
};
public void start() {
timer.scheduleAtFixedRate(ticktime, 1000, 1000);
}
public void PressButton(ActionEvent event){
Controller startclock = new Controller();
startclock.start();
System.out.println("Hello World");
}
@Override
public void initialize(URL url, ResourceBundle rb) {
Minelocation.getItems().addAll("North", "South", "North-East");
XPTracker.setProgress(0.5);
double XP = XPTracker.getProgress() * 100;
XPTrackerlabel.setText(XP + "%");
clock.setText(hourspassed + ":" + minutespassed + ":" + secondspassed);
}
}
FXML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane fx:id="UI" alignment="center" hgap="10" minHeight="300.0" minWidth="300.0" vgap="10" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="GUI.Controller">
<columnConstraints>
<ColumnConstraints />
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
</rowConstraints>
<children>
<Button fx:id="start_btn" mnemonicParsing="false" onAction="#PressButton" stylesheets="@Style.css" text="Start" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="NEVER" GridPane.rowIndex="7" GridPane.valignment="CENTER" GridPane.vgrow="NEVER" />
<ComboBox fx:id="Minelocation" prefWidth="150.0" promptText="Select Area" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER" />
<ProgressBar fx:id="XPTracker" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="11" />
<Label fx:id="XPTrackerlabel" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="11" GridPane.valignment="CENTER" />
<Label fx:id="clock" GridPane.columnIndex="1" GridPane.halignment="CENTER" />
</children>
</GridPane>
错误:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at GUI.Controller.lambda$run[=12=](Controller.java:38)
at com.sun.javafx.application.PlatformImpl.lambda$null2(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater3(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$null7(WinApplication.java:177)
at java.lang.Thread.run(Unknown Source)
事实证明 Itai 是对的,出于某种原因我认为在 Pressbutton
中创建一个新的控制器实例是个好主意,这就是错误不断被抛出的原因。只需使用 start() 而不是创建新实例并调用 start() 即可解决问题!感谢您的帮助。
修改后的代码如下:
打包 GUI;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
public class Controller implements Initializable {
int secondspassed = 0;
int minutespassed = 0;
int hourspassed = 0;
@FXML
private Label XPTrackerlabel;
@FXML
private ProgressBar XPTracker;
@FXML
private ComboBox Minelocation;
@FXML
private Label clocker;
Timer timer = new Timer();
TimerTask ticktime = new TimerTask(){
public void run(){
secondspassed++;
if (secondspassed == 60){ secondspassed = 0; minutespassed++;}
else if (minutespassed == 60){ minutespassed = 0; hourspassed++;}
Platform.runLater(() -> clocker.setText(hourspassed + ":" + minutespassed + ":" + secondspassed));
}
};
public void start() {
timer.scheduleAtFixedRate(ticktime, 1000, 1000);
}
public void PressButton(ActionEvent event){
start();
System.out.println("Hello World");
}
@Override
public void initialize(URL url, ResourceBundle rb) {
Minelocation.getItems().addAll("North", "South", "North-East");
XPTracker.setProgress(0.5);
double XP = XPTracker.getProgress() * 100;
XPTrackerlabel.setText(XP + "%");
clocker.setText(hourspassed + ":" + minutespassed + ":" + secondspassed);
}
}
我正在尝试创建一个时钟,它通过使用每秒变化的动态 UI 标签来监视程序的运行时间。我试过使用以下代码,但一直收到空指针异常。此异常源于 "clock" 标签,该标签在 JavaFX 应用程序线程上似乎为空,尽管已在控制器 class 中声明了它。我还实现了 Platform.runlater 以确保标签更新在 JavaFX 线程上为 运行,因为这是声明标签的地方,但是,它仍然抛出此异常。关于为什么会发生这种情况的任何指示?
控制器:
package GUI;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
public class Controller implements Initializable {
int secondspassed = 0;
int minutespassed = 0;
int hourspassed = 0;
@FXML
private Label XPTrackerlabel;
@FXML
private ProgressBar XPTracker;
@FXML
private ComboBox Minelocation;
@FXML
private Label clock;
Timer timer = new Timer();
TimerTask ticktime = new TimerTask(){
public void run(){
secondspassed++;
if (secondspassed == 60){ secondspassed = 0; minutespassed++;}
else if (minutespassed == 60){ minutespassed = 0; hourspassed++;}
Platform.runLater(() -> clock.setText(hourspassed + ":" + minutespassed + ":" + secondspassed));
}
};
public void start() {
timer.scheduleAtFixedRate(ticktime, 1000, 1000);
}
public void PressButton(ActionEvent event){
Controller startclock = new Controller();
startclock.start();
System.out.println("Hello World");
}
@Override
public void initialize(URL url, ResourceBundle rb) {
Minelocation.getItems().addAll("North", "South", "North-East");
XPTracker.setProgress(0.5);
double XP = XPTracker.getProgress() * 100;
XPTrackerlabel.setText(XP + "%");
clock.setText(hourspassed + ":" + minutespassed + ":" + secondspassed);
}
}
FXML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane fx:id="UI" alignment="center" hgap="10" minHeight="300.0" minWidth="300.0" vgap="10" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="GUI.Controller">
<columnConstraints>
<ColumnConstraints />
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
</rowConstraints>
<children>
<Button fx:id="start_btn" mnemonicParsing="false" onAction="#PressButton" stylesheets="@Style.css" text="Start" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="NEVER" GridPane.rowIndex="7" GridPane.valignment="CENTER" GridPane.vgrow="NEVER" />
<ComboBox fx:id="Minelocation" prefWidth="150.0" promptText="Select Area" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER" />
<ProgressBar fx:id="XPTracker" prefWidth="200.0" progress="0.0" GridPane.columnIndex="1" GridPane.rowIndex="11" />
<Label fx:id="XPTrackerlabel" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="11" GridPane.valignment="CENTER" />
<Label fx:id="clock" GridPane.columnIndex="1" GridPane.halignment="CENTER" />
</children>
</GridPane>
错误:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at GUI.Controller.lambda$run[=12=](Controller.java:38)
at com.sun.javafx.application.PlatformImpl.lambda$null2(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater3(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$null7(WinApplication.java:177)
at java.lang.Thread.run(Unknown Source)
事实证明 Itai 是对的,出于某种原因我认为在 Pressbutton
中创建一个新的控制器实例是个好主意,这就是错误不断被抛出的原因。只需使用 start() 而不是创建新实例并调用 start() 即可解决问题!感谢您的帮助。
修改后的代码如下:
打包 GUI;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
public class Controller implements Initializable {
int secondspassed = 0;
int minutespassed = 0;
int hourspassed = 0;
@FXML
private Label XPTrackerlabel;
@FXML
private ProgressBar XPTracker;
@FXML
private ComboBox Minelocation;
@FXML
private Label clocker;
Timer timer = new Timer();
TimerTask ticktime = new TimerTask(){
public void run(){
secondspassed++;
if (secondspassed == 60){ secondspassed = 0; minutespassed++;}
else if (minutespassed == 60){ minutespassed = 0; hourspassed++;}
Platform.runLater(() -> clocker.setText(hourspassed + ":" + minutespassed + ":" + secondspassed));
}
};
public void start() {
timer.scheduleAtFixedRate(ticktime, 1000, 1000);
}
public void PressButton(ActionEvent event){
start();
System.out.println("Hello World");
}
@Override
public void initialize(URL url, ResourceBundle rb) {
Minelocation.getItems().addAll("North", "South", "North-East");
XPTracker.setProgress(0.5);
double XP = XPTracker.getProgress() * 100;
XPTrackerlabel.setText(XP + "%");
clocker.setText(hourspassed + ":" + minutespassed + ":" + secondspassed);
}
}