JavaFX でさらに足し算のお勉強
前回のプログラムを利用して今回も JavaFX で足し算アプリに手を加えてみることにしました。
今回追加する機能は アプリのウィンドウサイズの変更をできないようにする。
チェックボックスを利用して BGM を流せるようにする。
問題の難易度を選択できるようにトグルボタンを排他制御して可能にする。
ツールチップを設定する。
ニーモニックを設定する。
結局、こんな感じにできあがりました。
トグルボタンは私の実力ではニーモニックを正しく動作させることができなかったので諦めました。(>_<。)
素直にラジオボタンを使えばよかったかも・・・
トグルボタンの排他制御のイベント処理はかなり怪しいことをしています。
我ながらこれは無いだろうと思いながら他に良い方法を知らないので動けばいいやってのりでやってます。(オヒ
だからニーモニックが・・・・・ とどのつまりラジオボタンを使おう、今度からは。
いちおう、なんとか動いたので良しとしました。(^_^;)
それではそんなこんなでいい加減ですがプログラムを晒しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
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<Boolean>() { 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; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.geometry.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.text.*?> <AnchorPane id="AnchorPane" maxHeight="-1.0" maxWidth="-1.0" minHeight="160.0" minWidth="320.0" prefHeight="160.0" prefWidth="320.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="jp.yucchi.calc.CalcFormController"> <children> <VBox prefHeight="-1.0" prefWidth="-1.0" AnchorPane.bottomAnchor="12.0" AnchorPane.leftAnchor="12.0" AnchorPane.rightAnchor="12.0" AnchorPane.topAnchor="12.0"> <children> <AnchorPane prefHeight="47.0" prefWidth="-1.0"> <children> <Label fx:id="questionLabel" prefHeight="30.0" prefWidth="184.0" text="" AnchorPane.leftAnchor="5.0" AnchorPane.topAnchor="10.0"> <font> <Font size="16.0" fx:id="x1" /> </font> </Label> <TextField fx:id="answerField" alignment="CENTER_RIGHT" onAction="#handleAnswer" prefHeight="30.0" prefWidth="95.0" text="" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="10.0"> <tooltip> <Tooltip text="半角 0 ~ 9 で入力してね!" /> </tooltip> </TextField> </children> </AnchorPane> <HBox alignment="CENTER_RIGHT" prefHeight="47.0" prefWidth="296.0"> <children> <ToggleButton fx:id="easy" mnemonicParsing="false" onAction="#handleEasy" prefWidth="65.0" selected="true" text="Easy" wrapText="false"> <toggleGroup> <ToggleGroup fx:id="mode" /> </toggleGroup> <tooltip> <Tooltip text="2桁以内の足し算" /> </tooltip> <HBox.margin> <Insets /> </HBox.margin> </ToggleButton> <ToggleButton fx:id="normal" mnemonicParsing="false" onAction="#handleNormal" prefWidth="65.0" text="Normal" toggleGroup="$mode"> <tooltip> <Tooltip text="3桁以内の足し算" /> </tooltip> <HBox.margin> <Insets left="5.0" fx:id="x2" /> </HBox.margin> </ToggleButton> <ToggleButton fx:id="hard" mnemonicParsing="false" onAction="#handleHard" prefWidth="65.0" selected="false" text="Hard" textAlignment="LEFT" toggleGroup="$mode" HBox.margin="$x2"> <tooltip> <Tooltip text="5桁以内の足し算" /> </tooltip> </ToggleButton> </children> </HBox> <HBox alignment="CENTER_RIGHT" prefHeight="47.0" prefWidth="296.0" spacing="12.0"> <children> <Button fx:id="clearButton" mnemonicParsing="true" onAction="#handleClear" text="_Clear"> <tooltip> <Tooltip text="次の問題" /> </tooltip> </Button> <Button fx:id="answerButton" mnemonicParsing="true" onAction="#handleAnswer" text="_Answer"> <tooltip> <Tooltip text="ファイナルアンサー?" /> </tooltip> </Button> </children> <padding> <Insets /> </padding> </HBox> </children> </VBox> <Label fx:id="resultLabel" prefHeight="30.0" prefWidth="-1.0" text="" textFill="RED" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="110.0"> <font> <Font size="20.0" /> </font> </Label> <CheckBox fx:id="bgmCheck" alignment="CENTER_LEFT" allowIndeterminate="false" contentDisplay="LEFT" mnemonicParsing="true" selected="false" text="_BGM" textAlignment="LEFT" AnchorPane.leftAnchor="5.0" AnchorPane.topAnchor="73.0"> <font> <Font size="14.0" /> </font> <tooltip> <Tooltip text="BGM 設定" /> </tooltip> </CheckBox> </children> </AnchorPane> |
アプリのウィンドウサイズの変更をできないようにするために 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
ちょっと五月蠅くなってしまいましたがご勘弁を。
もっといろいろ楽しいことが出来るようなのでボチボチと遊んでみたいと思ってます。
TAGS: JavaFX,NetBeans | 2013年8月6日11:03 PM | Comment : 1