【问题标题】:Why is my JavaFX label being marked as null despite declaring it within the JavaFX Application thread?尽管在 JavaFX 应用程序线程中声明了我的 JavaFX 标签,为什么它仍被标记为 null?
【发布时间】:2019-05-22 21:53:37
【问题描述】:

我正在尝试创建一个时钟,通过使用每秒更改的动态 UI 标签来监视程序的运行时间。我尝试使用以下代码,但不断收到空指针异常。此异常源于 JavaFX 应用程序线程上似乎为空的“时钟”标签,尽管已在控制器类中声明它。我还实现了 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$1.lambda$run$0(Controller.java:38)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(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$147(WinApplication.java:177)
    at java.lang.Thread.run(Unknown Source)

【问题讨论】:

  • Controller.java:38 处抛出异常。请将此行标记为注释,以便我们知道哪一行是 38。
  • 尝试在initialize 方法中初始化ticktime
  • PressButton 中创建Controller 的新实例,而不是通过FXMLLoader 加载。这可能是您问题的根源。
  • 参见例如this question's answer了解更多信息。

标签: java javafx java-8 label scenebuilder


【解决方案1】:

事实证明 Itai 是对的,出于某种原因,我认为在 Pressbutton 中创建一个新的控制器实例是个好主意,这就是错误不断抛出的原因。只需使用 start() 而不是创建新实例并调用 start() 即可解决问题!感谢您的帮助。

这是修改后的代码:

包图形界面;

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);
    }
}

【讨论】:

    猜你喜欢
    • 2016-01-11
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    相关资源
    最近更新 更多