none
30分のカウントダウンタイマーを作りたい RRS feed

  • 質問

  • 初心者の黒です。

    開発環境はWin10、vs2015のprofessionalでアプリを開発しています。

    timerコントロールを使って、ボタンを押すと30:00から1秒ずつ減っていくカウントダウンタイマーを作りたいです。

    今まではIF文とかを使用してごちゃごちゃしたプログラムを書いていたのですが、

    datetimeとAddseconds(-1)を使用すれば、if文を使わないで30:00から1秒ずつ引き算でできるのかと思ったのですが、できませんでした。

    すみませんが、コードを教えてください。

    追記です。開発はvb.netでやっています 2019/4/3 14:46

    もしくは300秒→5:00という表記に変更する方法はないですか

    CtypeではIntからdatetimeはダメと言われました。

    • 編集済み 9638masa 2019年4月3日 5:47
    2019年4月2日 8:47

回答

  • 経過時間や時間の差を扱うなら TimeSpan 型が良いと思います。
    たとえば、以下のようなコードだと、result に 00:29:50 と入ります。

    Dim t As TimeSpan = TimeSpan.FromMinutes(30)
    Dim elapsed As TimeSpan = TimeSpan.FromSeconds(10)
    Dim result As String = (t - elapsed).ToString()
    

    また、Timer の Tick イベントは Interval プロパティで指定した間隔よりも長い間隔で呼び出されることがあり、1 回のイベントハンドラ呼び出しで 1 秒ずつ減らしていると、実際の経過時間とずれる可能性があります。
    Stopwatch クラスをフィールド変数で保持して、開始時に Start メソッドを呼び、経過した時間 Elapsed プロパティで取り出して、TimeSpan.FromMinutes(30) から引くと残り時間が計算できると思います

    イメージ:

    Private stopWatch As Stopwatch
    
    Private Sub StartCountDown()
      stopWatch.Start
    End Sub
    
    Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
      Label1.Text = (TimeSpan.FromMinutes(30) - stopWatch.Elapsed).ToString()
    End Sub
    

    • 回答としてマーク 9638masa 2019年4月3日 8:59
    2019年4月2日 13:17
    モデレータ
  • フォーム1をLOADして00:29:59のまま変化しません。

    下記の Button1 と Button2 の違いを考えてみてください。

    常に 00:29:59 になってしまっているのは、現状のコードが Button1 相当の処理になってしまっていることを意味します。

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Label1.Text = "30"
            Label2.Text = "30"
        End Sub
        Private Count1 As Integer = 30
        Private Count2 As Integer = 30
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim result As String = (Count1 - 1).ToString()
            Label1.Text = result
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Count2 -= 1
            Dim result As String = Count2.ToString()
            Label2.Text = result
        End Sub
    End Class


    • 回答としてマーク 9638masa 2019年4月3日 8:58
    2019年4月3日 8:21

すべての返信

  • Addseconds メソッドはそのオブジェクトの情報を書き換えるのではなく、指定された秒数を加算した新しい DateTime を返すので、例えば下記のように書くといいかもしれません。

    DateTime date1 = new DateTime(2014, 9, 8, 16, 0, 0);

    date1 = date1.AddSeconds(-1);

    DataTime は実際の日時を保持するオブジェクトなのでカウントダウンにはそぐわないかもしれません。int など数値の方がよい?

    参考サイト : https://docs.microsoft.com/ja-jp/dotnet/api/system.datetime.addseconds?view=netframework-4.7.2

    • 編集済み kenjinoteMVP 2019年4月3日 7:34 変数のスペルミスを修正
    2019年4月2日 9:33
  • 経過時間や時間の差を扱うなら TimeSpan 型が良いと思います。
    たとえば、以下のようなコードだと、result に 00:29:50 と入ります。

    Dim t As TimeSpan = TimeSpan.FromMinutes(30)
    Dim elapsed As TimeSpan = TimeSpan.FromSeconds(10)
    Dim result As String = (t - elapsed).ToString()
    

    また、Timer の Tick イベントは Interval プロパティで指定した間隔よりも長い間隔で呼び出されることがあり、1 回のイベントハンドラ呼び出しで 1 秒ずつ減らしていると、実際の経過時間とずれる可能性があります。
    Stopwatch クラスをフィールド変数で保持して、開始時に Start メソッドを呼び、経過した時間 Elapsed プロパティで取り出して、TimeSpan.FromMinutes(30) から引くと残り時間が計算できると思います

    イメージ:

    Private stopWatch As Stopwatch
    
    Private Sub StartCountDown()
      stopWatch.Start
    End Sub
    
    Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
      Label1.Text = (TimeSpan.FromMinutes(30) - stopWatch.Elapsed).ToString()
    End Sub
    

    • 回答としてマーク 9638masa 2019年4月3日 8:59
    2019年4月2日 13:17
    モデレータ
  • >すみませんが、コードを教えてください。

    そうですね。良いコードをたくさん読むことは上達の早道です。最初はどれが良いコードなのかわからないと思いますが、経験を積んでいけばわかるようになるでしょう。また、自分にとって参考になれば、それは自分基準で良いコードです。
    どうぞ、多くのコードを探してみて下さい。
    コードを探す場合、キーワードを入れて画像検索するのも一つの手です。実行中のプログラムの画像が検索されますから、自分が求めているものを探しやすいでしょう。例えば「c# stopwatch タイマー」などのキーワードで検索してみて下さい。
    そのうちの一つを以下にご紹介します。

    (参考)
    C#「ストップウォッチ」
    https://ameblo.jp/hanatarekozou88/entry-11202391192.html

    (追記)
    すみません。C#かどうか書かれていませんでした。この辺りの情報は書くようにして下さい。

    2019年4月3日 3:02
    モデレータ
  • 過去のスレッドを見ている感じだと VB 希望かなと予想しています。

    なお、私のサンプルは Stopwatch のところに New キーワードを書き忘れていたので試す際にはご注意下さい。

    2019年4月3日 3:18
    モデレータ
  • Azuleanさん

    おっしゃる通り、VB希望です。アドバイスありがとうございます。

    タイマーティックの中に入れて、リザルトをtextbox1.textに表示させたのですが、

    フォーム1をLOADして00:29:59のまま変化しません。

    配置する場所がわるいのですかね~

    全然別の問題でブレークポイントを設置して1行ごとに見ようとしたのですが、timespan.csが見つかりませんのエラーがでてしまい確認できませんでした。


    Dim t As TimeSpan = TimeSpan.FromMinutes(30)←はpublic class form1の直下で宣言してます。

    Private Sub countdownTimer_Tick(sender As Object, e As EventArgs) Handles countdownTimer.Tick

            Dim elapsed As TimeSpan = TimeSpan.FromSeconds(1)
            Dim result As String = (t - elapsed).ToString()
            TextBox1.Text = result
        End Sub

    ストップウォッチのコードを試してみます。

    2019年4月3日 4:48
  • kenjinoteさん アドバイスありがとうございます。

    visualbasicで開発しているため、Cのコードは分かりませんでした。

    私の勉強不足でどう取り入れたら良いか分かりませんでした。すみません。

    2019年4月3日 4:52
  • > visualbasicで開発しているため、Cのコードは分かりませんでした。

    kenjinote さんが紹介された Microsoft の記事の言語は切り替え可能です。



    あと、変換サービスがあるので使ってみてください。完璧にとはいかなくても人が読んで理解するには十分なレベルで変換してくれるはずです。

    Telerik Code Converter
    http://converter.telerik.com/
    • 編集済み SurferOnWww 2019年4月3日 5:43 誤字訂正
    2019年4月3日 5:43
  • SurferOnWwwさん ありがとうございます。

    なるほど、そこに切替ボタンがあったのですね。とても参考になりました。

    2019年4月3日 5:52
  • フォーム1をLOADして00:29:59のまま変化しません。

    下記の Button1 と Button2 の違いを考えてみてください。

    常に 00:29:59 になってしまっているのは、現状のコードが Button1 相当の処理になってしまっていることを意味します。

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Label1.Text = "30"
            Label2.Text = "30"
        End Sub
        Private Count1 As Integer = 30
        Private Count2 As Integer = 30
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim result As String = (Count1 - 1).ToString()
            Label1.Text = result
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Count2 -= 1
            Dim result As String = Count2.ToString()
            Label2.Text = result
        End Sub
    End Class


    • 回答としてマーク 9638masa 2019年4月3日 8:58
    2019年4月3日 8:21
  • 魔界の仮面弁士さん アドバイスありがとうございます。

    ボタン1は30から1を引いたの表示

    ボタン2は押すたびに30から1ずつ引いた数を表示ということだと思いました。

    アドバイスからコードを修正したら、タイマーを発動させると30:00から1秒ずつ引くタイマーができました。

    ありがとうございました。

    2019年4月3日 8:58