Pythonの「Tkinter」は、GUIプログラミングを行うためのライブラリです。Tkinterを活用すれば、ボタンや図形などを画面に表示できます。そのため、ユーザーフレンドリーなアプリを開発できます。現代的なアプリを作るためにも、GUIプログラミングのスキルは必須です。
しかし、Tkinterではさまざまなメソッドやウィジェットを使いこなす必要があるため、「難しい」「わからない」とお悩みの方も多いでしょう。そこで本記事では、PythonのTkinterの使い方と応用テクニックを、サンプルコード付きでわかりやすく解説します。
目次
Pythonの「Tkinter(ティーキンターもしくはティーケイインター)」とは、GUIプログラムを開発するためのライブラリです。GUIはグラフィカルユーザインターフェース、つまりボタンや図形などを表示したグラフィカルな画面を指します。PythonでGUIを作るために必要なのが、TkinterをはじめとするGUIライブラリです。
Tkinterでは、「ウィジェット」と呼ばれる部品をウィンドウに配置し、GUI画面を構成します。ウィジェットには、ボタンやテキスト、チェックボックスやスライダーなどがあります。これらを組み合わせることで、普段から馴染みがあるGUIアプリを制作可能です。
また、Pythonで使えるGUIライブラリは、「PyQt」「Kivy」「Pygame」などさまざま種類があります。その中でもTkinterは、Pythonの標準的なGUIライブラリであることや、構造がシンプルであることから、GUIプログラミングの初心者でも扱いやすいことが魅力です。
TkinterでGUIプログラムを開発するメリットとして、以下の5つが挙げられます。
Tkinterは、Windows・Linux・Macなど複数のOSに対応している、クロスプラットフォームなGUIライブラリです。その理由のひとつとして、Tkinterが「Tcl/Tk(ティクル・ティーケー)」をベースにしていることが挙げられます。
Tk(ティーケー)はGUI部品を集めたもので、そのTkを操作するためのプログラミング言語が「Tcl(ティクル)」です。Tcl/Tk自体が、さまざまなOSで動作するGUIライブラリなので、それを継承したTkinterもクロスプラットフォームに対応できます。
現在では、ソフトウェアやアプリのクロスプラットフォーム化が一般的です。たとえば、AndroidとiPhoneのどちらでも動作するアプリを作ることは、ユーザー数を増やすためにも重要なことです。TkinterでGUIプログラミングを学ぶと、こうしたクロスプラットフォーム対応のアプリ開発の基礎が身につきます。
前述したように、Pythonで使えるGUIライブラリは多岐にわたります。その中でもTkinterはとくに歴史が長く、さまざまな分野で活用されてきました。安定した動作や扱いやすさなどが主な理由です。
そのため、Tkinterには「情報の得やすさ」といった、学習者にとって大きなメリットがあります。メソッドやウィジェットの使い方がわからないときは、インターネットや書籍ですぐに解決策が見つかるので安心です。
Tkinterは全体的にシンプルな構造なので、GUIプログラミング初心者でも比較的容易に習得できます。さらに、そのシンプルさゆえに起動や処理のスピードがほかのGUIライブラリより速く、快適なアプリを作りやすいこともポイントです。
なお、機能性の点ではTkinterよりも、「Kivy」や「Pyglet」など新しいGUIライブラリのほうが有利です。しかし、GUIプログラミングの学習目的では、シンプルなTkinterがベストな選択肢だといえるでしょう。Tkinterを習得することで、ほかのGUIライブラリへの移行もスムーズにできるようになります。
Tkinterは、Pythonにデフォルトで付属するGUIライブラリです。つまり、Pythonの開発環境さえあれば、Tkinterライブラリをインポートするだけで使えるということです。
ほかの多くのGUIライブラリは、開発環境にインストールしないといけないため、事前準備に手間がかかります。さらに、この手順につまずくこともあるため、初心者が「ハードルが高い」と感じるポイントでもあります。そのため、インストールなしで使えるTkinterは、初心者に優しいライブラリだといえるでしょう。
Tkinterは機能性や構文がシンプルです。ウィンドウの生成は1行で済みますし、各ウィジェットの生成・初期化の方法は基本的に同じです。そのため、GUIプログラミングの初心者でも、比較的短期間で使いこなせるようになります。
GUIプログラミングは、通常のCUI(コンソール画面でのプログラミング)と異なる点が多いため難しい印象があるかもしれません。しかし、Tkinterなら気軽にチャレンジできますし、Tkinterで習得した知識は新しいGUIライブラリを使うときも役立ちます。
PythonのGUIライブラリ「Tkinter」の基本的な使い方について、以下2つのポイントに分けて解説します。
GUIアプリに欠かせない要素が「ウィンドウ」です。tkinterのウィンドウ生成は「tkinter.Tk()メソッド」を実行するだけで可能です。
tkinter.Tk()は戻り値としてウィンドウのオブジェクトを返します。このウィンドウに対して、さまざまな「ウィジェット(GUIの部品)」を追加していくことで、グラフィカルな画面を構成していきます。プログラムの最後に、mainloop()メソッドを呼び出すことも特徴です。詳細を以下のサンプルコードで確認しましょう。
なお、本記事のソースコードの実行時に「SyntaxError」というエラーが出るときは、「# coding: UTF-8」の部分を「# coding: Shift_JIS」に書き換えてください。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# tkinterのイベントを処理する
root.mainloop()
//実行結果
「title()メソッド」の引数に文字列を引き渡すと、ウィンドウのタイトル設定が可能です。ウィンドウサイズは「geometry()メソッド」で行いましょう。このとき、引数は「”横x縦”」の形式で指定し、必ずアルファベットの「x」を挟みます。ほかの文字や空白を入れると、エラーになるので注意してください。
最後の「mainloop()メソッド」は、いわばその後の処理をTkinterに任せるためのものです。内部では無限ループが回されており、各種イベントの処理などが自動的に行われます。mainloop()のあとに記載したソースコードは、メインウィンドウが閉じられるまで実行しないため、アプリの実行内容は「Tkinter.Tk()」と「mainloop()」の間に記載しましょう。
GUIでは、ラベルやボタンなど、さまざまな部品をウィンドウに配置します。こうしたGUI部品を「ウィジェット」と呼びます。アプリの見栄えを良くするためには、それぞれのウィジェットを適切に「配置」することが重要です。Tkinterでは、以下3種類のメソッドを使用し、ウィジェットを配置できます。
「pack()メソッド」は、上から順番にウィジェットを配置します。以下のサンプルコードで、4つのボタンをpack()メソッドで配置してみましょう。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# 4つのボタンを生成する
buttonA = tkinter.Button(root, text = “ボタンA”)
buttonB = tkinter.Button(root, text = “ボタンB”)
buttonC = tkinter.Button(root, text = “ボタンC”)
buttonD = tkinter.Button(root, text = “ボタンD”)
# 4つのボタンを「pack()メソッド」で配置する
buttonA.pack()
buttonB.pack()
buttonC.pack()
buttonD.pack()
# tkinterのイベントを処理する
root.mainloop()
//実行結果
pack()メソッドでは、「side引数」に「tkinter.TOP」「tkinter.LEFT」「tkinter.RIGHT」「tkinter.BOTTOM」いずれかの値を指定します。これにより、以下のように上寄せ・左寄せ・右寄せ・下寄せでウィジェットを配置することが可能です。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# 4つのボタンを生成する
buttonA = tkinter.Button(root, text = “ボタンA”)
buttonB = tkinter.Button(root, text = “ボタンB”)
buttonC = tkinter.Button(root, text = “ボタンC”)
buttonD = tkinter.Button(root, text = “ボタンD”)
# 4つのボタンを「pack()メソッド」で配置する
buttonA.pack(side = tkinter.TOP) # 上寄せ
buttonB.pack(side = tkinter.LEFT) # 左寄せ
buttonC.pack(side = tkinter.RIGHT) # 右寄せ
buttonD.pack(side = tkinter.BOTTOM) # 下寄せ
# tkinterのイベントを処理する
root.mainloop()
//実行結果
「grid()メソッド」は、「行」と「列」を指定してウィジェットを配置できます。まずは、引数に何も指定しない場合の挙動を確認しておきましょう。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# 4つのボタンを生成する
buttonA = tkinter.Button(root, text = “ボタンA”)
buttonB = tkinter.Button(root, text = “ボタンB”)
buttonC = tkinter.Button(root, text = “ボタンC”)
buttonD = tkinter.Button(root, text = “ボタンD”)
# 4つのボタンを「grid()メソッド」で配置する
buttonA.grid()
buttonB.grid()
buttonC.grid()
buttonD.grid()
# tkinterのイベントを処理する
root.mainloop()
//実行結果
引数を指定しない場合は、左上から下に向かって自動的に配置されます。一方、以下のサンプルコードのように「row引数」で行を、「column引数」で列を指定すると、ウィジェットをグリッド状に配置できます。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# 4つのボタンを生成する
buttonA = tkinter.Button(root, text = “ボタンA”)
buttonB = tkinter.Button(root, text = “ボタンB”)
buttonC = tkinter.Button(root, text = “ボタンC”)
buttonD = tkinter.Button(root, text = “ボタンD”)
# 4つのボタンを「grid()メソッド」で配置する
buttonA.grid(row = 1 ,column = 1) # 1行目1列目
buttonB.grid(row = 2 ,column = 2) # 2行目2列目
buttonC.grid(row = 2 ,column = 3) # 2行目3列目
buttonD.grid(row = 3 ,column = 4) # 3行目4列目
# tkinterのイベントを処理する
root.mainloop()
//実行結果
上記のように、buttonAは1行目1列目、buttonBは2行目2列目、buttonCは2行目3列目、buttonDは3行目4列目に配置されます。buttonBとbuttonCは同じ行に属するため、横並びになっていることがポイントです。
「place()メソッド」は、X座標とY座標を指定してウィジェットを配置できます。「x引数」と「y引数」に、それぞれウィンドウ内の座標を指定すると、以下のようにウィジェットを自由に配置可能です。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# 4つのボタンを生成する
buttonA = tkinter.Button(root, text = “ボタンA”)
buttonB = tkinter.Button(root, text = “ボタンB”)
buttonC = tkinter.Button(root, text = “ボタンC”)
buttonD = tkinter.Button(root, text = “ボタンD”)
# 4つのボタンを「place()メソッド」で配置する
buttonA.place(x = 150, y = 100) # X座標150・Y座標100に配置する
buttonB.place(x = 200, y = 150) # X座標200・Y座標150に配置する
buttonC.place(x = 250, y = 200) # X座標250・Y座標200に配置する
buttonD.place(x = 300, y = 250) # X座標300・Y座標250に配置する
# tkinterのイベントを処理する
root.mainloop()
//実行結果
なお、座標値はウィンドウ左上を原点として、右側に移動するとX座標が大きくなり、下側に移動するとY座標が大きくなります。また、指定した座標値にはウィジェットの左上が来るため、ウィジェット中央の座標値は自動的に調整されることがポイントです。上記のサンプルプログラムでは、次のボタンに移るたびにX座標とY座標が50ずつ増えるため、4つのボタンが斜めに並んでいます。
なお、place()メソッドは座標だけではなく、「width変数」に横幅・「height変数」に高さも指定できます。実際に以下のサンプルコードで、座標とサイズの両方を指定して、4つのボタンを配置してみましょう。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# 4つのボタンを生成する
buttonA = tkinter.Button(root, text = “ボタンA”)
buttonB = tkinter.Button(root, text = “ボタンB”)
buttonC = tkinter.Button(root, text = “ボタンC”)
buttonD = tkinter.Button(root, text = “ボタンD”)
# 4つのボタンを「place()メソッド」で配置する
buttonA.place(x = 150, y = 100, width = 50, height = 50) # X座標150・Y座標100に、横幅50・高さ50のボタンを配置する
buttonB.place(x = 200, y = 150, width = 80, height = 20) # X座標200・Y座標150に、横幅80・高さ20のボタンを配置する
buttonC.place(x = 250, y = 200, width = 80, height = 80) # X座標250・Y座標200に、横幅80・高さ80のボタンを配置する
buttonD.place(x = 350, y = 300, width = 40, height = 80) # X座標300・Y座標250に、横幅40・高さ80のボタンを配置する
# tkinterのイベントを処理する
root.mainloop()
//実行結果
place()メソッドを使うと、ウィジェットの位置とサイズをダイレクトに指定できます。そのため、実際の座標値がわかる場合はplace()を使い、大まかな場所を決めたい場合はpack()を使うといいでしょう。多数のウィジェットを整然と並べたい場合は、grid()がおすすめです。
Tkinterの主なウィジェットとして、以下の12種類のものが挙げられます。ここでは、それぞれのウィジェットの使い方について、サンプルコード付きで解説します。
「Label(ラベル)」は、画面上にテキストを表示するためのウィジェットです。Labelは「tkinter.Label()メソッド」で生成し、「text引数」でラベルの文字列を指定できます。以下のサンプルコードで、Labelウィジェットの使い方を確認しましょう。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# ラベルを生成する
label = tkinter.Label(text = “ラベル”)
# ラベルを「pack()メソッド」で配置する
label.pack()
# tkinterのイベントを処理する
root.mainloop()
//実行結果
なお、ラベルのフォントやサイズを指定したい場合は、tkinter.Label()メソッドの「font引数」を使用します。fontには、「フォント名」「文字サイズ」「太さ」をタプル型で指定しますが、太さは「normal(通常)」もしくは「bold(太さ)」を選びます。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# ラベルを生成する
# font引数でフォント
# foreground引数で文字色
# background引数で背景色
label = tkinter.Label(text = “ラベル”, font = (“メイリオ”, “30”, “bold”), foreground = “white”, background = “red”)
# ラベルを「place()メソッド」で配置する
label.place(x = 200, y = 100)
# tkinterのイベントを処理する
root.mainloop()
//実行結果
なお、「foreground引数」と「background引数」には、「white」や「red」などのカラーコードを指定します。より詳細に色を指定したい場合は、「FFFFFF」や「FF0000」など16進数のコードでも指定可能です。このとき、2桁を1つのかたまりとして、以下のように赤・緑・青の順番で記載することが重要です。
“0xFF0000” # 赤FF・緑00・青00 ⇒ 赤色
“0x00FF00” # 赤00・緑FF・青00 ⇒ 緑色
“0x0000FF” # 赤00・緑00・青FF ⇒ 青色
GUIプログラムに欠かせない「Button(ボタン)」ウィジェットは、「tkinter.Button()メソッド」で生成します。Labelと同じように、「text引数」でボタンの文字列を指定できます。以下のサンプルコードで、Buttonウィジェットの使い方を確認しましょう。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“640×480”)
# ボタンを生成する
button = tkinter.Button(text = “ボタン”)
# ボタンを「pack()メソッド」で配置する
button.pack()
# tkinterのイベントを処理する
root.mainloop()
//実行結果
なお、ボタンを押したときになんらかのアクションを起こしたい場合は、tkinter.Button()メソッドの「command引数」にメソッドを指定しましょう。ユーザーがボタンをクリックしたときに、指定したメソッドが呼び出されます。このように、外部から呼び出されたときにアクションを行うメソッドを、「イベントハンドラ(コールバック関数)」と呼びます。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # ボタンを生成する self.button = tkinter.Button(text = "ボタン", font = ("メイリオ", "30", "bold"), command = self.button_clicked) # ボタンを「pack()メソッド」で配置する self.button.pack() # tkinterのイベントを処理する root.mainloop() # button_clicked()メソッド|ボタンクリック時に呼び出される def button_clicked(self): # destroy()メソッドでウィジェットを削除する self.button.destroy() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
ボタンをクリックする前
ボタンをクリックした後
上記のサンプルプログラムでは、ユーザーがボタンをクリックするとそのボタンが消えます。command引数に「button_clicked()メソッド」を指定し、内部でボタンのdestroy()メソッドを呼び出していることがポイントです。destroy()は、ウィジェットを削除するための関数です。
なお、上記のサンプルコードでは「Applicationクラス」を定義し、その内部で各種ウィジェットを作成しています。こうすることで、メンバ変数として作成した各種ウィジェットに、イベントハンドラ内部からアクセス可能です。
1行だけ入力できるテキストボックスが必要な場合は、「Entry(エントリー)」を使用します。tkinter.Entry()メソッドを呼び出すと、以下のようにエントリーを生成できます。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # エントリーを生成する self.entry = tkinter.Entry() # エントリーを「pack()メソッド」で配置する self.entry.pack() # tkinterのイベントを処理する root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
初期状態
テキスト入力時
上記のように、エントリーにはユーザーが入力した文字列が表示されます。なお、エントリーに入力できる文字数は、「width変数」で指定可能です。初期文字列は「insert(tkinter.END, “文字列”)」で設定し、エントリーの文字列は「entry.get()メソッド」で取得できます。詳細を以下のサンプルコードで確認しましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # エントリーを生成する # width変数で入力できる文字数を設定 self.entry = tkinter.Entry(root, width = 70) # エントリーの初期文字列を設定する self.entry.insert(tkinter.END, "デフォルトの文字列") # エントリーを「pack()メソッド」で配置する self.entry.pack() # エントリーの初期文字列をコンソール画面に表示する print(self.entry.get()) # tkinterのイベントを処理する root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
GUI画面の表示
コンソールの表示
Tkinterでは、各ウィジェットの生成時に、「command引数」でイベントハンドラ(コールバック関数)を指定できます。しかし、エントリーだけはcommand引数を指定できません。そのため、テキストの入力時にアクションを起こしたい場合は、「入力検証」の機能を利用する必要があります。
入力検証とは、エントリーへの入力値が適切かチェックする機能です。まずは「root.register()メソッド」の引数で、イベントハンドラ(コールバック関数)を指定しましょう。その戻り値を、tkinter.Entry()メソッドの「validatecommand引数」に設定します。ただし、validatecommand引数はタプル形式で指定する必要があり、2つ目の要素として以下のパラメーターのいずれかを選びます。
パラメーター | 詳細 |
---|---|
%d | アクションの種類 挿入は「1」・削除は「0」・再検証は「-1」 |
%i | 挿入・削除された文字の位置 どちらでもない場合は「-1」 |
%P | テキスト編集後の文字列 |
%s | テキスト編集前の文字列 |
%S | 挿入・削除された文字列 |
%v | validate引数で指定した値 |
%V | 現在のvalidateの種類 |
%W | Entryウィジェットの変数名 |
さらに、tkinter.Entry()メソッドは「validate引数」で、入力検証が発生する条件も指定する必要があります。こちらは、以下のいずれかから選びましょう。
validateの種類 | 詳細 |
---|---|
none | 入力検証を行わない |
key | 文字列の入力・挿入・削除が行われたとき |
focus | フォーカス状態が変化したとき |
focusin | フォーカスを取得したとき |
focusout | フォーカスを失ったとき |
all | すべてのタイミング |
これらのオプションを使用して、Entryウィジェットの入力検証を行ってみましょう。以下のサンプルコードでは、入力されたテキストが5文字以上である場合のみ、コンソール画面にアクションの種類と文字列を表示します。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # entry_validate()メソッドを入力検証用のメソッドとして登録する validate_command = root.register(self.entry_validate) # エントリーを生成する # width変数で入力できる文字数を設定 # validate変数でコマンド発生の条件を設定 # validatecommand変数でコールバック関数を指定 self.entry = tkinter.Entry(root, width = 70, validate = "key", validatecommand = (validate_command, "%P")) # エントリーの初期文字列を設定する self.entry.insert(tkinter.END, "デフォルトの文字列") # エントリーを「pack()メソッド」で配置する self.entry.pack() # tkinterのイベントを処理する root.mainloop() # entry_validate()メソッド|入力検証を行う def entry_validate(self, text): # 5文字以上入力した場合は、コンソール画面に文字列を表示する if len(text) >= 5: print(text) # 検証結果は常にTrueを返す return True # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
GUI画面の表示
コンソールの表示
tkinter.Entry()メソッドの引数で、「validate」と「validatecommand」を指定していることがポイントです。前述したように、validatecommand引数はタプル形式で、登録済みのイベントハンドラと検証パラメーターを設定しましょう。検証パラメーターは、同時に複数指定することも可能です。なお、エントリーと入力検証の活用例については、後ほど「実践編」で紹介します。
複数行のテキストを入力できる「テキストフィールド」を設置したい場合は、Entryではなく「Text(テキスト)」ウィジェットを使用します。tkinter.Text()メソッドを呼び出すことで、以下のように簡易的なメモ帳のようなアプリが作れます。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # テキストを生成する self.text = tkinter.Text(font = ("メイリオ", "30", "bold")) # テキストを「pack()メソッド」で配置する self.text.pack() # tkinterのイベントを処理する root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
上記のように、キーボード入力で自由にテキストの入力・挿入・削除ができます。なお、テキストフィールドの活用法については、後ほど「応用編」であらためて解説します。
複数の選択肢をチェックできる「チェックボックス」は、「CheckButton(チェックボタン)」ウィジェットで作成できます。tkinter.Checkbutton()メソッドの「text引数」に項目名を指定すると、以下のようにチェックボックスが表示されます。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("300x50") # チェックボタンを生成する self.checkbutton = tkinter.Checkbutton(text = "チェックボタン") # チェックボタンを「pack()メソッド」で配置する self.checkbutton.pack() # tkinterのイベントを処理する root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
初期状態
チェック時
チェックボックスを便利に使いこなすためには、「variable引数」と「command引数」を指定する必要があります。variable引数にはチェックボックスのチェック状態を格納する変数、command引数にはチェック時に呼び出されるコールバック関数を設定します。variable引数に指定した変数には、Boolean値でチェック状態が格納されることがポイントです。詳細を以下のサンプルコードで確認しましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # チェックボタン関連の変数を生成する self.values = {} self.checkbuttons = {} # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # 5つのチェックボタンを生成する for i in range(5): # チェック値変数を生成する self.values[i] = tkinter.BooleanVar() # チェックボタンを生成する # variable引数にチェック値変数を指定する # command引数にコールバック関数を指定する self.checkbuttons[i] = tkinter.Checkbutton(text = "チェックボタン" + str(i + 1),variable = self.values[i], command = self.checked) # チェックボタンを「pack()メソッド」で配置する self.checkbuttons[i].pack() # ラベルを生成して配置する self.label = tkinter.Label() self.label.pack() # tkinterのイベントを処理する root.mainloop() def checked(self): # ラベルのテキストをリセットする # 「["text"]」でラベルのテキストを変更可能 self.label["text"] = "" # 各チェックボタンの値をチェックする for i in range(5): if self.values[i].get(): # チェックされているボタンの名前をラベルに追加する self.label["text"] += "チェックボックス" + str(i + 1) + "\n" # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
また、ラベルのテキストを変更したいときは「label[“text”]」と記載し、表示したい文字列を右辺に指定しましょう。上記のサンプルプログラムでは、「checked()メソッド」でラベルの文字列を変更し、チェックしたテキストボックスの名前を表示しています。
「Radiobutton(ラジオボタン)」ウィジェットは、複数の選択肢からひとつだけ選べるチェックボックスです。選択肢の回数だけtkinter.Radiobutton()メソッドを呼び出すと、必要な数のラジオボタンが表示されます。詳細を以下のサンプルコードで確認しましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # ラジオボタン配列を生成する self.radiobuttons = {} # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # ラジオボタンの選択値変数を生成する self.selection = tkinter.IntVar() # 5つのラジオボタンを生成する for i in range(5): # ラジオボタンを生成する # value引数にボタン番号を指定する # variable引数に選択値変数を指定する # command引数にコールバック関数を指定する self.radiobuttons[i] = tkinter.Radiobutton(text = "ラジオボタン" + str(i + 1), value = i + 1, variable = self.selection, command = self.checked) # ラジオボタンを「pack()メソッド」で配置する self.radiobuttons[i].pack() # ラベルを生成して配置する self.label = tkinter.Label() self.label.pack() # tkinterのイベントを処理する root.mainloop() def checked(self): # チェックされているボタンの名前をラベルに設定する self.label["text"] = f"ラジオボタン{self.selection.get()}が選択されています" # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
tkinter.Radiobutton()メソッドでは、各ラジオボタンの番号を「value引数」で設定し、すべてのボタンの「variable引数」に同じ変数を指定することがポイントです。value引数として指定した変数の「get()メソッド」を呼び出すことで、どのボタンが選択されているかわかります。
つまみを動かすことで値を変更できるスライダーは、「Scale(スケール)」ウィジェットで実装できます。tkinter.Scale()メソッドに以下の引数を指定することで、さまざまなスライダーを設置可能です。
引数 | 概要 |
---|---|
variable | スライダーの値を格納する変数 |
orient | スライダーの向き 「HORIZONTAL(水平)」もしくは「VERTICAL(垂直)」 |
length | スライダー全体の長さ |
width | スライダー全体の太さ |
sliderlength | スライダーのつまみの幅 |
from | 最小値 |
to | 最大値 |
resolution | スライダーの分解能 |
tickinterval | 目盛りの間隔 |
各引数を変更することで、自由な形式のスケール(スライダー)を作成できます。スケールの使い方について、以下のサンプルコードで確認しましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # ラジオボタン配列を生成する self.radiobuttons = {} # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # デフォルトのスケールを生成する scale_v = tkinter.Scale() scale_v.pack(side = tkinter.LEFT) # スケールの値変数を生成する self.value_h = tkinter.DoubleVar() # カスタムのスケールを生成する self.scale_h = tkinter.Scale(variable = self.value_h, orient = tkinter.HORIZONTAL, length = 500, width = 20, sliderlength = 20, from_ = 0, to = 300, resolution = 0.5, tickinterval = 30) self.scale_h.pack(side = tkinter.RIGHT) # tkinterのイベントを処理する root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
初期状態
スライダー移動時
上記のサンプルプログラムでは、2つのスケールを作成しています。引数に何も指定しなければ、デフォルト形式として縦型のスライダーが表示されます。横型のスケールにする場合は、orient引数に「tkinter.HORIZONTAL」を指定しましょう。スケールのサイズや目盛りの解像度なども自由に変更できるため、いろいろなパターンを試してみてください。
これまでは、「pack()」「grid()」「place()」などのメソッドでウィジェットを配置してきました。しかし、ウィジェットを配置するための「Frame(フレーム)」ウィジェットを使えば、よりデザインの自由度が増します。tkinter.Frame()メソッドを活用して、ウィジェットの配置を工夫してみましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # フォントオブジェクトを生成する self.font = ("メイリオ", "10", "bold") # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # ツールバーを生成する self.create_toolbar() # ステータスバーを生成する self.create_statusbar() # カラムを生成する self.create_column() # 中央画面を生成する self.create_center() # tkinterのイベントを処理する self.root.mainloop() # create_toolbar()メソッド|ツールバーを作成する def create_toolbar(self): # ツールバー用のフレームを生成する frame = tkinter.Frame(self.root, bd = 2, relief = tkinter.RAISED, bg = "lightgray") # 5つのボタンを作成する button_1 = tkinter.Button(frame, text = "1", font = self.font, width = 3, command = self.button_clicked) button_2 = tkinter.Button(frame, text = "2", font = self.font, width = 3, command = self.button_clicked) button_3 = tkinter.Button(frame, text = "3", font = self.font, width = 3, command = self.button_clicked) button_4 = tkinter.Button(frame, text = "4", font = self.font, width = 3, command = self.button_clicked) button_5 = tkinter.Button(frame, text = "5", font = self.font, width = 3, command = self.button_clicked) # 各ボタンをフレームに左詰めで配置する button_1.pack(side = tkinter.LEFT) button_2.pack(side = tkinter.LEFT) button_3.pack(side = tkinter.LEFT) button_4.pack(side = tkinter.LEFT) button_5.pack(side = tkinter.LEFT) # ツールバーをウィンドウに配置する # ウィンドウ上部に表示したうえで、フレームを横方向に拡張する frame.pack(side = tkinter.TOP, fill = tkinter.X) # create_statusbar()メソッド|ステータスバーを作成する def create_statusbar(self): # ステータスバー用のフレームを生成する frame = tkinter.Frame(self.root, bd = 3, relief = tkinter.RAISED, bg = "darkgray") # ラベルを作成する self.label = tkinter.Label(frame, text = "ステータス", font = self.font) # ラベルをフレームに左詰めで配置する self.label.pack(side = tkinter.LEFT) # ステータスバーをウィンドウに配置する # ウィンドウ下部に表示したうえで、フレームを横方向に拡張する frame.pack(side = tkinter.BOTTOM, fill = tkinter.X) # create_column()メソッド|カラムバーを作成する def create_column(self): # カラム用のフレームを生成する frame = tkinter.Frame(self.root, relief = tkinter.SUNKEN, bd = 3, bg = "white") # 3つのチェックボタンを作成する checkbutton_1 = tkinter.Checkbutton(frame, text = "Check1", font = self.font, command = self.checkbutton_clicked) checkbutton_2 = tkinter.Checkbutton(frame, text = "Check2", font = self.font, command = self.checkbutton_clicked) checkbutton_3 = tkinter.Checkbutton(frame, text = "Check3", font = self.font, command = self.checkbutton_clicked) # 各チェックボタンをフレームに上から順番に配置する checkbutton_1.pack() checkbutton_2.pack() checkbutton_3.pack() # カラムバーをウィンドウに配置する # ウィンドウ右側に表示したうえで、フレームを縦方向に拡張する frame.pack(side = tkinter.RIGHT, fill = tkinter.Y) # create_center()メソッド|中央画面を作成する def create_center(self): # 中央画面用のフレームを生成する frame = tkinter.Frame(self.root, relief = tkinter.SUNKEN, bd = 2, bg = "gray") # 中央画面をウィンドウに配置する # ウィンドウ全体に拡張する frame.pack(expand = True, fill = tkinter.BOTH) # button_clicked()メソッド|ボタンクリック時の処理 def button_clicked(self): self.label["text"] = "ツールバーのボタンがクリックされました!" # checkbutton_clicked()メソッド|チェックボタンクリック時の処理 def checkbutton_clicked(self): self.label["text"] = "カラムバーのチェックボタンがクリックされました!" # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
初期状態
カラムのボタンクリック時
各フレームの「pack()メソッド」の引数を変えると、各ウィジェットの配置自体はそのままですが、フレームのウィンドウへの配置方法が変わります。フレームがどのように拡張されるか、背景色を見れば理解できるので、さまざまなパターンを試してみましょう。
フレームが便利な点は、あらかじめウィンドウをフレームに分割し、各フレームにウィジェットを配置できることです。そのうえで、フレーム単位でGUI画面を構成できるため、ウィジェットを直接ウィンドウに配置するよりも、効率的なデザインが可能です。
矩形や楕円などの図形や、イラストや写真などの画像は、ウィンドウに直接表示できません。これらの要素を表示するためには、「Canvas(カンバス)」ウィジェットを使用する必要があります。Canvasウィジェットには、以下のようなメソッドが搭載されており、さまざまな図形や画像を表示できます。
メソッド・関数 | 表示できる図形の種類 |
---|---|
create_arc | 円弧 |
create_bitmap | ビットマップ |
create_image | イメージ |
create_line | 直線・折れ線 |
create_oval | 楕円・円 |
create_polygon | ポリゴン(任意の多角形) |
create_rectangle | 矩形 |
create_text | 文字 |
create_window | ウィンドウ |
Canvasウィジェットを活用して、矩形・楕円・テキストを表示してみましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): def __init__(self): # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x480") # カンバスを作成する # 背景色を白にする canvas = tkinter.Canvas(root, bg = "lightgray") # カンバスを配置する # ウィンドウに合わせて拡張させる canvas.pack(fill = tkinter.BOTH, expand = True) # 矩形を描画する canvas.create_rectangle(10, 10, 300, 200, fill = "skyblue", width = 10, outline = "blue") # 楕円を描画する canvas.create_oval(350, 250, 600, 450, fill = "pink", width = 5, outline = "red") # 矩形のテキストを描画する canvas.create_text(330, 110, text = "矩形のサンプル", font = ("メイリオ", "30", "bold"), fill = "blue", anchor = tkinter.W) # 楕円のテキストを描画する canvas.create_text(30, 350, text = "楕円のサンプル", font = ("メイリオ", "30", "bold"), fill = "red", anchor = tkinter.W) # tkinterのイベントを処理する root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
上記のサンプルプログラムでは、「create_rectangle()」「create_oval()」「create_text()」を活用して、矩形・楕円・テキストを表示しています。引数は基本的に左上部分の座標やサイズ、枠線の大きさや色などを指定します。なお、画像の表示方法については後述するので、参考にしてみてください。
GUIプログラムで欠かせないのが、画面上部に表示されているメニューです。「Menu(メニュー)」ウィジェットを活用すると、ユーザーがさまざまな機能を便利に使えるようになります。まずは、tkinter.Menu()メソッドを呼び出してメニューバーを生成します。それを親として、メニューを追加したり、add_command()メソッドで項目を追加したりすることが可能です。メニューの作成方法の詳細を、以下のサンプルコードで確認しましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # 「filedialog」の機能を使用する from tkinter import filedialog # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # メニューを作成する self.create_menu() # ラベルを作成する # 「wraplength引数」で自動改行する横幅を指定 self.label = tkinter.Label(self.root, font = ("メイリオ", "20", "bold"), wraplength = 600) # ラベルを配置する self.label.pack() # tkinterのイベントを処理する self.root.mainloop() # create_menu()メソッド|メニューを作成する def create_menu(self): # メニューバーを作成する menu_bar = tkinter.Menu(self.root) # 「ファイル」関連のメニューを作成する # 第1引数で親となるメニューバーを指定 # 「tearoff引数」で区切り線の有無を設定 menu_file = tkinter.Menu(menu_bar, tearoff = False) # 「ファイルを開く」項目を追加する # 「command引数」でコールバック関数を指定 # 「accelerator引数」でショートカットキーを指定 menu_file.add_command(label = "ファイルを開く", command = self.file_open_clicked, accelerator = "Ctrl+O") # 「ファイルを保存する」項目を追加する # 「command引数」でコールバック関数を指定 # 「accelerator引数」でショートカットキーを指定 menu_file.add_command(label = "ファイルを保存する", command = self.file_save_clicked, accelerator = "Ctrl+S") # 区切り線を追加する menu_file.add_separator() # 「プログラムを終了する」項目を追加する # コールバック関数として標準の「root.destroy()メソッド」を指定する menu_file.add_command(label = "プログラムを終了する", command = self.root.destroy) # 各ショートカットキーをコールバック関数と関連付ける menu_file.bind_all("<Control-o>", self.file_open_clicked) menu_file.bind_all("<Control-s>", self.file_save_clicked) # 「表示」関連のメニューを作成する # 第1引数で親となるメニューバーを指定 # 「tearoff引数」で区切り線の有無を設定 menu_display = tkinter.Menu(menu_bar, tearoff = False) # チェックボタンの値を格納するリスト self.display_values = {} # 3つのチェックボタンを生成する for i in range(3): self.display_values[i] = tkinter.BooleanVar() menu_display.add_checkbutton(label = "表示" + str(i + 1), command = self.dispay_clicked(i + 1), variable = self.display_values[i]) # 「選択」関連のメニューを作成する # 第1引数で親となるメニューバーを指定 # 「tearoff引数」で区切り線の有無を設定 menu_select = tkinter.Menu(menu_bar, tearoff = False) # ラジオボタンの値を格納する変数 self.select_value = tkinter.IntVar() # 3つのラジオボタンを生成する for i in range(3): menu_select.add_radiobutton(label = "選択" + str(i + 1), command = self.select_clicked, variable = self.select_value, value = i + 1) # メニューバーにそれぞれの項目を追加する # 「label引数」に項目名を指定 # 「menu引数」にメニューを指定 menu_bar.add_cascade(label = "ファイル", menu = menu_file) menu_bar.add_cascade(label = "表示", menu = menu_display) menu_bar.add_cascade(label = "選択", menu = menu_select) # 作成したメニューバーをウィンドウに追加する self.root.config(menu = menu_bar) # file_open_clicked()メソッド|選択したファイルの名称を表示する def file_open_clicked(self): # ファイルの選択画面を表示し、選択されたファイル名を表示する filename = filedialog.askopenfilename(title = "ファイルを開く", initialdir = "./") self.label["text"] = "「ファイルを開く」が選択された\n" + filename # file_save_clicked()メソッド|選択したファイルの名称を表示する def file_save_clicked(self): # ファイルの選択画面を表示し、選択されたファイル名を表示する filename = filedialog.asksaveasfilename(title = "ファイルを保存する", initialdir = "./") self.label["text"] = "「名前を付けて保存」が選択された\n" + filename # dispay_clicked()メソッド|チェックボタンの値を表示する def dispay_clicked(self, num): # 「クロージャー(関数内関数)」でチェックボタンのインデックスを格納する def inner(): # ラベルのテキストを変更する self.label["text"] = f"「表示{num}」のチェック状態は「{self.display_values[num].get()}」" # クロージャー(関数内関数)を間接的に呼び出す return inner # select_clicked()メソッド|ラジオボタンの値を表示する def select_clicked(self): # ラベルのテキストを変更する self.label["text"] = f"{self.select_value.get()}番目のラジオボタンを選択" # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
「表示」のチェックボタンをクリックしたとき
「ファイルを開く」をクリックしたとき
上記のサンプルプログラムは、複数のメニューと項目を追加し、ユーザーがアクションを起こしたときにその内容を表示します。
なお、メニューのショートカットキーを追加する場合は、まずメニュー変数のadd_command()メソッドを呼び出し、「accelerator引数」でショートカットキーを指定します。そのうえで、bind_all()メソッドで、イベントハンドラ(コールバック関数)と関連付けましょう。
なお、本プログラムでは複数のチェックボタンを管理するために、チェックボタンの配列を管理し、イベントハンドラに引数付きの関数「dispay_clicked()」を引き渡しています。その引数にチェックボタンの番号を格納することで、dispay_clicked()が呼び出されたときに、該当するチェックボタンの名前を表示できるようになっています。なお、どのボタンがクリックされたか表示する方法については、「実践編」をご参考ください。
「LabelFrame(ラベルフレーム)」ウィジェットを使用すると、複数のウィジェットをラベル付きの枠線で囲めます。tkinter.LabelFrame()メソッドを呼び出し、それを親として各ウィジェットを生成すると、ラベルフレーム内にウィジェットが表示されます。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # 「filedialog」の機能を使用する from tkinter import filedialog # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # 使用するフォントを生成する font = ("メイリオ", "20", "bold") # ラジオボタン用のラベルフレームを作成する radio_button_frame = tkinter.LabelFrame(self.root, text = "ラジオフレーム", font = font, foreground = "red") # ラジオボタンの値を格納する変数 radio_value = tkinter.IntVar() # 3つのラジオボタンを作成する radio_buttons = {} for i in range(3): radio_buttons[i] = tkinter.Radiobutton(radio_button_frame, text = "ラジオ" + str(i + 1), font = font, variable = radio_value, value = i) radio_buttons[i].pack() # ラジオボタン用のラベルフレームを配置する radio_button_frame.pack() # チェックボタン用のラベルフレームを作成する # 「width変数」でラベルフレームの横幅を指定 # 「height変数」でラベルフレームの高さを指定 check_button_frame = tkinter.LabelFrame(self.root, text = "チェックフレーム" , font = font, foreground = "blue", width = 250, height = 250) # ラベルフレームの横幅と高さを指定する場合は、「propagate()メソッド」の呼び出しが必須 check_button_frame.propagate(False) # チェックボタンの値を格納する変数 check_values = {} # 3つのチェックボタンを作成する check_buttons = {} for i in range(3): check_values[i] = tkinter.BooleanVar() check_buttons[i] = tkinter.Checkbutton(check_button_frame, text = "チェック" + str(i + 1), font = font, variable = check_values[i]) # チェックボタンの配置をインデックスに応じて変更する if i % 3 == 0: check_buttons[i].pack(anchor = tkinter.W) elif i % 3 == 1: check_buttons[i].pack(anchor = tkinter.CENTER) else: check_buttons[i].pack(anchor = tkinter.E) # チェックボタン用のラベルフレームを配置する check_button_frame.pack() # tkinterのイベントを処理する self.root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
複数のウィジェットをまとめながら、サイズを変更できるフレームを「PanedWindow(ペインドウィンドウ)」と呼びます。tkinter.PanedWindow()メソッドでペインドウィンドウを生成したあとで、tkinter.Frame()メソッドで生成したフレームを追加すればOKです。ペインドウィンドウの使い方は、以下のサンプルコードのとおりです。
//サンプルプログラム
# 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # ペインドウィンドウを生成する # 「showhandle引数」でサッシ(ペインドウィンドウ間の空白)のハンドル表示を指定 # 「sashwidth引数」でサッシ空間の横幅を指定する paned_window = tkinter.PanedWindow(self.root, showhandle = True, sashwidth = 10) # 左右のフレームを作成する # 「width引数」で横幅を設定 # 「height引数」で高さを設定 frame_left = tkinter.Frame(paned_window, width = 500, height = 480, bg = "lightgray") frame_right = tkinter.Frame(paned_window, width = 140, height = 480, bg = "darkgray") # 各フレームをペインドウィンドウに追加する paned_window.add(frame_left) paned_window.add(frame_right) # ペインドウィンドウを配置する # 引数を「expand = True, fill = tkinter.BOTH」とすると、 # ペインドウィンドウのサイズがウィンドウに合わせて自動的に調整される paned_window.pack() # tkinterのイベントを処理する self.root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
初期状態
ペインドウィンドウのサイズ変更時
なお、ペインドウィンドウの間にある空間を「サッシ」と呼び、四角いボタンのようなものは「ハンドル」です。ここをドラッグすることで、ペインドウィンドウのサイズを変更できます。「sashwidth引数」でサッシ空間の横幅を変更できます。ペインドウィンドウは、画像を表示するアプリなどで役立つでしょう。
これまで解説したTkinterの基礎知識を活かせば、単純なGUIアプリは作れます。しかし、より本格的なGUIアプリを開発したい場合は、以下の7つの応用テクニックも身につけておきましょう。わかりやすいサンプルコード付きで解説するので、ぜひ参考にしてみてください。
Button・Frame・Labelなど、Tkinterのウィジェットで使えるほとんどのウィジェットは、「relief(枠線)」を選択できます。reliefには以下の6つのタイプがあり、それぞれウィジェットの外周部分の見た目が変わります。
ウィジェットの枠線は、各ウィジェットを生成するときに、「relief引数」を指定することで変更できます。ボタンを題材として、6種類のreliefを次のサンプルコードで比較してみましょう。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“320×280″)
# 6種類のボタンを作成する
button_1 = tkinter.Button(root, text=”tkinter.RAISED”, relief=tkinter.RAISED)
button_2 = tkinter.Button(root, text=”tkinter.GROOVE”, relief=tkinter.GROOVE)
button_3 = tkinter.Button(root, text=”tkinter.SUNKEN”, relief=tkinter.SUNKEN)
button_4 = tkinter.Button(root, text=”tkinter.RIDGE”, relief=tkinter.RIDGE)
button_5 = tkinter.Button(root, text=”tkinter.FLAT”, relief=tkinter.FLAT)
button_6 = tkinter.Button(root, text=”tkinter.SOLID”, relief=tkinter.SOLID)
# 6つのボタンを配置する
button_1.pack(pady = 10)
button_2.pack(pady = 10)
button_3.pack(pady = 10)
button_4.pack(pady = 10)
button_5.pack(pady = 10)
button_6.pack(pady = 10)
# tkinterのイベントを処理する
root.mainloop()
//実行結果
GUIプログラムでは、ボタンなどをクリックしたいときに、次の画面に移りたいときがあるでしょう。そのときは、tkinter.Tk()メソッドを新たに呼び出すことで、自動的に次のウィンドウが表示されます。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # 1つ目のウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # ボタンの生成と表示を行う button = tkinter.Button(self.root, text = "新しい画面に遷移する", command = self.forward_window) button.pack() # tkinterのイベントを処理する self.root.mainloop() # forward_window()メソッド|次の画面に進む def forward_window(self): # 2つ目のウィンドウを生成する self.second_window = tkinter.Tk() # ウィンドウのタイトルを設定する self.second_window.title("新しい画面") # ウィンドウのサイズを設定する self.second_window.geometry("300x200") # ボタンの生成と表示を行う button = tkinter.Button(self.second_window, text = "最初の画面に戻る", command = self.backward_window) button.pack() # tkinterのイベントを処理する self.second_window.mainloop() # backward_window()メソッド|最初の画面に戻る def backward_window(self): self.second_window.destroy() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
最初の画面
新しい画面
このように、tkinter.Tk()を呼び出すだけで画面遷移ができるので便利です。なお、前の画面を削除したい場合は、ウィンドウのdestroy()メソッドを呼び出します。さらなる画面遷移のテクニックについては、後ほどあらためて解説します。
Tkinterでは、メソッド生成時に「command引数」にイベントハンドラ(コールバック)関数を指定することで、クリック時にアクションを起こせます。しかし、ボタンのように複数の選択肢がある場合は、ボタンごとにイベントハンドラを作成・指定しないといけないので、以下のように手間がかかります。
//サンプルプログラム
# coding: UTF-8
# 「tkinterモジュール」をインポートする
import tkinter
# 1つ目のボタンクリック時のコールバック関数
def button_1_clicked():
print(“「ボタン1」がクリックされました”)
# 2つ目のボタンクリック時のコールバック関数
def button_2_clicked():
print(“「ボタン2」がクリックされました”)
# 3つ目のボタンクリック時のコールバック関数
def button_3_clicked():
print(“「ボタン3」がクリックされました”)
# メインウィンドウを生成する
root = tkinter.Tk()
# ウィンドウのタイトルを設定する
root.title(“Tkinter サンプルプログラム”)
# ウィンドウのサイズを設定する
root.geometry(“320×320”)
# 3つのボタンを生成する
button_1 = tkinter.Button(root,text = “ボタン1”, command = button_1_clicked)
button_2 = tkinter.Button(root,text = “ボタン2”, command = button_2_clicked)
button_3 = tkinter.Button(root,text = “ボタン3”, command = button_3_clicked)
# 3つのボタンを配置する
button_1.pack()
button_2.pack()
button_3.pack()
# tkinterのイベントを処理する
root.mainloop()
//実行結果
メインウィンドウ
ボタンクリック時
ボタンがさらに多くある場合は、このようにイベントハンドラを個別に作成するのは困難になることでしょう。そこで、以下のように引数付きのイベントハンドラを定義して、引数にボタン番号や名前などを持たせておくと便利です。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # ボタンクリック時のコールバック関数 def button_clicked(i): # コールバック関数をネストして、「クロージャー(関数内関数)」として定義する def inner(): print(f"「ボタン{str(i + 1)}」がクリックされました") # 間接的にコールバック関数を呼び出す return inner # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x320") # 大量のボタンを生成する buttons = {} for i in range(100): # ボタンを生成する buttons[i] = tkinter.Button(root, text = f"ボタン{i + 1}", command = button_clicked(i)) # ボタンを配置する buttons[i].grid(row = int(i / 10 + 1), column = int(i % 10 + 1)) # tkinterのイベントを処理する root.mainloop()
//実行結果
メインウィンドウ
ボタンクリック時
このように、ボタンが100個あっても的確に判定できます。重要なポイントは、イベントハンドラ(コールバック関数)であるbutton_clicked()の内部に、inner()があることです。これは「クロージャー(関数内関数)」と呼ばれ、外側の関数が内側の関数を自動的に生成する仕組みです。
この場合は、inner()がbutton_clicked()の引数「i」を使用し、ボタンの数だけinner()を自動的に生成します。そのため、わざわざ手動でイベントハンドラを作成しなくても、「どのボタンが押されたか」を判定できます。ソースコードも非常に簡潔なので、ぜひ覚えておきたいテクニックです。
先ほどは、クリックされたボタンを簡潔に判断できるテクニックを紹介しましたが、ウィジェットそのものを取得する方法もあります。
これまで解説した方法では、「command引数」オプションにイベントハンドラ(コールバック関数)を引き渡すことで、ウィジェットクリック時に関数が呼び出されました。一方、以下のように「bindメソッド」を使用すると、イベントハンドラの引数からウィジェットの情報を取得できます。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # ボタンクリック時のコールバック関数 def button_clicked(event): # 「event.widget」と指定することでウィジェットの情報を取得できる text = event.widget["text"] print(f"「{text}」がクリックされました") # メインウィンドウを生成する root = tkinter.Tk() # ウィンドウのタイトルを設定する root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する root.geometry("640x320") # 大量のボタンを生成する buttons = {} for i in range(100): # ボタンを生成する buttons[i] = tkinter.Button(root, text = f"ボタン{i + 1}") # マウス左ボタンでウィジェットがクリックされたときのコールバック関数を指定する # 第1引数の「<1>」はマウスの左クリックを指定するトリガー buttons[i].bind("<1>", button_clicked) # ボタンを配置する buttons[i].grid(row = int(i / 10 + 1), column = int(i % 10 + 1)) # tkinterのイベントを処理する root.mainloop()
//実行結果
メインウィンドウ
ボタンクリック時
イベントハンドラのbutton_clicked()は、引数「event」を受け取ります。「event.widget」と記載することで、クリックされたウィジェットの情報を取得可能です。ただし、この方法を使用する場合は、メソッドの生成後にbindメソッドを呼び出し、第1引数にイベントの種類・第2引数にイベントハンドラを指定する必要があります。なお、イベントとして利用できるものは以下のとおりです。
イベントのトリガー | 概要 |
---|---|
<Button-1> <1> |
左クリック |
<Button-2> <2> |
ホイールクリック |
<Button-3> <3> |
右クリック |
<KeyPress-H> <h> |
Hキー入力 |
<Control-Shift-KeyPress-H> | 「Ctrl+Shift+H」入力 |
実際に以下のサンプルコードで、ウィジェットの左クリック時に背景色を変更してみましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # ボタンクリック時のコールバック関数 def widget_clicked(event): # ボタンの背景色が「白」だったら「赤」に変更する if event.widget["bg"] == "white": event.widget["bg"] = "red" # ボタンの背景色が「赤」だったら「白」に変更する else: event.widget["bg"] = "white" # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # 使用するフォントを生成する font = ("メイリオ", "20", "bold") # ラジオボタン用のラベルフレームを作成する radio_button_frame = tkinter.LabelFrame(self.root, text = "ラジオフレーム", font = font, foreground = "red") # ラジオボタンの値を格納する変数 radio_value = tkinter.IntVar() # 3つのラジオボタンを作成する radio_buttons = {} for i in range(3): # ラジオボタンを作成する # 「command引数」は指定しない radio_buttons[i] = tkinter.Radiobutton(radio_button_frame, text = "ラジオ" + str(i + 1), font = font, variable = radio_value, value = i, bg = "white") # widget_clicked()メソッドを「左クリック時」のコールバック関数として指定する radio_buttons[i].bind("<1>", widget_clicked) # ラジオボタンを配置する radio_buttons[i].pack() # ラジオボタン用のラベルフレームを配置する radio_button_frame.pack() # チェックボタン用のラベルフレームを作成する # 「width変数」でラベルフレームの横幅を指定 # 「height変数」でラベルフレームの高さを指定 check_button_frame = tkinter.LabelFrame(self.root, text = "チェックフレーム" , font = font, foreground = "blue", width = 250, height = 250) # ラベルフレームの横幅と高さを指定する場合は、「propagate()メソッド」の呼び出しが必須 check_button_frame.propagate(False) # チェックボタンの値を格納する変数 check_values = {} # 3つのチェックボタンを作成する check_buttons = {} for i in range(3): # チェックボタンの値を格納するリスト check_values[i] = tkinter.BooleanVar() # チェックボタンを作成する # 「command引数」は指定しない check_buttons[i] = tkinter.Checkbutton(check_button_frame, text = "チェック" + str(i + 1), font = font, variable = check_values[i], bg = "white") # widget_clicked()メソッドを「左クリック時」のコールバック関数として指定する check_buttons[i].bind("<1>", widget_clicked) # チェックボタンの配置をインデックスに応じて変更する if i % 3 == 0: check_buttons[i].pack(anchor = tkinter.W) elif i % 3 == 1: check_buttons[i].pack(anchor = tkinter.CENTER) else: check_buttons[i].pack(anchor = tkinter.E) # チェックボタン用のラベルフレームを配置する check_button_frame.pack() # tkinterのイベントを処理する self.root.mainloop() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
初期状態
ウィジェットの左クリック時
GUIプログラムでは、ユーザーに情報を伝えたいときに「メッセージボックス」を表示することが一般的です。Tkinterでは、「messageboxクラス」のメソッドを呼び出すことで、以下のようなメッセージボックスを利用できます。
メッセージボックスの種類 | 概要 | 戻り値 |
---|---|---|
showinfo | 情報を表示する | OK |
showwarning | 警告を表示する | OK |
showerror | エラーを表示する | OK |
askquestion | 「はい」「いいえ」 2択の質問を表示する |
Yes, No |
askokcancel | 「OK」「キャンセル」 2択の質問を表示する |
True, False |
askyesno | 「はい」「いいえ」 2択の質問を表示する |
True, False |
askretrycancel | 「再試行」「キャンセル」 2択の質問を表示する |
True, False |
askyesnocancel | 「はい」「いいえ」「キャンセル」 3択の質問を表示する |
True, False, None |
以下のサンプルコードで、実際にメッセージボックスを呼び出して、それぞれの違いをチェックしてみましょう。
//サンプルプログラム
# coding: Shift-JIS
# Tkinterライブラリを使用する
import tkinter
# messageboxの機能を使用する
from tkinter import messagebox
# 「showinfo」メッセージボックスを表示する
messagebox.showinfo(title = “showinfo”, message = “メッセージ”)
# 「showwarning」メッセージボックスを表示する
messagebox.showwarning(title = “showwarning”, message = “メッセージ”)
# 「showerror」メッセージボックスを表示する
messagebox.showerror(title = “showerror”, message = “メッセージ”)
# 「askquestion」メッセージボックスを表示する
messagebox.askquestion(title = “askquestion”, message = “メッセージ”)
# 「askokcancel」メッセージボックスを表示する
messagebox.askokcancel(title = “askokcancel”, message = “メッセージ”)
# 「askyesno」メッセージボックスを表示する
messagebox.askyesno(title = “askyesno”, message = “メッセージ”)
# 「askretrycancel」メッセージボックスを表示する
messagebox.askretrycancel(title = “askretrycancel”, message = “メッセージ”)
# 「askyesnocancel」メッセージボックスを表示する
messagebox.askyesnocancel(title = “askyesnocancel”, message = “メッセージ”)
//実行結果
「showinfo」メッセージボックス
「showwarning」メッセージボックス
「showerror」メッセージボックス
「askquestion」メッセージボックス
「askokcancel」メッセージボックス
「askyesno」メッセージボックス
「askretrycancel」メッセージボックス
「askyesnocancel」メッセージボックス
メッセージボックスを活用して、ユーザーにメッセージを伝えるプログラムは以下のとおりです。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # messageboxの機能を使用する from tkinter import messagebox # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # アクション用のボタンを作成する button = tkinter.Button(self.root, text = "終了", font = ("メイリオ", "20", "bold"), command = self.button_clicked) # ボタンを配置する button.pack() # tkinterのイベントを処理する self.root.mainloop() def button_clicked(self): # メッセージボックスを表示して、プログラムを終了するかどうか確認する result = messagebox.askyesno(title = "メッセージ", message = "プログラムを終了しますか?") # 「はい」がクリックされたらプログラムを終了する if result == True: quit() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
GUIプログラミングにおいて、ファイルの読み込みと保存は必須機能です。先ほど解説した「Text(テキストフィールド)」と「filedialog(ダイアログボックス)」を組み合わせて、簡易的なメモ帳を実装してみましょう。なお、エラーが出る場合は、ロード対象のテキストファイルが「UTF-8」形式で保存されているか確認してください。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # 「filedialog」の機能を使用する from tkinter import filedialog # 「osモジュール」をインポートする import os # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # ウィンドウのリサイズを禁止する self.root.resizable(False, False) # ウィジェットで使用するフォントオブジェクトを生成する self.font = ("メイリオ", "15", "bold") # テキストフィールドを作成する self.text = tkinter.Text(self.root, font = self.font, relief = tkinter.SOLID, bd = 3) # テキストフィールドを配置する self.text.place(x = 10, y = 10, width = 620, height = 360) # 「ファイルを開く」と「ファイルを保存する」のボタンを作成する button_open = tkinter.Button(self.root, text = "ファイルを開く", font = self.font, command = self.button_open_clicked) button_save = tkinter.Button(self.root, text = "ファイルを保存する", font = self.font, command = self.button_save_clicked) # 各ボタンを配置する button_save.pack(side = tkinter.BOTTOM) button_open.pack(side = tkinter.BOTTOM) # tkinterのイベントを処理する self.root.mainloop() # 「開く」ボタンが押されたときの挙動を制御する def button_open_clicked(self): # ファイルオープン用のダイアログボックスを開く # 「title引数」でダイアログのタイトルを指定 # 「filetypes引数」で有効な拡張子を指定 # 「initialdir引数」で既定ディレクトリを指定 filename = filedialog.askopenfilename(title = "ファイルを開く", filetypes = [("テキストファイル", ".txt")], initialdir = ".\\") # テキストファイルを読み込む if os.path.exists(filename): # 「UTF-8」エンコード形式でファイルを開く file = open(filename, "r", encoding = "UTF-8") data = file.read() file.close() # テキストフィールドにデータを表示する self.text.delete(0.0, tkinter.END) self.text.insert(0.0, data) # 「保存する」ボタンが押されたときの挙動を制御する def button_save_clicked(self): # ファイルセーブ用のダイアログボックスを開く # 「title引数」でダイアログのタイトルを指定 # 「filetypes引数」で有効な拡張子を指定 # 「initialdir引数」で既定ディレクトリを指定 filename = filedialog.asksaveasfilename(title = "ファイルを保存する", filetypes = [("テキストファイル", ".txt")], initialdir = ".\\") # テキストファイルに書き込む if filename: # 「UTF-8」エンコード形式でファイルを開く file = open(filename, "w", encoding = "UTF-8") file.write(self.text.get(0.0, tkinter.END)) file.close() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
テキスト入力時
「ファイルを保存する」をクリックしたとき
作成したテキストファイルは「メモ帳」などでも閲覧可能
上記のプログラムで作成したテキストファイルは、簡易的なメモ帳のように利用でき、「ファイルを開く」で選択するとテキストフィールド上に表示されます。なお、テキストフィールドのデータは「delete(0.0, tkinter.END)」で削除し、「insert(0.0, data)」でファイルから読み込んだデータを反映できます。
Tkinterでカンバスに画像を表示するためには、「Pillow(PIL)」というライブラリが必要です。ただし、Pythonには標準でPillowが備わっていないため、以下の手順でインストールしましょう。
まず、「コマンドプロンプト」を管理者権限で開き、以下のコマンドを入力します。これでPythonを最新の状態にアップデートできます。
続いて、次のスクリプトをPythonで実行し、表示されたファイルパスをコピーします。これは、Pythonのモジュールがインストールされている場所です。
もう一度コマンドプロンプトを開き、「cd」コマンドを使って先ほどのファイルパスに移動します。ただし、ファイルパスから最後の「\python.exe」を除くことが重要です。さらに、次のコマンドを入力するとVisual Studioに「Pillow(PIL)」をインストールできます。
以下のような画面が表示されたら、Pillowのインストール手順の完了です。
TkinterとPillowを組み合わせて、以下のような簡易的な画像ビューアを作成してみましょう。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # 「filedialog」の機能を使用する from tkinter import filedialog # 「PILライブラリ」をインポートする from PIL import Image, ImageTk # 「osモジュール」をインポートする import os # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのタイトルを設定する self.root.title("Tkinter サンプルプログラム") # ウィンドウのサイズを設定する self.root.geometry("640x480") # ウィンドウのリサイズを禁止する self.root.resizable(False, False) # カンバスを作成する self.canvas = tkinter.Canvas(self.root) # カンバスを配置する self.canvas.pack(expand = True, fill = tkinter.BOTH) # 「ファイルを開く」のボタンを作成する button = tkinter.Button(self.root, text = "ファイルを開く", font = ("メイリオ", "15", "bold"), command = self.button_clicked) # ボタンを配置する button.pack(side = tkinter.BOTTOM) # tkinterのイベントを処理する self.root.mainloop() # 「ファイルを開く」ボタンが押されたときの挙動を制御する def button_clicked(self): # ファイルオープン用のダイアログボックスを開く # 「title引数」でダイアログのタイトルを指定 # 「filetypes引数」で有効な拡張子を指定 # 「initialdir引数」で既定ディレクトリを指定 filename = filedialog.askopenfilename(title = "ファイルを開く", filetypes = [("テキストファイル", ".bmp .png .jpg .tif")], initialdir = ".\\") # 画像ファイルを読み込む if os.path.exists(filename): # PillowのImage.open関数で画像ファイルを開く self.image_file = Image.open(filename) # カンバスのサイズを取得する canvas_width = self.canvas.winfo_width() canvas_height = self.canvas.winfo_height() # 画像のサイズを取得する image_width = self.image_file.width image_height = self.image_file.height # 画像の横幅が高さより長ければ、横幅に合わせて拡縮する if image_width > image_height: ratio = canvas_width / image_width # 画像の横幅が高さより短ければ、高さに合わせて拡縮する else: ratio = canvas_height / image_height # カンバスに合わせて画像を拡縮する self.image_file = self.image_file.resize((int(image_width * ratio), int(image_height * ratio))) # PhotoImage関数でピクセルデータを取得する self.photo_image = ImageTk.PhotoImage(image = self.image_file) # 画像を描画する # 表示位置は画面中央に合わせる self.canvas.create_image(canvas_width / 2, canvas_height / 2, image = self.photo_image) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
初期画面
画像選択時
まずはカンバスを作成・配置し、ファイルを指定するためのボタンを設置します。ボタンがクリックされたら、filedialog.askopenfilename()で指定されたファイル名を取得し、PillowのImage.open()で画像ファイルを開きます。そのうえで、カンバスサイズに合わせてresize()で画像を拡大縮小し、ImageTk.PhotoImage()でピクセルデータに変換しましょう。最後にカンバスのcreate_image()を呼び出せば、画像を表示させられます。
これまでに解説した知識・テクニックを活かして、以下の2つのプログラム開発にチャレンジしてみましょう。
GUIプログラムで代表的なものが、ユーザー情報の管理やログイン画面です。「Button(ボタン)」や「Entry(エントリー)」、イベントハンドラ(コールバック関数)などを駆使して作成できます。
以下のサンプルコードでは、「アカウント登録」をクリックしてユーザー名・パスワードを入力すると、ユーザーを登録することが可能です。「ログイン」からユーザー名・パスワードを入力すると、ユーザー一覧ファイルと照合し、内容が完全に一致した場合のみログイン完了となります。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # 「osモジュール」をインポートする import os # 「reモジュール」をインポートする import re # 「csvモジュール」をインポートする import csv # 「messagebox」の機能を使用する from tkinter import messagebox # Applicationクラス|GUIを生成する class Application(): def __init__(self): # 各フレームを定義する self.main_frame = None self.login_frame = None self.register_frame = None # 使用するフォントを生成する self.font = ("メイリオ", "12") # ユーザー情報を読み込む self.read_users() # メインウィンドウを起動する self.main_window() # main_window()メソッド|メイン画面を表示する def main_window(self): # すべてのウィンドウをリセットする self.reset() # メインウィンドウを生成する self.main_frame = tkinter.Tk() # ウィンドウのサイズを設定する self.main_frame.geometry("300x200") # ウィンドウのタイトルを設定する self.main_frame.title("ユーザー管理") # ウィンドウのリサイズを禁止する self.main_frame.resizable(False, False) # 「アカウント登録」ボタンを生成する # command引数に「register_window()メソッド」を指定し、ユーザー登録画面に進めるようにする button_1 = tkinter.Button(self.main_frame, text = "アカウント登録", font = self.font, command = self.register_window) button_1.pack(pady = 30) # 「ログイン」ボタンを生成する # command引数に「login_window()メソッド」を指定し、ログイン画面に進めるようにする button_2 = tkinter.Button(self.main_frame, text = "ログイン", font = self.font, command = self.login_window) button_2.pack(pady = 10) # tkinterのイベントを処理する self.main_frame.mainloop() # register_window()メソッド|ユーザー登録画面を表示する def register_window(self): # すべてのウィンドウをリセットする self.reset() # ユーザー登録ウィンドウを生成する self.register_frame = tkinter.Tk() # ウィンドウのタイトルを設定する self.register_frame.title("ユーザー登録") # ウィンドウのリサイズを禁止する self.register_frame.resizable(False, False) # 入力画面を作成する self.create_menu(self.register_frame, self.register_user) # tkinterのイベントを処理する self.register_frame.mainloop() # login_window()メソッド|ログイン画面を表示する def login_window(self): # すべてのウィンドウをリセットする self.reset() # ログインウィンドウを生成する self.login_frame = tkinter.Tk() # ウィンドウのタイトルを設定する self.login_frame.title("ログイン") # ウィンドウのリサイズを禁止する self.login_frame.resizable(False, False) # 入力画面を作成する self.create_menu(self.login_frame, self.button_clicked) # tkinterのイベントを処理する self.login_frame.mainloop() # ()メソッド| def create_menu(self, frame, execute_command): # ラベルのフレームを作成する entry_frame = tkinter.Frame() entry_frame.grid() # ユーザー名のラベルを生成する username_label = tkinter.Label(entry_frame, text = "ユーザー名", font = self.font) username_label.grid(row = 0, column = 0, sticky = tkinter.E) # パスワードのラベルを生成する password_label = tkinter.Label(entry_frame, text = "パスワード", font = self.font) password_label.grid(row = 1, column = 0, sticky = tkinter.E) # ユーザー名入力のためのエントリーを作成する self.username_entry = tkinter.Entry(entry_frame, font = self.font, width = 20, validatecommand = (frame.register(self.username_validate), "%P"), validate = "all") self.username_entry.grid(row = 0, column = 1) # パスワード入力のためのエントリーを作成する # 「show引数」に「*」を指定してパスワード入力値を隠蔽する self.password_entry = tkinter.Entry(entry_frame, font = self.font, width = 20,validatecommand = (frame.register(self.password_validate), "%P"), validate = "all", show = "*") self.password_entry.grid(row = 1, column = 1) # ボタンのフレームを作成する button_frame = tkinter.Frame(entry_frame) button_frame.grid(row = 2, column = 1, sticky = tkinter.W) # 「進む」ボタンを作成する # state引数を「disabled」にして、初期状態でクリックできないようにする # command引数を指定して、クリック時にアクションを起こす self.button1 = tkinter.Button(button_frame, text = "進む", font = self.font, width = 5, state = "disabled", command = execute_command) self.button1.pack(side = tkinter.LEFT) # 「戻る」ボタンを生成する # command引数に「main_window()メソッド」を指定し、クリック時に最初の画面に戻るようにする self.button2 = tkinter.Button(button_frame, text = "戻る", font = self.font, width = 5, command = self.main_window) self.button2.pack(side = tkinter.LEFT) # read_users()メソッド|ユーザー情報を読み込む def read_users(self): # ユーザー情報を格納する辞書 self.data = {} # ユーザー登録ファイルが存在するか確認する if os.path.isfile("Users.txt"): # 「UTF-8」エンコード形式でファイルを開く file = open("Users.txt", "r", encoding = "UTF-8") # CSVオブジェクトを作成する reader = csv.reader(file) # CSVデータを辞書変数に格納する self.data = {rows[0]:rows[1] for rows in reader} # ファイルを閉じる file.close() # register_user()メソッド|新規ユーザーを登録する def register_user(self): # 新規のユーザー情報を辞書に追加する # ユーザー名が重複している場合は上書きする self.data[self.username_entry.get()] = self.password_entry.get() # 「UTF-8」エンコード形式でファイルを開く file = open("Users.txt", "w", encoding = "UTF-8") # CSV形式でユーザー情報を出力する for k, v in self.data.items(): file.writelines(str(k) + "," + str(v) + "\n") # ファイルを閉じる file.close() # 次のユーザー登録へ移る self.register_window() # validate()メソッド|ユーザー名の入力検証を行う def validate(self, text): # 半角英数字のみ受け付ける return re.fullmatch("[a-zA-Z0-9]+", text) # username_validate()メソッド|ユーザー名の入力検証を行う def username_validate(self, text): # 双方のエントリーが条件を満たした場合のみ、OKボタンを有効化する if self.validate(text) and self.validate(self.password_entry.get()): self.button1["state"] = "normal" else: self.button1["state"] = "disabled" # 入力検証の結果は常にTrueとする return True # password_validate()メソッド|パスワードの入力検証を行う def password_validate(self, text): # 双方のエントリーが条件を満たした場合のみ、OKボタンを有効化する if self.validate(text) and self.validate(self.username_entry.get()): self.button1["state"] = "normal" else: self.button1["state"] = "disabled" # 入力検証の結果は常にTrueとする return True # button_clicked()メソッド|ボタンクリック時のアクションを指定する def button_clicked(self): # エントリーに入力されたユーザー名を取得する username = self.username_entry.get() # ユーザー名がデータに登録されているか確認する if username in self.data: # パスワードが一致するか照合する if self.data[username] == self.password_entry.get(): messagebox.showinfo(title = "完了", message = "ログインしました") self.main_window() # パスワードが一致しない else: messagebox.showerror(title = "エラー", message = "パスワードが正しくありません") # ユーザー名が登録されていない else: messagebox.showerror(title = "エラー", message = "ユーザー名が正しくありません") # reset()メソッド|各ウィンドウを削除する def reset(self): # メインウィンドウを削除する if self.main_frame != None: self.main_frame.destroy() self.main_frame = None # ユーザー登録ウィンドウを削除する if self.register_frame != None: self.register_frame.destroy() self.register_frame = None # ログインウィンドウを削除する if self.login_frame != None: self.login_frame.destroy() self.login_frame = None # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
メイン画面
ユーザー登録画面
「Users.txt」ファイル
ログイン画面
ログイン成功時
重要なポイントは、ユーザー登録時に辞書型のデータとして、ファイルにユーザーIDとパスワードを書き出していることです。そのため、プログラムを終了したあとでも、登録したユーザーの情報は保持されます。ユーザーがログイン情報を入力したときは、辞書データからユーザーIDを検索し、該当するデータがあればパスワードと照合します。その結果をメッセージボックスで表示していることもポイントです。
なお、本プログラムではより高度な画面遷移も実装しています。ボタンがクリックされたときに、tkinter.Tk()で新たなウィンドウを生成し、古いウィンドウはdestroy()で削除することで、画面が完全に切り替わったかのように表現できます。
BMI計算アプリは、以下のように比較的単純なソースコードで作れます。以下のようなサンプルコードで作ると簡単です。
//サンプルプログラム
# coding: UTF-8 # 「tkinterモジュール」をインポートする import tkinter # 「messagebox」の機能を使用する from tkinter import messagebox # Applicationクラス|GUIを生成する class Application(): # コンストラクタ def __init__(self): # メインウィンドウを生成する self.root = tkinter.Tk() # ウィンドウのサイズを設定する self.root.geometry("300x100") # ウィンドウのタイトルを設定する self.root.title("BMI算出プログラム") # 使用するフォントを生成する self.font = ("メイリオ", "12") # ラベルの生成と設置を行う label_1 = tkinter.Label(self.root, text = "身長", font = self.font, width = 7) label_2 = tkinter.Label(self.root, text = "体重", font = self.font, width = 7) label_1.grid(row = 0, column = 0) label_2.grid(row = 1, column = 0) # エントリーの生成と設置を行う self.text_1 = tkinter.Entry(width = 15, font = self.font) self.text_2 = tkinter.Entry(width = 15, font = self.font) self.text_1.grid(row = 0, column = 1) self.text_2.grid(row = 1, column = 1) # ラベルの生成と設置を行う label_3 = tkinter.Label(self.root, text = "cm", font = self.font, width = 4) label_4 = tkinter.Label(self.root, text = "kg", font = self.font, width = 4) label_3.grid(row = 0, column = 2) label_4.grid(row = 1, column = 2) # ボタンの生成と設置を行う button = tkinter.Button(self.root, text = "BMI算出", font = self.font, command = self.button_clicked) button.grid(row = 2, column = 1) # tkinterのイベントを処理する self.root.mainloop() # button_clicked()メソッド|ボタンクリック時にBMI値を算出・表示する def button_clicked(self): # 身長と体重を取得する height = float(self.text_1.get()) weight = float(self.text_2.get()) # BMI値を算出する result = height / 100 result = weight / (result * result) result = round(result, 1) # 結果を表示する messagebox.showinfo(title = "完了", message = f"あなたのBMI値は「{result}」です") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # GUIを生成する application = Application()
//実行結果
入力画面
結果画面
このプログラムでは、複数のラベルとエントリーを配置し、ユーザーが入力した数値をもとにBMIの演算を行います。なお、BMIは「体重÷((身長(cm)÷100)×(身長(cm)÷100))」の計算式で算出可能です。その結果をメッセージボックスで表示することで、ユーザーにBMI値を示せます。
Pythonで最も基本的なGUIライブラリ「Tkinter」の使い方・テクニックを解説しました。一見すると難しそうに見えるGUIプログラミングですが、今回解説した内容を少しずつ身につけていけば、便利なGUIアプリが作れるようになります。初心者の方は、まず各ウィジェットの使い方を覚えたうえで、必要なものを組み合わせるためのテクニックを身につけていきましょう。
2024.06.17
子供におすすめのプログラミングスクール10選!学習メリットや教室選びのコツも紹介
#プログラミングスクール
2022.01.06
【完全版】大学生におすすめのプログラミングスクール13選!選ぶコツも詳しく解説
#プログラミングスクール
2024.01.26
【未経験でも転職可】30代におすすめプログラミングスクール8選!
#プログラミングスクール
2024.01.26
初心者必見!独学のJava学習方法とおすすめ本、アプリを詳しく解説
#JAVA
2024.01.26
忙しい社会人におすすめプログラミングスクール15選!失敗しない選び方も詳しく解説
#プログラミングスクール
2022.01.06
【無料あり】大阪のおすすめプログラミングスクール14選!スクール選びのコツも紹介
#プログラミングスクール
2024.01.26
【目的別】東京のおすすめプログラミングスクール20選!スクール選びのコツも徹底解説
#プログラミングスクール
2024.01.26
【無料あり】福岡のおすすめプログラミングスクール13選!選び方も詳しく解説
#プログラミングスクール
2024.01.26
【徹底比較】名古屋のおすすめプログラミングスクール13選!選び方も詳しく解説
#プログラミングスクール
2024.01.26
【徹底比較】おすすめのプログラミングスクール18選!失敗しない選び方も徹底解説
#プログラミングスクール