質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.80%

JavaFXのanimationクラスのTimelineの停止の仕方がわからない。

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,720

Miyahala

score 19

JavaFXでストップウォッチを、TimeAPIとDurationクラスを使う事にこだわって作成しようとしています。
なんとかここまで作って来たのですが、ストップボタンを押したときの動作がうまく行きません。
timeline.stop()の使い方に誤りがあるようだと考えて、stopSWメゾット内にtimeline.stop()を記述したり、if文を用いたり色々手を尽くしてみましたがどうにもうまくいきません、それで質問させて頂くことにしました。どのようにすればtimeline.stop()を動作させる事が出来るのでしょうか?

package miyastopwatch9;

import java.awt.Insets;
import java.time.*;
import java.time.format.DateTimeFormatter;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

/**
 *
 * @author miya
 */
public class MiyaStopwatch9 extends Application {

    //フィールドの類

    //時間計算用のInstant型が2つ
    Instant timeA;
    Instant timeB;

    //結果のデータ出力用にInstant型とDuration型それぞれ1つ
    Instant ans;
    Duration durationans;

    //ストップウオッチの制御用にboolean型を1つ
    boolean stopSW=false;

    //GUIの表示用にString型を1つ
    String display;

     /*Stringへの型変換用のフォーマット用変数を宣言、
    フォーマッタの準備、変数formatter1にフォーマッタの代入をしている。*/
    DateTimeFormatter formatter1=DateTimeFormatter.ofPattern("H:mm:ss");

   //続いてGUIの類です。
    Label labelTime1=new Label("00");
    LocalTime now=LocalTime.of(0, 0, 0, 0);
    Button btnSTA = new Button("Strat");
    Button btnSTO=new Button("Stop");

    //ラムダ式でstartSWとstopSWのイベント処理を書きました。
    @Override
    public void start(Stage primaryStage) {        

        btnSTA.setOnAction(event-> {

            startSW();
        });

        btnSTO.setOnAction(event->{

            stopSW();
        });

         //フォントサイズの指定
        labelTime1.setFont(new Font(50));

        //レイアウトはHBoXとVBoxの組み合わせで行いました。

        HBox HBox=new HBox();
        HBox.setAlignment(Pos.CENTER);
        //HBox、横方向(H)にlabelTime1を整列させよ
        HBox.getChildren().addAll(labelTime1);

        HBox HBox2=new HBox();
        HBox2.setAlignment(Pos.CENTER);
        //HBox2、横方向(H)にlbtnSTAとbtnSTOを整列させよ
        HBox2.getChildren().addAll(btnSTA,btnSTO);

        VBox VBox = new VBox();  
        VBox.setAlignment(Pos.CENTER);
        VBox.setSpacing(20.0);
        //VBox、縦方向(V)にHBoxとHbox2を整列させよ
        VBox.getChildren().addAll(HBox,HBox2);

        Scene scene = new Scene(VBox,300, 250);

        primaryStage.setTitle("ストップウォッチ");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    //各呼び出され側のメゾットの内容です。
     public void startSW(){
         System.out.println(" startSWメゾット起動");
         this.timeA=Instant.now();
         pendulum();
         //pendulum 和訳「振り子」
     }

     public void pendulum() {
         System.out.println("pendulumメゾット起動");

         /*Timelineインスタンス作成、同時にKeyFrameインスタンスも作成し、
         1000millisごとのアニメーション動作を指定*/
          Timeline timeline = 
                new Timeline(
                               new KeyFrame(
                                            javafx.util.Duration.millis(1000),
                                            /*KeyFrameのコンストラクタの引数である、
                                       インターフェースEventHandler<actionevent>を実装、
                                       (ActionEvent型の引数としてeventを渡す)*/
                                                event->{
                                                //現在時刻を取得
                                                this.timeB=Instant.now();
                                                timecalcu();
                                                labelTime1.setText(display);
                                                }    
                                            )
                                );
                       //アニメーションの作動時間は無限とする。
                      timeline.setCycleCount(Timeline.INDEFINITE);                   
                      //アニメーション開始
                      timeline.play();

           /*もしストップボタンのスイッチがtrueであるならばStopせよ*/            
                   if(stopSW==true){

                       timeline.stop();
                       System.out.println("お願いだから止っておくれ");

                  }


     }
      public void timecalcu(){
          System.out.println("timecalcuメゾット起動");

          //ローカル変数
          long longans;
          LocalTime LocalTimeans;
          Instant Instantans;
          ZonedDateTime ZonedDatetimeans;

          //Duration.betweenに2つの瞬間時間を引渡し、かかった時間をduratonansにリターンさせる。
          this.durationans=Duration.between(timeA,timeB);

          /*2018年7月現在、Durationクラスには文字列へのフォーマッタが準備されていない(!)
          仕方がないのでlong型と他の日付クラスを介してString型に変換する。*/

          // longans=durationans.getSeconds(); これだとうまくいかない。

          //duration型からlong型に変換する。
          longans=durationans.toMillis();         

         /*<参考> this.display=""+longans;
          JDKの自動型変換のルールを利用してlong型からStrng型へ変換する方法も見つけた。*/

         //long型からInstant型へ変換する。
          Instantans=Instant.ofEpochMilli(longans);        

         //Instant型からZonedDateTimeTime型へ変換する。
           ZonedDatetimeans=Instantans.atZone(ZoneId.of("Asia/Tokyo"));         

         //ZonedDateTimeTime型からLocalTime型へ変換する。
         LocalTimeans=ZonedDatetimeans.toLocalTime();       

         //9時間の時差の分を調整する。
         LocalTimeans=LocalTimeans.minusHours(9);

         //LocalTime型からString型へ変換する。(予め準備しておいたformatter1を使用している)
         display=formatter1.format(LocalTimeans);        

         System.out.println(display);
      }

       public void stopSW() {
          System.out.println("stopSWメゾット起動");
          this.stopSW=true;
          System.out.println(this.stopSW);

          //event->{timeline.stop()};

       }

    //JavaFXはmainから起動する。
    public static void main(String[] args) {
        launch(args);
    }   
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

変数:timelineをインスタンス変数に変更し各処理で呼び出せばよいかと。

1,Timeline timelineインスタンス変数で宣言。

    Timeline timeline;


2,pendulumメソッドの変数:timelineへの代入部分をstartメソッドに移動

        VBox.getChildren().addAll(HBox,HBox2);
        timeline =
                new Timeline(
                        new KeyFrame(
                                javafx.util.Duration.seconds(1), // 変更
                                event->{
                                    //現在時刻を取得
                                    this.timeB=Instant.now();
                                    timecalcu();
                                    labelTime1.setText(display);
                                }
                        )
                );
        //アニメーションの作動時間は無限とする。
        timeline.setCycleCount(Timeline.INDEFINITE);
        Scene scene = new Scene(VBox,300, 250);
        // 後略


3,stopSWメソッドはtimeline.stop();を呼び出す。

    public void stopSW() {
        System.out.println("stopSWメゾット起動");
        this.stopSW=true;
        System.out.println(this.stopSW);
        timeline.stop(); // 追加
    }

    Button btnSTA = new Button("Strat");
    Button btnSTO=new Button("Stop");
    //ストップウオッチの制御用にboolean型を1つ
    boolean stopSW=false;

内部の状態が1つかないのであればトグル・ボタンが使えます。

◆質問分のソースコードをか変更をしました。
1, ToggleButtonクラスを使用。
2, StopWatchクラスを作成。
3, bindする形に変更したソースコードです。ご参考まで。

package miyastopwatch9;

import java.time.Instant;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.VBox;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 * @author miya
 */
public class MiyaStopwatch9 extends Application {
    //フィールドの類
    private final StopWatch stopWatch = new StopWatch();
    //続いてGUIの類です。
    private final Label labelTime1 = new Label();
    private final ToggleButton button = new ToggleButton();

    @Override
    public void start(final Stage primaryStage) {
        // ※bind
        labelTime1.textProperty().bind(stopWatch.timeProperty());
        // ※StopとStartのラベル変更をbind ToggleButton#setText()と同じ
        button.textProperty().bind(Bindings.when(button.selectedProperty()).then("Stop").otherwise("Start"));
        button.setOnAction(event -> {
            final ToggleButton source = (ToggleButton) event.getSource();
            if (source.isSelected()) {
                stopWatch.start();// ストップウォッチを開始
            } else {
                stopWatch.stop();// ストップウォッチを終了
            }
        });
        //フォントサイズの指定
        labelTime1.setFont(new Font(50));

        //レイアウトはHBoXとVBoxの組み合わせで行いました。
        final HBox HBox = new HBox();
        HBox.setAlignment(Pos.CENTER);
        //HBox、横方向(H)にlabelTime1を整列させよ
        HBox.getChildren().addAll(labelTime1);

        final HBox HBox2 = new HBox();
        HBox2.setAlignment(Pos.CENTER);
        //HBox2、横方向(H)にbuttonを整列させよ
        HBox2.getChildren().addAll(button);
        // ※setSpacingはコンストラクタでも設定可能です。
        final VBox VBox = new VBox(20.0);
        VBox.setAlignment(Pos.CENTER);
        //VBox、縦方向(V)にHBoxとHbox2を整列させよ
        VBox.getChildren().addAll(HBox, HBox2);

        final Scene scene = new Scene(VBox, 300, 250);
        primaryStage.setTitle("ストップウォッチ");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    //JavaFXはmainから起動する。
    public static void main(String[] args) {
        launch(args);
    }
}

class StopWatch {
    private final Timeline timeline;

    //private final Duration START_TIME = Duration.hours(2); // 2時間 // 表示テスト用
    //private final Duration START_TIME = Duration.minutes(3); // 3分 // 表示テスト用
    private final Duration START_TIME = Duration.ZERO;
    private Duration elapsed_time = START_TIME;
    private final DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("H:mm:ss");

    private final StringProperty total_time = new SimpleStringProperty(format(elapsed_time));

    StopWatch() {
        // ※pendulumから移動
        // javafx.util.Duration.millis(1000) → Duration.seconds(1)
        timeline = new Timeline(new KeyFrame(Duration.seconds(1), e -> {
            final Duration duration = ((KeyFrame) e.getSource()).getTime();
            elapsed_time = elapsed_time.add(duration);
            final String s = format(elapsed_time);
            // デバック用
            //System.out.println(s);
            total_time.set(s);
        }));
        //アニメーションの作動時間は無限とする。
        timeline.setCycleCount(Timeline.INDEFINITE);
    }

    public StringProperty timeProperty() {
        return total_time;
    }

    public String format(final Duration duration) { // timecalcu
        System.out.println("formatメソッド起動");
        //duration型からlong型に変換する。
        long longans = (long) duration.toMillis();

        Instant Instantans = Instant.ofEpochMilli(longans);
        ZonedDateTime ZonedDatetimeans = Instantans.atZone(ZoneId.of("Asia/Tokyo"));

        //ZonedDateTimeTime型からLocalTime型へ変換する→9時間の時差の分を調整する。
        LocalTime LocalTimeans = ZonedDatetimeans.toLocalTime().minusHours(9);
        return formatter1.format(LocalTimeans);
    }

    public void start() { // startSW
        System.out.println("startメソッド起動");
        elapsed_time = START_TIME;
        final String s = format(elapsed_time);
        total_time.set(s);
        timeline.play();
    }

    public void stop() { // stopSW
        System.out.println("stopメソッド起動");
        timeline.stop();
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/09 23:16

    timelineをインスタンス変数に置き換えて使用するという発想が初学者の私にはなくとても驚きでした。
    トグル・ボタンの有用性も教えて下さり本当にありがとうございます。
    書かれましたコードをまだ理解把握出来ていない部分も多いのですが、自分の以前のコードと見比べならら学習しプログラミングの技術を向上させていきたいと思います。
    またどうしてもダメな時はどうぞ質問させてください。(^^;)
    感謝致します。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る