Code

PythonでTkinerを使ってTimerを作ってみる【その2】

Code

前回の続きになります。

今回はカウントダウンの部分のロジック部分を作っていきます。

2-1. 残り時間の部分に動的な値を表示する

前回までで残り時間を表示している部分は、固定されたテキストの表示まででした。このテキストを変数を使って動的に変更していきます。

動的に表示を変更するにはTimerViewのLabelで指定していた「text」を「textvariable」に変更した上で、「変数」の設定を行います。

Tkinterで動的な変数を使うには「TkinterのStringVar」をはじめに宣言する必要があるため、initで宣言します。

今回は残り時間などのロジック部分はView側ではなくて、TimerMain側に持たるので利用する変数をTimerMain側へ定義します。

※各変数の役割はコメントを参照してください。

// timer_main.py
import tkinter as tk

class TimerMain():
    def __init__(self):
        self.__start_statys = True

        self.__text_min = tk.StringVar()  # フォームの分
        self.__text_sec = tk.StringVar()  # フォームの秒
        self.__remain_min = tk.StringVar() # 残り時間Labelの分
        self.__remain_sec = tk.StringVar() # 残り時間Labelの秒

        self.__text_min.set(str(60)) # 最初の設定値 60分
        self.__text_sec.set(str(0))  # 最初の設定値 0秒
        self.__remain_min.set(str("-")) # 最初の設定値 -
        self.__remain_sec.set(str("-")) # 最初の設定値 0秒

        self.__text_start_stop_button = tk.StringVar() # Startボタン
        self.__text_start_stop_button.set("Start") # 最初はStartと表示

        self.__scheduled_finish_time = tk.StringVar() # 後で実装する推定終了時間
        self.__scheduled_finish_time.set(str("-")) # 最初は - で表示する

    def click_timer_button(self):
        print("Click!!!!")

次にTimerView側で今ほどの変数を利用するのですが、__(アンダースコア2つ)でprivate化しているので@propetryを使ってgetterを作ります。(@propetryがわからない方はPythonでのgetterとかsetterを調べるといいかと思います)

click_timer_buttonの下側に続けて以下を記載します。

// timer_main.py
(略)
    def click_timer_button(self):
        print("Click!!!!")

    @property
    def text_min(self):
        return self.__text_min

    @property
    def text_sec(self):
        return self.__text_sec

    @property
    def text_start_stop_button(self):
        return self.__text_start_stop_button

    @property
    def remain_min(self):
        return self.__remain_min

    @property
    def remain_sec(self):
        return self.__remain_sec

    @property
    def scheduled_finish_time(self):
        return self.__scheduled_finish_time

TimerMain内での変数側の宣言が終わったのでTimerView側から利用する変数として指定します。

先ほどの繰り返しになりますが、変数部分は「text」から「textvariable」に変更し、TimerMain内の変数を呼びだすようにしています。

from tkinter import ttk
from tkinter import *

from timer_main import TimerMain


class TimerView(ttk.LabelFrame):
    def __init__(self, master=None):
        self.timer_main = TimerMain()
        __frame = ttk.LabelFrame(master, text="タイマー")
        __frame.pack(anchor="w", fill="x", expand=True, padx=30, pady=10)

        __label = Label(__frame, text="タイマー入力")
        __label.grid(row=0, column=0)

        __label = Entry(__frame, justify="right", width="8", textvariable=self.timer_main.text_min)
        __label.grid(row=0, column=1)

        __label = Label(__frame, text="分")
        __label.grid(row=0, column=2)

        __label = Entry(__frame, justify="right", width="8", textvariable=self.timer_main.text_sec)
        __label.grid(row=0, column=3)

        __label = Label(__frame, text="秒")
        __label.grid(row=0, column=4)

        __label = Button(__frame, textvariable=self.timer_main.text_start_stop_button,
                         command=self.timer_main.click_timer_button)
        __label.grid(row=0, column=5)

        __label = Label(__frame, text="残時間")
        __label.grid(row=1, column=0)

        __label = Label(__frame, textvariable=self.timer_main.remain_min)
        __label.grid(row=1, column=1)

        __label = Label(__frame, text="分")
        __label.grid(row=1, column=2)

        __label = Label(__frame,  textvariable=self.timer_main.remain_sec)
        __label.grid(row=1, column=3)

        __label = Label(__frame, text="秒")
        __label.grid(row=1, column=4)

        __label = Label(__frame, text="推定終了時刻:")
        __label.grid(row=1, column=5)

        __label = Label(__frame, textvariable=self.timer_main.scheduled_finish_time)
        __label.grid(row=1, column=6)

この状態で実行すると以下の様な画面になり、先ほど変数で指定した初期値が表示されるかと思います。まだ、この時点ではStartボタンを押してもClickと表示されるだけです

という事で、いよいよカウントダウンの部分を作っていきましょう。

2-2. カウントダウンのロジックを作成する

では、Startボタンがクリックされたらカウントダウンタイマーの処理が始まるようにロジック部分を作成します。

具体的にはTinkerでタイマーを実装するために「after関数」を使います。

「タイマーに設定した〇分後に実行する」というだけであればtime関数のsleepでも問題ないのですが、今回は前回作ったの要件定義にある1秒単位でカウントダウンする、というのが必要です。

  • 「Start」ボタンをクリックするとタイマーが開始され、1秒単位でカウントダウンする

上の要件の通りにするにはsleepのように完全に処理を止める(=1秒単位でのカウントダウンをしない)ということでは困るので「特定の処理を指定した時間分遅らせて実行する」役割を持つ「after関数」を利用することになります。

1秒単位でTkinerのビューをリフレッシュする際に、TimerViewのFrameを再読み込みさせる必要があります。TimerMain側で利用できるようにTimerMainにframeを渡します。

先ほどまでは先頭でTimerMainインスタンスを作ってましたが、frameを渡すために順番を遅らせてます。

// timer_view.py
    def __init__(self, master=None):

        __frame = ttk.LabelFrame(master, text="タイマー")
        __frame.pack(anchor="w", fill="x", expand=True, padx=30, pady=10)
        self.timer_main = TimerMain(__frame)

次に受け取るTimerMain側の処理です。一気にStartがクリックされた際のafter部分まで作ってしまいます。

// timer_main.py
(略)
    def click_timer_button(self):
        self.__remain_sec.set(int(self.__text_sec.get()))
        self.exec_timer()

    def exec_timer(self):
        __tmp_time_sec = int(self.__remain_sec.get())
        __tmp_time_sec -= 1
        self.__remain_sec.set(str(__tmp_time_sec))
        self.__frame.after(1000, self.exec_timer)
(略)

Startをクリックすると残時間の秒の部分がタイマー的な動きになっているのが分かったと思います。(マイナスになっていってますが・・・)

簡単に解説します。

StartボタンをクリックしてTimerMainのclick_timer_buttonが呼ばれます。始めにフォームで入力された秒の値(__text_sec)を残時間の秒(__remain_sec)にセットします。

exec_timerを呼び出しして、__remain_secをマイナス1してからafter関数で自分自身を呼び出ししてます。afterで指定している1000は1000ms=1秒となります

マイナスしている部分ですが、StringVar形式なので単純にマイナス1はできずに一旦getで呼び出し→一時的な変数で処理→setで設定という流れを踏んでます。

まとめ

今回ではで見た目のところで残っていた部品をとりあえず配置してから、after関数を使って、タイマーの中核に当たる部分が完成できました。

要件でいうと以下の黄色塗りの部分です。残り時間の部分は秒だけしか完成していないのでまだ作成中となります。

  • Timerで設定できるのは「分」と「秒」とし、それぞれがフォーム入力可能とする(第1回)
  • ボタンは1つとして、開いたタイミングでは「Start」を表示(第1回)
  • 「Start」ボタンをクリックするとタイマーが開始され、1秒単位でカウントダウンする(第2回)
  • 0秒になったらアラートのポップアップメッセージを表示する(今回はTkinerのmesageboxで実装する)
  • 「Start」ボタンを押したらタイマーが開始され、ボタンが「Stop」の表示に切り替わる
  • Stopを押したらタイマーが停止する
  • 残り時間として「分」と「秒」を表示する
  • 上と共に「推定での終わる時刻」を表示する。M/D hh:mm:ss形式とする
  • 「推定での終わる時刻」は1分で随時更新される

次は「分」の部分の計算を実装していきましょう。

第2回終了時のGithubコード

以下に保管してますので参考にどうぞ

GitHub - gogoloon/python-timer at Lesson#2
Contribute to gogoloon/python-timer development by creating an account on GitHub.

Pythonのオススメ勉強方法

私がオススメするPythonの効果的な学習方法は「Udemy(ユーデミー)」によるビデオ学習です。

「Udemy」は、オンライン学習の提供サイトです。学びたい人は多くある講座の中から受講したいコースを選択することができ、動画で学べるのが特徴です。

多くあるPythonのコースの中でもオススメするPythonのコースは以下となります!!

現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル

このコースでは合計で28.5時間のビデオ講座があって、それらを受講するだけで、Pythonの基礎から応用まで学ぶことができます。

私も購入して受講していますが、内容としては初心者の方から上級者まで対応する幅広い内容になっています。

下手な書籍を何冊か購入するより、この動画コースを最初からじっくりと受けることで総合的なスキルを習得することができるできます。おそらくこれ以上の教材はないと思いますので、絶対おすすめです。

ちなみに、Udemyでは頻繁にセール(1か月に2,3回程度)が開催されているので、セールのタイミングで購入すれば90%OFFになる講座もあるため、セールが開催されてからの購入をオススメします!

今回は以上となります。

コメント

タイトルとURLをコピーしました