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

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

JavaFX:FXMLからイベント処理すると実行エラー!FXMLに書き忘れていたこと

      2017/05/09

前回、Sene Builderで作ったUI(FXML)をJavaFXで表示させました。

実行するとこんな感じ↓になるやつです。ボタンを押してもイベントは発生せずただ表示するだけのプログラムでした。

 

で、次にやろうとしたことは、ボタンクリックで何かのイベントを発生させること。まあ、そこは楽勝と思ってやってみたのですが、結果、すげー難航しました

意味不明の実行エラーばかりでプログラム動かず、ググっても解決できず。

で、結局動いたのですが、FXMLにあることを書き忘れた(Scene Builderで設定し忘れた)ために起きたエラーでした。その経緯含め書き留めておきます。

[ad#top-1]

まずはエラーまでの軌跡

前回作ったScene Builderのボタンイベントを設定しました。

ボタンを選択して、On Actionの欄にコールバック関数名を記載(clickBtnとしました)して保存。

 

保存したFXMLの中身を見るとこんな感じです。

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
  prefHeight="100.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
  <children>
    <Label layoutX="46.0" layoutY="26.0" text="Hello World">
      <font>
        <Font name="Meiryo UI" size="36.0" />
      </font>
    </Label>
    <Button layoutX="267.0" layoutY="31.0" mnemonicParsing="false" onAction="#clickBtn" prefHeight="19.0" prefWidth="95.0" text="OK">
      <font>
        <Font size="18.0" />
      </font>
    </Button>
  </children>
</AnchorPane>
 

 

Buttonタグ内に「onAction=”#clickBtn”」が追加されました。

JavaFX側は以下の通りです。//追加 と書かれているところが前回から追加したところになります。

import javafx.application.Application;
import javafx.fxml.*;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.AnchorPane;
import javafx.event.ActionEvent; //追加

public class Hello extends Application {
  @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, 400, 100));
    primaryStage.show();
  }

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

  //追加
  @FXML
  public void clickBtn(ActionEvent e) {
    System.out.println("OK");
  }
}
 

 

Scene Builder で設定したコールバック関数clickBtnを追記してボタンを押したら、コンソール上にOKと表示されるようになっています(・・・のつもりでした)。

 

で、実行したらエラー発生。なぜだ?

コンパイルして(コンパイルは普通に通りました)、実行したところ、以下のように実行エラーが発生して実行できず。

 

InvocationTargetExceptionという例外が発生しているみたいですが、調べても謎。なんとなくFXMLの呼び出しエラーっぽい感じに読み取れましたが、イベント処理させなかったときは普通に読み込めたし。

エラーの発生個所もFXMLファイルの19行目となっていましたが、その行は</Button>とタグを閉めている行。意味不明です。

ググってもググっても解決策が見つからず、もうこりゃダメか??とあきらめかけていたところ・・・。

 

英語サイトで問題個所発見!

日本語サイトではもうダメだと思って(それこそQiita見てもわからず)、英語サイトに活路を見出しました。(英語苦手だけど)

そしたら、それらしき記述発見!

 

投稿者はまさに僕と同じ問題にぶち当たっていたようです。おぉ、これだ!と思って、回答を見てみると、※文字色の赤に注目

The error says it, the FXML is missing the fx:controller declaration. Add the controller declaration to BorderPane. declaration as shown :


<BorderPane maxHeight=”1.7976931348623157E308″
maxWidth=”1.7976931348623157E308″ prefHeight=”400.0″
prefWidth=”600.0″ xmlns=”http://javafx.com/javafx/8″
xmlns:fx=”http://javafx.com/fxml/1″
fx:controller=”Weert.Controller”>

fx:controllerではクラス名を明示させているようです。で、僕のFXMLを見ると、AchorPaneタグにfx:controllerがないではないですか。

早速、手書きで追記しました。

 

再度コンパイルして実行

見事、実行しました。ボタンを押すとコンソールにOKと表示されています。

 

イベント処理する場合はクラスとの紐づけが必要だったんですね。そのほか、コントロールをjavaファイル内で使用する場合も紐づけが必須だったみたいです。

ありがとう!stack overflowに回答してくれたItachiUchihaさん。アイコンがクレヨンしんちゃんだけどJapan通なのかな?

 

Scene Builderのどこで設定するのか?

で、Scene builderのどこで設定するのかというと、左下のControllerというタグの中にありました。Controller classというところに、クラス名を入力すればOKです。これを最初にやるべきだったんですが、知りませんでした。

 

雑感とか反省とか

  1. JavaFXに関してネットで日本語情報が少ない。
  2. やっぱ、JavaFXはプログラミング言語としてあんまり人気ないみたい。
  3. こういう場合は英語サイト読めないとな~
  4. FXMLに問題があった場合、コンパイルでは拾ってくれないみたい。且つ、実行エラー文を読むだけでは問題個所に到達しにくい。
  5. それだけに、構文ミスが出ないようScene Builderの使用は必須。且つ、正しく使わないと(反省)。
  6. 今回の問題はScene Builder+EclipseみたいなIDEと併用すれば発生しなかったかも。
  7. でも、IDEは嫌いなのであんまり使いたくない。
  8. しばらく、Scene Builder+テキストエディタでがんばってみて、ダメそうならEclipseかNetBeansの導入を考えよう。

次はFXMLで作成したコントロールをJava側で制御する方法です。

[ad#ad-1]

スポンサーリンク

 - Java