前回のプログラムを利用して今回も JavaFX で足し算アプリに手を加えてみることにしました。
今回追加する機能は アプリのウィンドウサイズの変更をできないようにする。
チェックボックスを利用して BGM を流せるようにする。
問題の難易度を選択できるようにトグルボタンを排他制御して可能にする。
ツールチップを設定する。
ニーモニックを設定する。
結局、こんな感じにできあがりました。




トグルボタンは私の実力ではニーモニックを正しく動作させることができなかったので諦めました。(>_<。)
素直にラジオボタンを使えばよかったかも・・・
トグルボタンの排他制御のイベント処理はかなり怪しいことをしています。
我ながらこれは無いだろうと思いながら他に良い方法を知らないので動けばいいやってのりでやってます。(オヒ
だからニーモニックが・・・・・ とどのつまりラジオボタンを使おう、今度からは。
いちおう、なんとか動いたので良しとしました。(^_^;)
それではそんなこんなでいい加減ですがプログラムを晒しておきます。
package jp.yucchi.calc;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Calc2 extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("CalcForm.fxml"));
Scene scene = new Scene(root);
stage.setTitle("足し算できますか?");
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
package jp.yucchi.calc;
import java.awt.Toolkit;
import static java.lang.Integer.parseInt;
import java.net.URL;
import java.util.Random;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class CalcFormController implements Initializable {
private int x;
private int y;
private int resultAnswer;
private int modeNumber = 99;
Random rnd = new Random();
private final Media start = new Media(getClass().getResource("start.mp3").toExternalForm());
private final Media ok = new Media(getClass().getResource("ok.mp3").toExternalForm());
private final Media ng = new Media(getClass().getResource("ng.mp3").toExternalForm());
private final Media bgm = new Media(getClass().getResource("bgm.mp3").toExternalForm());
private final Media m_easy = new Media(getClass().getResource("easy.mp3").toExternalForm());
private final Media m_normal = new Media(getClass().getResource("normal.mp3").toExternalForm());
private final Media m_hard = new Media(getClass().getResource("hard.mp3").toExternalForm());
@FXML
private Label questionLabel;
@FXML
private TextField answerField;
@FXML
private Label resultLabel;
@FXML
CheckBox bgmCheck;
@FXML
ToggleGroup mode;
@FXML
ToggleButton easy;
@FXML
ToggleButton normal;
@FXML
ToggleButton hard;
@FXML
public void handleAnswer(ActionEvent event) {
Pattern intPattern = Pattern.compile("[0-9]+");
Matcher match = intPattern.matcher(answerField.getText());
if (match.matches() != false || answerField.getText().isEmpty()) {
} else {
resultLabel.setText("数値を入力してね!");
Toolkit.getDefaultToolkit().beep();
}
if (answerField.getText().isEmpty()) {
resultLabel.setText("答えを入力してね!");
Toolkit.getDefaultToolkit().beep();
} else {
boolean result = calc(answerField.getText());
if (result) {
resultLabel.setText("正解!");
MediaPlayer mp_ok = new MediaPlayer(ok);
mp_ok.play();
} else {
resultLabel.setText("不正解!");
MediaPlayer mp_ng = new MediaPlayer(ng);
mp_ng.play();
}
}
}
@FXML
public void handleClear(ActionEvent event) {
answerField.clear();
resultLabel.setText(null);
x = rnd.nextInt(modeNumber) + 1;
y = rnd.nextInt(modeNumber) + 1;
resultAnswer = x + y;
questionLabel.setText(" " + x + " + " + y + " = ");
}
@FXML
public void handleEasy(ActionEvent event) {
if (easy.isSelected()) {
modeNumber = 99;
answerField.clear();
resultLabel.setText(null);
x = rnd.nextInt(modeNumber) + 1;
y = rnd.nextInt(modeNumber) + 1;
resultAnswer = x + y;
questionLabel.setText(" " + x + " + " + y + " = ");
MediaPlayer mp_easy = new MediaPlayer(m_easy);
mp_easy.play();
} else {
easy.setSelected(true);
}
}
@FXML
public void handleNormal(ActionEvent event) {
if (normal.isSelected()) {
modeNumber = 999;
answerField.clear();
resultLabel.setText(null);
x = rnd.nextInt(modeNumber) + 1;
y = rnd.nextInt(modeNumber) + 1;
resultAnswer = x + y;
questionLabel.setText(" " + x + " + " + y + " = ");
MediaPlayer mp_normal = new MediaPlayer(m_normal);
mp_normal.play();
} else {
normal.setSelected(true);
}
}
@FXML
public void handleHard(ActionEvent event) {
if (hard.isSelected()) {
modeNumber = 99999;
answerField.clear();
resultLabel.setText(null);
x = rnd.nextInt(modeNumber) + 1;
y = rnd.nextInt(modeNumber) + 1;
resultAnswer = x + y;
questionLabel.setText(" " + x + " + " + y + " = ");
MediaPlayer mp_hard = new MediaPlayer(m_hard);
mp_hard.play();
} else {
hard.setSelected(true);
}
}
@Override
public void initialize(URL url, ResourceBundle rb) {
x = rnd.nextInt(modeNumber) + 1;
y = rnd.nextInt(modeNumber) + 1;
resultAnswer = x + y;
questionLabel.setText(" " + x + " + " + y + " = ");
MediaPlayer mp_start = new MediaPlayer(start);
mp_start.play();
bgmCheck.selectedProperty().addListener(new ChangeListener() {
MediaPlayer mp_bgm;
@Override
public void changed(ObservableValue extends Boolean> ov, Boolean oldVal, Boolean newVal) {
if (newVal.booleanValue()) {
mp_bgm = new MediaPlayer(bgm);
mp_bgm.setVolume(0.07);
mp_bgm.play();
mp_bgm.setCycleCount(MediaPlayer.INDEFINITE);
} else {
mp_bgm.stop();
}
}
});
}
private boolean calc(String ans) {
int answer = parseInt(ans);
return answer == resultAnswer;
}
}
アプリのウィンドウサイズの変更をできないようにするために Calc2.java の 19 行目で
stage.setResizable(false);
としています。
チェックボックスを利用して BGM を流せるようにするために CalcFormController.java の 163 行目から 178 行目までで
チェックボックスにリスナーを設定して制御しています。
トグルボタンはグループ化して排他制御可能としてます。
これは JavaFX Scene Builder を使って簡単に設定できます。
トグルボタンのイベントをそれぞれ実装して JavaFX Scene Builder で結びつければいいだけです。
トグルボタンのグループも JavaFX Scene Builder で簡単に設定できます。便利!便利!
ただ前述したとおりトグルボタンが必ずどれか一つ選択状態にあるようにしたいため適当なことをやっています。
おそらく、なんだこれは?といいたくなるかもしれませんがスマートな方法を知らないのでこうなりました。(^_^;)
よってトグルボタンにニーモニックを設定しても上手く動作しなくなります。だからニーモニックはあきらめました。(ヲヒ
チェックボックス、テキストフィールド、ボタンにはニーモニックを JavaFX Scene Builder で簡単に設定できます。
プロパティの Text 欄に _ を先頭につけて記入し(_BGM)

Mnemonic Parsing のチェックボックスを ON にすればいいだけです。

ツールチップも同様に JavaFX Scene Builder を使えば楽勝です!
JavaFX Scene Builder のライブラリ Popup Controls から Tooltip をドラッグアンドドロップして
プロパティを設定してやればいいだけという非常に楽ちんな作業です。

以上、こんな感じでできあがりました。
Webstart: click to launch this app as webstart
ちょっと五月蠅くなってしまいましたがご勘弁を。
もっといろいろ楽しいことが出来るようなのでボチボチと遊んでみたいと思ってます。
