JavaFXでウィンドウにボタンを配置してクリックでメッセージを出力する

Java を勉強してみるぞシリーズ第 3 段。配置したボタンのアクションイベントでクリックを補足して、コンソールにメッセージを出力します。
関連記事
- 初めてJavaを触った人間がEclipseでJavaFXのGUIアプリを起動するまで
- JavaFX Scene BuilderでのContainers(土台)部の違いについて
- JavaFXでウィンドウにボタンを配置してクリックでメッセージを出力する ←NOW!
- JavaFXでインプットダイアログの結果をアラートで表示する
- JavaFXでテキストフィールドに値を入れたり取得したり
順番に見てもらったほうがわかりやすいと思います。
書いたときの環境
- JDK 8u121
- Eclipse4.6 NEON
- Scene Builder 8.3.0
- Windows7/10
です。
プロジェクトを作成

Eclipse にて、土台のコンテナを AnchorPane にした、新規 JavaFX Project を作成したところから始めます。

こんな構成。自動で作成されたものそのままです。
Main.java
package application; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage primaryStage) { try { AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("Form.fxml")); Scene scene = new Scene(root); scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm()); primaryStage.setScene(scene); primaryStage.setTitle("testJava"); primaryStage.show(); } catch(Exception e) { e.printStackTrace(); } } public static void main(String[] args) { launch(args); } }
Scene Builder での大きさを反映させるため、15行目のデフォルトで書いてあった 400×400 を消しておきます。
また、18行目のprimaryStage.setTitle
を追加しておくと、起動したフォームのタイトルに任意の文字列を表示することができます。
ボタンを配置
フォーム(という呼び方でいいのかちょっと不安ですが)にボタンを作りましょう。

Form.fxml を右クリックして、Scene Builder で開きます。

開きましたが…、これ、真ん中に AnchorPane が表示されていて欲しいですよね。これがちょっと、私の環境だけなのかよくわかんないのですが、デフォルトでは AnchorPane の大きさが明示的に指定されていないため出てこないっぽいです。

なので、左下の Document で AnchorPane を選択して、右側の Layout を開きます。

PrefWidth と PrefHeight のサイズを指定します。200 × 200 くらいにしてみましょうか。

そうすると、出ました! やったー。

この AnchorPane 上にボタンを配置します。Control から Button を選んでドラッグ。

ここで、いったん保存しましょう。File → Save からできますが、保存と言ったら Ctrl+S なので、いつもショートカットでやっちゃってます。
いったん動作検証
Eclipse に戻って、Form.fxml をダブルクリックしてコードを見てみましょう。
Form.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.Button?> <?import javafx.scene.layout.AnchorPane?> <AnchorPane prefHeight="200.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.FormController"> <children> <Button layoutX="73.0" layoutY="89.0" mnemonicParsing="false" text="Button" /> </children> </AnchorPane>
Scene Builder の変更が反映されれば、こんな感じのコードになっているはず。8行目にボタンが追加された記述があります。
実行
ではこのプロジェクトを実行して、実際にフォームにボタンが追加されているか見てみましょう。

Main.java を右クリックして、「実行」の「Javaアプリケーション」をクリックします。

出ました。Scene Builder で設定したとおりの大きさで、ボタンもちゃんとありますね。タイトルは、最初に Main.java で指定した文字列が表示されています。でもまだボタンは配置しただけなので、クリックしてもなんにも起こりません。
ボタンにアクションイベント名を設定
Scene Builder にて、ボタンのクリックを取得するために、イベント名をつけます。

ボタンを選択して、右側の Code の、On Action という項目に任意の文字列で設定します。
普段 VBA ばっかりさわってる私からすると「Button1_Click」とかいう名前にしちゃいそうなんですが、Javaっぽくないと思うので、ここでは「onButtonClick」という名前にしておきますね。
ちなみに、ひとつ上の fx:id というところでこのコントロールの名前をつけられるのですが、ボタンクリックに関してはコントロール名なしでも動いたので、今回は必要最低限に留めます。コントロールがテキストフィールドなどのときは、ここが必要になります。
これで Scene Builder を保存します。

保存が反映されると、Eclipse 側の Form.fxml にも「On Action」が追加されるのですが、図のように赤くエラーになります。これは、「アクションイベントが設定されてるけど、これに対するイベントの記述がないよー!」と言ってるんですね。まだ書いてないですからね。
アクションイベントの枠組を作る
アクションイベントは、FormController.java に書きます。

この時点では、まだデフォルト状態で、こんな感じです。この FormController クラスの中に、下記の 5 ~ 8 行を追記します。
package application; public class FormController { @FXML protected void onButtonClick(ActionEvent evt) { } }
5 行目の「@FXML」は、「ここから書くコードに対して、JavaFX の部品を使いますよ」という意味で、6 ~ 8 行目がアクションイベントのブロックとなります。

そしたら、エラーが複数出てしまいました…! コントロールを使用するには、そのための設定も書かなければならないのですが、それがないよー! と言っているんです。

細々した設定の記述は Eclipse の機能を使うと、とっても便利です。エラーになっている 5 行目に、マウスを載せてみましょう。表示されたボックスから、「’FXML’ をインポートします」をクリックします。

すると、自動的にimport
の記述が追加され、@FXML 部分のエラーが消えました! さすがの補完機能ですねー!

同じように、「ActionEvent」部分もオンマウスで設定の記述を入れましょう。

インポートの記述が追加され、これでエラーがすべて消えました。

FormController.java にアクションイベントに対する記述が書かれたので、Form.fxml の「onAction」部分のエラーも消えました!
アクションイベントの中身を書く
これで、「ボタンをクリックしたら何かが起こる」ための枠組ができましたが、中身を書かないことには何も起きないですよね。
FormController.java
package application; import javafx.event.ActionEvent; import javafx.fxml.FXML; public class FormController { @FXML protected void onButtonClick(ActionEvent evt) { System.out.println("クリックされました!"); } }
アクションイベント「onButtonClick」の中に、上記のように書いてみます。まずは一番シンプルに、コンソールに文字列を出力してみましょう。
動作検証
Main.java を実行します。

ボタンをクリックしてみましょう。

Eclips のコンソールに、コード内に書いた文字列が出力されました。
今回はここまで。今度はボタンクリックでダイアログとか出したいと思ってます。
参考リンク
今回の記事を書くにあたって、こちらのサイトをめちゃくちゃ参考にさせていただきました。ありがとうございました! 不適切な部分や間違ってるぞコノヤロウ的なところがありましたらご指摘ください。
コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)
YouTubeでQ&Aコンテンツを企画しています
運営しているYouTubeチャンネルで、ご相談やご質問を募集しています。動画のコメントやお問い合わせページからお気軽にご相談をお寄せください。