#Tkinter CookBook 時計の作成
##前提
###1. 実行環境
本ページで記載しているプログラムコードはWindows10, python3.6で実行できることを確認しています。
2. 必要なpythonモジュール
特に必要ありません。
※python3.6本体に含まれております。
###3. 本投稿の目的
tkinterで簡単なデジタル時計を作成します。
##それでは、はじめましょう
import tkinter as tk
import datetime
import time
import threading
class Timer:
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(self.root)
self.label["font"] = ("Helvetica", 50)
self.label["bg"] = "green"
self.label["fg"] = "white"
self.label.grid(column=0, row=0)
def changeLabelText(self):
while True:
self.label["text"] = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
time.sleep(1)
if __name__ == "__main__":
timer = Timer()
thread = threading.Thread(target=timer.changeLabelText)
thread.start()
timer.root.mainloop()
実行すると下記のようなウィンドウが起動します。
1秒ごとに画面が更新されるようになっています。
このプログラムが行っていることは
- **「Label」**オブジェクトを配置
- **「Label」オブジェクトの「text」**属性を1秒ごとに更新
です。
1. 「Label」オブジェクトを配置
class Timer:
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(self.root)
self.label["font"] = ("Helvetica", 50)
self.label["bg"] = "green"
self.label["fg"] = "white"
self.label.grid(column=0, row=0)
クラスオブジェクトとして**「Timer」を宣言し、「init」**部分でオブジェクトの作成、設定、配置を行っています。
オブジェクトを作る際は、tkinterで実装されているオブジェクト(ここでは**「tk.Label」**)をインスタンス化します。
次にオブジェクトの各属性を設定します。オブジェクトの属性にアクセスする方法はいくつかありますが、私は次のように行っています。
tkinterインスタンス["属性名"] = 属性値
設定できる属性は色々あります。今回のプログラムで設定したのは、
- font:表示する文字のフォント
- fg:表示する文字の色
- bg:表示する背景色
- text:表示する文字列
です。
最後に(良く忘れがちですが)作成したオブジェクトを配置しましょう。
※インスタンス化した時点で配置されると思いがちですが、そんなことはありません。私は過去に何度も作ったはずのオブジェクトが表示されなくて焦ったことがあります。
配置方法もいくつかありますがここでは、
tkinterインスタンス.grid(column=(横の値), row=(縦の値))
としています。
###2 「Label」オブジェクトの「text」属性を1秒ごとに更新
def changeLabelText(self):
while True:
self.label["text"] = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
クラスのメソッドとしてchangeLabelText(self)を定義、呼び出された際にself.labelのtext属性にアクセスし、表示する文字列を更新します。
更新する文字列は現在の日付、時刻です。
datetimeオブジェクトのnowメソッドで現在の日付、時刻を取得します。このままだとdatetimeオブジェクト型なので、これをstr型に変換します。それがstrftimeです。
strftimeの中にある**%Yとか%Hはdatetimeオブジェクトで取得した「年」や「時間」**を表します。
具体例は下記の通りです。
>>> time = datetime.datetime.now()
>>> time
datetime.datetime(2019, 4, 28, 10, 19, 10, 795179)
time.strftime("%Y%m%d")
'20190428'
time.strftime("%Y/%m/%d")
'2019/04/28'
time.strftime("%Y/%m/%d %H:%M:%S")
'2019/04/28 10:19:10'
上で示したようにstrftimeはdatetimeオブジェクト型をstr型に変換する際のフォーマットを指定するメソッドです。変換先がstr型なので、%hogehogeの間に任意の文字列、例えば**「/」や「:」**を入れることが可能です。
1秒ごとに更新を行うため、time.sleep関数を使用します。
time.sleep(1)
引数として待機させたいだけの時間を指定します。
##実行
実行する際の注意点です。
if __name__ == "__main__":
timer = Timer()
thread = threading.Thread(target=timer.changeLabelText)
thread.start()
timer.root.mainloop()
上記のような記述をpythonファイル内に記載しておけば、コマンドプロンプト、ターミナルからpython pythonファイル名で実行できます。
一番最初に呼び出された場合name
がmain
となるためです。
このように記述しておけば、他のプログラムで呼ぶことも可能で、このプログラムだけで呼ぶことも可能となります。
また、「Label」オブジェクトのtext属性を更新する関数の実行にはthreadingオブジェクトを使用しています。
これは別のスレッド、別の流れを作成するオブジェクトです。GUIは常にユーザーの入力を待ち受けている、つまりウィンドウが閉じるまでループしている状態です。
その中でtime.sleepのような処理を一時的に停止する処理があると、GUIのループと競合(?)して、ウィンドウが固まってしまいます。
そのため、別のスレッド、別の流れを作成し、そちらで表示する文字列の更新を行っています。
上の説明は正しいかどうか、自信がないのですが私はそのように解釈しています。
以上です。