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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Q&A

解決済

4回答

1513閲覧

Tkinter 00分00秒に処理を実行したい

person

総合スコア223

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

0グッド

0クリップ

投稿2020/02/04 11:04

00分00秒になったら処理func()を1回ずつ実行したいです。
(00時00分00秒になったら処理を1回実行、01時00分00秒になったら処理を1回実行、・・・)

そのためのプログラムを下のように書いたのですが上手くできません。

Tkinterでウィンドウを開いている最中に実行することを想定しているので、Threadを使っています。

どなたか、何をどうすれば意図した処理ができるのか教えてください。

Python

1from datetime import datetime 2import tkinter as tk 3import threading as th 4import time 5 6def func(): 7 print("func") 8 9def loop(): 10 while True: 11 t = datetime.now() 12 if t.strftime("%M:%S") == "00:00": 13 func() 14 #time.sleep(1) 15 16def on_closing(): 17 t.join() 18 win.destroy() 19 20if __name__ == "__main__": 21 win = tk.Tk() 22 23 t = th.Thread(target=loop) 24 t.start() 25 26 win.protocol("WM_DELETE_WINDOW", on_closing) 27 win.mainloop()

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

after を使う手もありますよ。

python

1from datetime import datetime, timedelta 2import tkinter as tk 3 4def func(): 5 print("func") 6 7def each_hour(win, callback): 8 9 def action(): 10 callback() 11 each_hour(win, callback) 12 13 now = datetime.now() 14 target = (now + timedelta(hours=1)).replace(minute=0, second=0, microsecond=0) 15 delta = target - now 16 win.after(int(delta.total_seconds() * 1000 + 1), action) 17 18if __name__ == "__main__": 19 win = tk.Tk() 20 each_hour(win, func) 21 win.mainloop()

投稿2020/02/05 02:14

編集2020/02/05 04:32
shiracamus

総合スコア5406

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

現状のアプリでどの様に問題を感じているのかがわからないので・・・・なのですが、とりあえず思うことを何点か。

1.
現在の時刻情報はdatetime型で得ることができているのに、比較を文字列で行うのはどうなのでしょう。
date型で比較を行ったほうがよいのではないでしょうか。

datetime.now().replace(hour=0).time()

とすることで、現在の時刻情報から分秒以下を取り出すことができます。これを使うのはどうでしょうか。

2.
ikapyさんも書かれておりますが、0:00 ピッタリと比較すると処理が抜ける可能性があります。
単純に前回取得した時間(分秒のみ)より値が小さくなったら実行などでよいのでは無いでしょうか。

Python

1def loop(): 2 # 略 3 while is_valid: 4 cur = datetime.now().replace(hour=0).time() 5 # 前回よりも小さい値か? 6 if cur < before: 7 func() 8 before = cur 9 time.sleep(1)

3.
time.sleep(1) の部分ですが、ここは精度CPU負荷のトレードオフとなります。
ある程度精度が必要な場合はtime.sleep(0.1)などとしてみても良いかもしれません。
逆に、そこまでの精度が必要ないのであればtime.sleep(5)などとしても問題なく動作します。
(当然 "0:00"ピッタリと比較するのであれば動作しなくなりますが)

4.
現在のアプリではThreadが無限ループで実装されているので終了時に止まりません。

Python

1def loop(): 2 global is_valid 3 is_valid = True 4 5 while is_valid: 6 # 何かしらの処理

のようにフラグで無限ループを抜けることができるようにして、終了処理にて

Python

1def on_closing(): 2 global is_valid 3 is_valid = False 4 t.join()

などとすると良いかと思います。

以上まとめるとこんな感じとなります

Python

1from datetime import datetime 2import tkinter as tk 3import threading as th 4import time 5 6def func(): 7 print("func") 8 9def loop(): 10 global is_valid 11 is_valid = True 12 13 before = datetime.now().replace(hour=0).time() 14 while is_valid: 15 cur = datetime.now().replace(hour=0).time() 16 print(cur) 17 if cur < before: 18 func() 19 before = cur 20 time.sleep(1) 21 22def on_closing(): 23 global is_valid 24 25 is_valid = False 26 t.join() 27 win.destroy() 28 29if __name__ == "__main__": 30 win = tk.Tk() 31 32 t = th.Thread(target=loop) 33 t.start() 34 35 win.protocol("WM_DELETE_WINDOW", on_closing) 36 win.mainloop()

投稿2020/02/05 01:55

magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

cronとかタスクスケジューラなどで毎時実行させるようにすればどーでしょう

投稿2020/02/04 14:37

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

放送局などで使用している精密なタイマーやリアルタイムOSを使っているシステムと違い、一般家庭で使用するPCなどでは、スワップや他タスクの影響でどうしても時間制御は正確にできません。
プログラムを見ると、Just”00:00”で判定していますが、スワップや他タスクの影響で1秒くらいの誤差は出る可能性は充分あります。
Justの判定ではなく

python

1if t.strftime("%M:%S") >= "00:00": 2とか 3if t.strftime("%M:%S") >= "00:00" and t.strftime("%M:%S") <= "00:05":

のように、余裕をもったらいかがでしょうか。
また私でしたら、下記のように起動フラグを設けて、二重起動防止のため起動済みなら起動しないようにします(この場合、invoke_flag は global で有る必要があります)。

python

1invoke_flag = False 2... 3if invoke_flag is False and t.strftime("%M:%S") >= "00:00" and t.strftime("%M:%S") <= "00:00": 4 invoke_flag = True 5 func() 6 ... 7 8def func(): 9 ... 10 invoke_flag = False 11 ...

投稿2020/02/04 11:52

編集2020/02/04 11:53
ikapy

総合スコア1167

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問