11
10

More than 3 years have passed since last update.

TkinterでGUIアプリケーション開発

Last updated at Posted at 2020-03-29

GUIとは

GUIはGraphical User Interface の略で、多くのPCやスマホで利用されている視覚的に操作できるアプリ/ソフトのことをいいます。
これに対立する概念としてCUI(Character User Interface)があり、コマンドプロンプトやpowershell(windows)、Mac/Linuxのterminal上で動くアプリケーションがこれにあたります。

PythonでGUI

pythonにもGUIアプリケーションを作るためのライブラリがいくつか存在します。その中で今回はTkinterをとりあげます。
Tkinterはそれなりに古く、資料が豊富にあり、そもそもpythonを入れると一緒に入っているので別途インストールする必要がなく手軽に始めやすいという利点があります(日本語を使うのはあまり向いてないっぽいけど)。

Tkinter

Tkinterとは端的に言うとTcl/Tkのpython用ラッパーです。
つまり何なんだと言われると、Tclとは80年代に使われていたスクリプト言語で、TkとはそのGUItoolkitです。今ではあまり聞かない言語ですが、windows・Mac・Linuxで現役で動作する上、Tkはtclごとpythonに組み込まれるなど陰で生き続けています。
このtcl/tkをpythonの文法で使えるようにしたのがTkinterとなります。

TkinterでのGUIアプリケーション開発

環境

python3.7を使用しています。
MacOS catalina 10.15.3で実行しています。

前提知識

Tkinterではボタンやウィンドウは全てwidgetと呼ばれ、これらを組み合わせることでGUIを構成します。

1. 最も簡単なTkinter app

from tkinter import *

root = Tk()

root.mainloop()

上記を実行してみましょう。以下のような真っ白なウィンドウが表示されたと思います。
スクリーンショット 2020-03-20 8.56.28.png (77.2 kB)

コードの解説

巷のチュートリアルではfrom tkinter import *のようにwildcard importでtkinterのライブラリを全てimportすることが多いようです。
ただしこのようなimportはあまり推奨はされていないので、きっちりやりたい人は以下の記事を参考に必要なものを個別にimportすることをおすすめします。
参考: How To Avoid Wildcard Imports

この記事ではめんどくさくなってwildcard importを使ってしまいました。気が向いたら直します。

tkinterでアプリを作る際に絶対に必要なのがTk root widgetで、これを作るのがroot = Tk()です。先ほどみた真っ白なウィンドウで、この中にボタンやテキストを配置することになります。
tkinterは歴史が長く多くのチュートリアルがありますが、それぞれ様々な流儀で書かれています。中でも大きく2つの派閥に分かれているのがこのwidgetをクラスにするか否かです。個人的にはAn Introduction To Tkinterに倣い、初めはクラスにせず、後半コードが長くなってからクラスにしたいと思います。

Tkinterのアプリケーションとマウスのクリックなどのイベントを関連づけるのがroot.mainloop()です。
「イベントがくるのを待ち、イベントが起こる度に何かをする」を繰り返すのでloopとついています。

2.widgetを配置する

tkinerのwidgetにはテキストエリア、ラベル、ラジオボタン、プルダウン等色々あります。また、配置する方法にもpack(), grid(), place()の3種類があり、それぞれ違いがあります。

pack() grid() place()
一次元的に並べる 2次元的に並べる 前者2つでうまくいかない時に使う

・pack() で配置する

先ほどのコードに4行(とエンコード情報を1行)追加しました。


# -*- coding: utf-8 -*-
from tkinter import *

root = Tk()

w = Label(text="Enter your name!")
w.pack()
t = Entry()
t.pack()

root.mainloop()

これを実行すると以下のようになります。
実行されたプログラム

一次元的(縦に一列に並んだ形)にLabel widgetとEntry widgetを配置しています。オラオラアプリならいいですが、わかりにくい気はします。# -*- coding: utf-8 -*-を追加したのは、これを書いておかないと日本語での入力ができないからです。なお、これを書いていてもエンターを押すまで入力した文字が表示されないので、マルチバイトの文字が考慮されていないライブラリだと言えます。textとして日本語を使う場合はu"名前"のようにuを付けます。

・grid() で配置する

pack()で配置する場合、全てのwidgetは縦並びになります。とはいえわかりづらい。例えば、以下のような入力欄の左にラベルが表示されているのに慣れている方がほとんどかと思います。
スクリーンショット 2020-03-25 23.52.01.png (57.0 kB)
こうした二次元的な配置をする場合、grid()を使用します。
gridはroot widgetを縦横の列に分け、何列目の何行目に置くと言う形でGUIを構成します。
「pack()で配置する」の項で書いたコードを変更して、以下のようなGUIを作成します。

# -*- coding: utf-8 -*-
from tkinter import *

root = Tk()

w = Label(text="Name")
w.grid(row=0, column=0)
t = Entry()
t.grid(row=0, column=1)

w1 = Label(text="adress")
w1.grid(row=1, column=0)
t1 = Entry()
t1.grid(row=1, column=1)

root.mainloop()

・placeで配置する

基本的にはgrid()で配置している例が多いように思いますが、凝ったことをしたい場合place()を使う必要があります。これはまた今度書きます。

3.データをあれやこれやする

もちろんアプリケーションなわけですから、インプットに対して計算結果を返したり、何かをする必要があります。
例えば、「入力されたテキストから何か生成する」とか、「選択されたボタンに応じてアウトプットを変える」とかです。
今回は名前とアドレスを入力し確認ボタンを押すと、下に入力した文字が表示されるGUIアプリケーションを作ってみます。
スクリーンショット 2020-03-26 1.47.45.png (48.9 kB)
Confirmボタンを押すと...
スクリーンショット 2020-03-26 1.48.27.png (61.3 kB)
ボタンの下に入力情報が表示されました。
これのコードは以下です。

# -*- coding: utf-8 -*-
from tkinter import *

root = Tk()

def Confirm_click():
    input_name = t.get()
    input_adress = t1.get()
    w2.configure(text=input_name)
    w3.configure(text=input_adress)

w = Label(text=u"名前")
w.grid(row=0, column=0)
t = Entry()
t.grid(row=0, column=1)

w1 = Label(text="adress")
w1.grid(row=1, column=0)
t1 = Entry()
t1.grid(row=1, column=1)

conf_button = Button(text="Confirm", command=Confirm_click)
conf_button.grid(row=2, column=1)

w2 = Label(text=" ")
w2.grid(row=3, column=1)

w3 = Label(text=" ")
w3.grid(row=4, column=1)

root.mainloop()

少しコードが醜くなってしまいましたが、後でクラスにしてきれいにしますので、ひとまずこれで行きます。

まず目に入るのはいきなり現れたdef Confbutton_click()だと思いますが、一旦無視してください。ちゃんと説明するので。その下の部分、

w = Label(text=u"名前")
w.grid(row=0, column=0)
t = Entry()
t.grid(row=0, column=1)

w1 = Label(text="adress")
w1.grid(row=1, column=0)
t1 = Entry()
t1.grid(row=1, column=1)

は上のgrid()で表示するの項のと同じです。
その下に今回はconfirmボタンを追加しました。

conf_button = Button(text="Confirm", command=Confirm_click)
conf_button.grid(row=2, column=1)

confirm ボタンにcommand=Confirm_clickと先ほど無視してくださいと書いた関数が出てきました。このボタンが押されると先のConfirm_click()が実行されるのです。この関数を先に定義したのは、定義しておかなければnot definedと言われてしまうからです。(自分の時は少なくともそうだった)
それではconfirm_click関数に飛んで見ましょう。

def Confirm_click():
    input_name = t.get()
    input_adress = t1.get()
    w2.configure(text=input_name)
    w3.configure(text=input_adress)

ボタンが押されたあとの動作は、入力された文字列を受け取り、ボタンの下に表示することです。
まず、get()メソッドで入力された文字を受け取り、表示するwidgetのtextプロパティをconfigure()メソッドで書き換えます。

conf_button.grid()の下にある

w2 = Label(text=" ")
w2.grid(row=3, column=1)

w3 = Label(text=" ")
w3.grid(row=4, column=1)

が入力された文字を表示する場所です。

4.コードをクラスで書く

上のコードはごちゃごちゃしてきたので、見やすくするためにメインの部分はクラスにしましょう。
すると以下のようになります。
selfについての解説はUnderstanding self in Pythonが詳しいです。

# -*- coding: utf-8 -*-
from tkinter import *

class window(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)

        w = Label(text=u"名前")
        w.grid(row=0, column=0)
        self.t = Entry()
        self.t.grid(row=0, column=1)

        w1 = Label(text="adress")
        w1.grid(row=1, column=0)
        self.t1 = Entry()
        self.t1.grid(row=1, column=1)

        self.conf_button = Button(text="Confirm", command=self.Confirm_click)
        self.conf_button.grid(row=2, column=1)

        self.w2 = Label(text="")
        self.w2.grid(row=3, column=1)

        self.w3 = Label(text="")
        self.w3.grid(row=4, column=1)


    def Confirm_click(self):
        input_name = self.t.get()
        input_adress = self.t1.get()
        self.w2.configure(text=input_name)
        self.w3.configure(text=input_adress)

if __name__ == "__main__":
    root = Tk()
    window(root)
    root.mainloop()

少なくとも先のコードよりは表示されるwidgetがまとめられ、動作も目でおいやすくなったと思います。

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10