yamaken1343’s blog

技術ブログもどき

JavaFXで時間管理タイマーを作る [まとめ]

まとめです

yamaken1343.hatenablog.jp

yamaken1343.hatenablog.jp

yamaken1343.hatenablog.jp

yamaken1343.hatenablog.jp

yamaken1343.hatenablog.jp

yamaken1343.hatenablog.jp

yamaken1343.hatenablog.jp

github.com

今後の予定

  • 見た目を何とかする - 達成
  • ログの出力とか実装
  • ステータスバーに情報を出したい
  • ダイアログとかどうやって出すか勉強したい
  • twitterにつぶやきたい

感想

  • Qtにくらべると随分素直で書きやすい
  • 情報が少ない
  • IntelliJ IDEAは神。これの補完ですべてを書いた

JavaFXで時間管理タイマーを作る [時刻編]

yamaken1343.hatenablog.jp

Java日付時刻APIメモ(Hishidama's Java8 Date and Time API Memo)

qiita.com

このサイトを参考に時刻関連の実装を行う

仕様変更

  • らぼりだ時刻は普段使われないので現在時刻を表示する。

コード(追加部分)

    private LocalDateTime dt;
    private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd HH:mm:ss");

    private Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), //時間経過をトリガにするのはTimelineクラスを使う
                new EventHandler<ActionEvent>() {
                    public void handle(ActionEvent actionEvent) { //ここに書いた処理がDuration.seconds(1)で示した感覚で実行される

                        dt = LocalDateTime.now();
                        nowTime.setText(dt.format(dtf));

                    }
                }
        )
    );

    public void mainButtonClick(ActionEvent actionEvent) {
        if (mainTimer.getStatus()){ //タイマーが動作中のクリック

            nowTimeLabel.setText("らぼりだ: ");

            dt = LocalDateTime.now();
            nowTime.setText(dt.format(dtf));


        }else { //タイマーが動作していない

            dt = LocalDateTime.now();
            inDate.setText(dt.format(dtf));
            nowTimeLabel.setText("現在時刻: ");

        }

    }

成果物

f:id:yamaken1343:20180424125125p:plain f:id:yamaken1343:20180424125143p:plain f:id:yamaken1343:20180424125153p:plain

github.com

一応完成ということにします

yamaken1343.hatenablog.jp

JavaFXで時間管理タイマーを作る [ボタン編]

yamaken1343.hatenablog.jp

ボタンを押したら実際に動作するところまで作ります。

コード

Controller クラス

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.util.Duration;
import javafx.scene.control.Label;

import java.net.URL;
import java.util.ResourceBundle;

import static javafx.animation.Animation.INDEFINITE;

public class Controller implements Initializable {
    private LabT mainTimer = new LabT();
    private LabT allTimer = new LabT();
    private LabT researchTimer = new LabT();
    private LabT restTimer = new LabT();
    private LabT otherTimer = new LabT();

    private Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), //時間経過をトリガにするのはTimelineクラスを使う
                new EventHandler<ActionEvent>() {
                    public void handle(ActionEvent actionEvent) { //ここに書いた処理がDuration.seconds(1)で示した感覚で実行される
                        mainTimer.timeCount();
                        allTimer.timeCount();
                        researchTimer.timeCount();
                        restTimer.timeCount();
                        otherTimer.timeCount();

                        mainTimerLabel.setText(mainTimer.formatPrint());
                        allTimerLabel.setText(allTimer.formatPrint());
                        childTimerLabel1.setText(researchTimer.formatPrint());
                        childTimerLabel2.setText(restTimer.formatPrint());
                        childTimerLabel3.setText(otherTimer.formatPrint());
                    }
                }
        )
    );

    @FXML
    private Label mainTimerLabel;
    @FXML
    private Label allTimerLabel;
    @FXML
    public Label childTimerLabel1;
    @FXML
    public Label childTimerLabel2;
    @FXML
    public Label childTimerLabel3;
    @FXML
    public Button mainButton;
    @FXML
    public Label statusLabel;

    public Controller() {

    }

    public void button1Click(ActionEvent actionEvent) {
        researchTimer.active();
        restTimer.inactive();
        otherTimer.inactive();

        mainTimer.reset();
        mainTimerLabel.setText(mainTimer.formatPrint()); //0に戻ったことを表示
        statusLabel.setText("研究中");

    }

    public void button2Click(ActionEvent actionEvent) {
        researchTimer.inactive();
        restTimer.active();
        otherTimer.inactive();

        mainTimer.reset();
        mainTimerLabel.setText(mainTimer.formatPrint());
        statusLabel.setText("休憩中");

    }

    public void button3Click(ActionEvent actionEvent) {
        researchTimer.inactive();
        restTimer.inactive();
        otherTimer.active();

        mainTimer.reset();
        mainTimerLabel.setText(mainTimer.formatPrint());
        statusLabel.setText("その他動作中");

    }

    public void mainButtonClick(ActionEvent actionEvent) {
        if (mainTimer.getStatus()){ //タイマーが動作中のクリック

            researchTimer.inactive(); //タイマーがstop時、全部非アクティブ前提
            restTimer.inactive();
            otherTimer.inactive();
            allTimer.inactive();
            mainTimer.inactive();

            timeline.stop();

            mainButton.setText("らぼいん");
            statusLabel.setText("らぼりだ中");


        }else { //タイマーが動作していない
            mainButton.setText("らぼりだ");

            researchTimer.reset();
            restTimer.reset();
            otherTimer.reset();
            allTimer.reset();
            mainTimer.reset();

            mainTimerLabel.setText(mainTimer.formatPrint()); //0に戻ったことを表示
            allTimerLabel.setText(allTimer.formatPrint());
            childTimerLabel1.setText(researchTimer.formatPrint());
            childTimerLabel2.setText(restTimer.formatPrint());
            childTimerLabel3.setText(otherTimer.formatPrint());

            mainTimer.active();
            allTimer.active();
            button1Click(null); //らぼいん初回は研究中とする

            timeline.setCycleCount(INDEFINITE); //何回繰り返すか指定する
            timeline.play();

        }

    }
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        mainTimerLabel.setText(mainTimer.formatPrint());
        allTimerLabel.setText(allTimer.formatPrint());
        childTimerLabel1.setText(researchTimer.formatPrint());
        childTimerLabel2.setText(restTimer.formatPrint());
        childTimerLabel3.setText(otherTimer.formatPrint());
        mainButton.setText("らぼいん");
        statusLabel.setText("らぼりだ中");
    }

}

fxml

<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<GridPane fx:controller="Controller"
          xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <Label text="らぼいん: " GridPane.rowIndex="0" GridPane.columnIndex="0"/>
    <Label fx:id="inDate" text="dummy" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
    <Label text="らぼりだ: " GridPane.rowIndex="0" GridPane.columnIndex="2"/>
    <Label fx:id="outDate" text="dummy" GridPane.rowIndex="0" GridPane.columnIndex="3"/>
    <Label text="らぼ時間" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
    <Label fx:id="allTimerLabel" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
    <Label text="研究時間: " GridPane.rowIndex="3" GridPane.columnIndex="0"/>
    <Label fx:id="childTimerLabel1" GridPane.rowIndex="3" GridPane.columnIndex="1"/>
    <Label text="休憩時間: " GridPane.rowIndex="4" GridPane.columnIndex="0"/>
    <Label fx:id="childTimerLabel2" GridPane.rowIndex="4" GridPane.columnIndex="1"/>
    <Label text="その他時間: " GridPane.rowIndex="5" GridPane.columnIndex="0"/>
    <Label fx:id="childTimerLabel3" GridPane.rowIndex="5" GridPane.columnIndex="1"/>
    <Label text="状態: " GridPane.rowIndex="6" GridPane.columnIndex="0"/>
    <Label fx:id="statusLabel" text="dummy" GridPane.rowIndex="6" GridPane.columnIndex="1"/>
    <Label fx:id="mainTimerLabel" GridPane.rowIndex="7" GridPane.columnIndex="1"/>
    <Button fx:id="mainButton" GridPane.rowIndex="8" GridPane.columnIndex="0" onAction="#mainButtonClick"/>
    <Button fx:id="childButton1" text="研究" GridPane.rowIndex="8" GridPane.columnIndex="1" onAction="#button1Click"/>
    <Button fx:id="childButton2" text="休憩" GridPane.rowIndex="8" GridPane.columnIndex="2" onAction="#button2Click"/>
    <Button fx:id="childButton3" text="その他" GridPane.rowIndex="8" GridPane.columnIndex="3" onAction="#button3Click"/>


</GridPane>

解説

前回からの変更点

  • コンストラクタに処理を書いていたのを対応したボタンとイニシャライザに割り当てた
  • ボタンにonActionを追加

ボタンのクリックと関数について

  • fxmlで作成したボタンをクリックするとonActionに対応した関数が実行される
  • なのでボタンクリック時に実行したい処理を対応した関数内に書いていく
  • 引数には何が入るのかは勉強不足により不明

mainButtonClick

  • トグル的な動作をさせたいのでif文で動作を切り替えるようにしている
  • ボタンと対応させた関数も普通に呼び出すことができる

initializeのoverride

  • initializeをオーバーライドすることで起動時に行われる処理を新たに記述することができる
  • 使用にはInitializableの継承が必要

成果画面

f:id:yamaken1343:20180419161645p:plainf:id:yamaken1343:20180419161657p:plainf:id:yamaken1343:20180419161702p:plain

次回は日付部分実装したい

JavaFXで時間管理タイマーを作る [タイマー編]

yamaken1343.hatenablog.jp

時間経過に応じてカウントがインクリメントされて表示されるためのコア部分を作成する

コード(抜粋)

private LabT mainTimer = new LabT();
private LabT allTimer = new LabT();
private LabT researchTimer = new LabT();
private LabT restTimer = new LabT();
private LabT otherTimer = new LabT();

@FXML
private Label mainTimerLabel;
//略

private Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), //時間経過をトリガにするのはTimelineクラスを使う
         new EventHandler<ActionEvent>() {
            public void handle(ActionEvent actionEvent) { //ここのブロック内に書いた処理がDuration.seconds()で示した感覚で実行される。今回は1秒
                mainTimer.timeCount(); //一括でタイマーのカウントアップを命令する
                allTimer.timeCount();
                researchTimer.timeCount();
                restTimer.timeCount();
                otherTimer.timeCount();

                mainTimerLabel.setText(mainTimer.formatPrint()); //表示の更新
                allTimerLabel.setText(allTimer.formatPrint());
                childTimerLabel1.setText(researchTimer.formatPrint());
                childTimerLabel2.setText(restTimer.formatPrint());
                childTimerLabel3.setText(otherTimer.formatPrint());
            }
        }
));

public Controller() { //コンストラクタ
        mainTimer.active(); //カウントアップしたいタイマーのみをアクティブにする
        allTimer.active();
        researchTimer.active();

        timeline.setCycleCount(INDEFINITE); //何回繰り返すか指定する。INDEFINITEで制限なし
        timeline.play(); //動作開始
}

解説

  • コンストラクタでカウントアップしたいタイマーのみをアクティブにしLabT.statusをTrueにする、時間経過で周期的な処理を行うtimelineインスタンスを起動する
  • timelineインスタンス内で各タイマーのカウントアップ命令を行う。このとき、LabT.statusがTrueのもののみ実際にカウントアップされる。
  • 指定したラベルにタイマーの値がセットされ、表示される
  • 1秒毎に繰り返される

yamaken1343.hatenablog.jp

JavaFXで時間管理タイマーを作る [見た目編]

前回の記事

yamaken1343.hatenablog.jp

fxmlファイルをいじってどういった見た目になるか規定していきます。

コード

  • GridPaneに配置すれば格子状に配列されるらしい
  • 要素は揃ったけど見た目的にはダサいのでなんとかしたい
  • テキストは適当においた(参考: らぼったあ | としつーる
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<GridPane fx:controller="Controller"
          xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <Label text="らぼいん: " GridPane.rowIndex="0" GridPane.columnIndex="0"/>
    <Label fx:id="inDate" text="dummy" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
    <Label text="らぼりだ: " GridPane.rowIndex="0" GridPane.columnIndex="2"/>
    <Label fx:id="outDate" text="dummy" GridPane.rowIndex="0" GridPane.columnIndex="3"/>
    <Label text="らぼ時間" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
    <Label fx:id="allTimerLabel" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
    <Label text="研究時間: " GridPane.rowIndex="3" GridPane.columnIndex="0"/>
    <Label fx:id="childTimerLabel1" GridPane.rowIndex="3" GridPane.columnIndex="1"/>
    <Label text="休憩時間: " GridPane.rowIndex="4" GridPane.columnIndex="0"/>
    <Label fx:id="childTimerLabel2" GridPane.rowIndex="4" GridPane.columnIndex="1"/>
    <Label text="その他時間: " GridPane.rowIndex="5" GridPane.columnIndex="0"/>
    <Label fx:id="childTimerLabel3" GridPane.rowIndex="5" GridPane.columnIndex="1"/>
    <Label text="状態: " GridPane.rowIndex="6" GridPane.columnIndex="0"/>
    <Label fx:id="statusLabel" text="dummy" GridPane.rowIndex="6" GridPane.columnIndex="1"/>
    <Label fx:id="mainTimerLabel" GridPane.rowIndex="7" GridPane.columnIndex="1"/>
    <Button fx:id="mainButton" text="らぼいん/らぼりだ" GridPane.rowIndex="8" GridPane.columnIndex="0"/>
    <Button fx:id="childButton1" text="研究" GridPane.rowIndex="8" GridPane.columnIndex="1"/>
    <Button fx:id="childButton2" text="休憩" GridPane.rowIndex="8" GridPane.columnIndex="2"/>
    <Button fx:id="childButton3" text="その他" GridPane.rowIndex="8" GridPane.columnIndex="3"/>
</GridPane>

結果

f:id:yamaken1343:20180412120720p:plain

次回

yamaken1343.hatenablog.jp

JavaFXで時間管理タイマーを作る [設計編]

JavaJavaFXとタイピング*1の練習で実用的かつかんたんなアプリケーションを作成したい。

 

 画面設計

入室時間    退室時間

総時間(おおきめ)

総研究時間

総休憩時間

総その他時間

現在の状態(研究/休憩/その他)

現在の状態時間(おおきめ)

入室/退室ボタン 研究ボタン 休憩ボタン その他ボタン

 

クラス設計

  • 経過時間と状態を持つクラスを作成
  • 状態によって毎秒カウントアップするか判別

実装

class LabT {
private long time = 0;
private boolean status = false;

void timeCount(){
if (status) time++;
}
void reset(){
time = 0;
}
long getTime(){
return time;
}
boolean getStatus() {
return status;
}
void active(){
status = true;
}
void inactive(){
status = false;
}
String formatPrint(){
return String.format("%02d:%02d:%02d", time/3600%60, time/60%60, time%60);
}
}

 

 続き

 

 

yamaken1343.hatenablog.jp

追記

なんだこれ

 

f:id:yamaken1343:20180425184357p:plain

桁がおかしい

修正しておきました

元コード

String formatPrint(){
    return String.format("%02d:%02d:%02d", time/3600, time/60, time%60);
}

*1:Dvorakにしたせいで速度がダメになった