非IT企業に勤める中年サラリーマンのIT日記

非IT企業でしかもITとは全く関係ない部署にいる中年エンジニア。唯一の趣味がプログラミングという”自称”プログラマー。

JavaFX/FXML: startメソッド内でsetText()が使えない!その対処法

      2017/07/24

JavaFXの書籍があまりないということもあって、ちょっと躓くと解決するまで時間がかかります。更にFXMLを使うとコンパイルで検知できず実行エラーになる上に、実行エラーの内容もよくわかりません。

今回僕もFXML関係でちょっと躓いて、なんとか解決できたのでシェアしておきます。

 

startメソッド内でLabelの文字列を変えたら実行エラー!

Scene BuilderでこんなUIを作ったとして、アプリ起動と共にLabelの「Hello World」が「こんにちは世界」に切り替わるようにしたいとします。Labelのidをlabelとしています。ボタンはありますが、今回ボタンイベントはありません。

 

で、そのために作ったコードが以下の通り。一見ちゃんと動きそうですが、これでは19行目で実行エラーが発生します。なぜでしょう??

import javafx.application.Application;
import javafx.fxml.*;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.AnchorPane;
import javafx.event.ActionEvent;
import javafx.scene.control.*;

public class Hello extends Application {
  @FXML private Label label;

  @Override
  public void start(Stage primaryStage) throws Exception{
    AnchorPane root = FXMLLoader.load(getClass().getResource("Hello.fxml"));
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root));
    primaryStage.show();

    label.setText("こんにちは世界"); //ここで実行エラー
  }

  public static void main(String[] args) {
    launch(args);
  }
}
 

 

Labelに書き込みたいのはボタンイベントの時ではなく、アプリ起動時です。

なので、最初に呼び出されるstartメソッドにそのコードを書きこんだのですがダメなのです。

[ad#top-1]

Initializableインターフェースを使う!

おそらくですが、startメソッド時はまだUIが初期化されていないタイミングなのでしょう。だからエラーが発生すると想像はできます。

ということは、UIがFXMLから読み込まれて初期化した後に発生するイベントがどこかにあるはずです。

それを探すのに結構時間がかかりました。ググってもなかなか現れないという…。

その答えは、Initializableインターフェースを実装してinitializeメソッドをオーバーライドする、そのinitializeメソッドにUIへの指示を書けばOKなのです。

import javafx.application.Application;
import javafx.fxml.*;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.AnchorPane;
import javafx.event.ActionEvent;
import javafx.scene.control.*;

public class Hello extends Application implements Initializable {
  @FXML private Label label;

  @Override
  public void start(Stage primaryStage) throws Exception{
    AnchorPane root = FXMLLoader.load(getClass().getResource("Hello.fxml"));
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root));
    primaryStage.show();
  }

  //↓これ
  @Override
  public void initialize(java.net.URL url, java.util.ResourceBundle bundle) {
    label.setText("こんにちは世界");
  }

  public static void main(String[] args) {
    launch(args);
  }
}
 

 

ちゃんと実行できました。

 

FXMLを使う場合、startメソッド内にコントロールの制御をやっちゃダメなんですね。一つ勉強になりました。

[ad#ad-1]

スポンサーリンク

 - Java