【Python】tkinterの使い方入門。計算機GUIアプリの作成に挑戦!

Pythonの応用
スポンサーリンク

ここでは、tkinterのパッケージを使ってGUIアプリを作ってみましょう。

Pythonのグラフィックスに関してはturtleモジュールも扱いました。

【Python】turtleグラフィックスでお絵かき入門
Pythonにはタートルグラフィックスというものがあり、子供にプログラミングを紹介する時などによく利用されます。turtleモジュールをインポートして簡単に図形を描いて楽しむことができます。色々と描いたり、コードを変更してみるのも有益です。

これはお絵かきの入門的なものでした。

ここで使うtkinterパッケージは、ほとんどのUnixプラットフォームやWindows上で利用できるTk GUI ツールキットをPythonで利用するためのインタフェースです。(Tk自体は Pythonの一部ではありません)

ここではもう少し複雑なGUIを使った操作をtkinterを使ってやってみたいと思います。

スポンサーリンク

tkinterの簡単な Hello World プログラム

tkinterを説明して行くにはどこから始めるか難しいところですが、簡単なコードを見てどういうものが理解していきます。細かい部分は実践して行く中でドキュメントなどで確認して行けば良いでしょう。

tkinterのドキュメントに「簡単な Hello World プログラム」というものが例として示されています。

tkinter --- Tcl/Tk の Python インタフェース — Python 3.9.0 ドキュメント

そのコードは以下のとおり。

import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Hello World\n(click me)"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack(side="top")

        self.quit = tk.Button(self, text="QUIT", fg="red",
                              command=root.destroy)
        self.quit.pack(side="bottom")

    def say_hi(self):
        print("hi there, everyone!")

root = tk.Tk()
app = Application(master=root)
app.mainloop()

これを実行するとこんなアプリが立ち上がります。

とても小さなものが表示されるので、はっきり言って「なんじゃこりゃ?」なアプリです。これが表示されてclick meのところをクリックするとターミナルにメッセージが表示されます。

3回クリックしてみました。

QUITをクリックするとアプリが終了します、単にそれだけのアプリです。

簡単にコードを解説してみましょう。

tkinterのもっとも単純化した形はこちらになります。

import tkinter 
root = tkinter.Tk()
root.mainloop()

tkinterを読み込んで、Tk()をオブジェクト化してmainloop()で表示する。これに、いろいろと表示や機能を加えてるコードを追加していくことになります。

では、上のコードを見て行きましょう。

import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)

#########(中略)###############

root = tk.Tk()
app = Application(master=root)
app.mainloop()

tkinterでアプリを作る時のパターンとして、最初と最後はこういう形というのが使い方の基本と考えておけばいいでしょう。

tkinterをtkとしてインポート。classのApplication()で初期化と各種の設定をします。tk.Tk()をオブジェクトにしてrootとし、Application()にmasterとしてrootを渡し、これをmainloop()としてアプリを実行(表示)するという流れです。

Application()クラス内のメソッドを順に見ていきます。

#    def __init__(self, master=None):
#        super().__init__(master)
        self.pack()
        self.create_widgets()

初期化メソッドの中にpack()がありますが、これでアプリのボタンなどの配置を制御します。create_widgets()は別に定義してアプリの中身を作ります。

次のcreate_widgets()を見ていきます。

    def create_widgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Hello World\n(click me)"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack(side="top")

        self.quit = tk.Button(self, text="QUIT", fg="red",
                              command=root.destroy)
        self.quit.pack(side="bottom")

    def say_hi(self):
        print("hi there, everyone!")

実行したアプリの表示と見比べながら見ていくといいと思います。

まず、hi_thereとしてメッセージ表示ボタンを作っていきます。まずtk.Button()でボタンを生成します。[“text”]として、アプリに表示する文を作り、[“command”]でsay_hiメソッドを実行。これはあとで定義します。pack()でこの部分をどう表示するか調整します。ここでは”top”ということで、上側に表示です。

次はquitでアプリを終了させるボタンを作ります。tk.Button()でボタンを生成して、表示textを”QUIT”、文字の色をred(赤)にして、commandをroot.destroyでアプリを終了させます。pack()でこのボタンの位置を”bottom”にしています。

あとは先ほど触れたsay_hi()の定義です。

    def say_hi(self):
        print("hi there, everyone!")

メッセージを表示するコードになっています。

以上が、tkinterのドキュメントに簡単な Hello World プログラムのコードの流れです。

ちょっとアプリがショボすぎですね。やっぱり何か作ってみましょう。やっぱり計算機がプログラムの練習の定番だと思いますので、簡単な計算機をtkinterで作ってみようと思います。

スポンサーリンク

tkinterで作る計算機の完成イメージ

では、tkinterを使ってGUIアプリを作ってみましょう。tkinterの使い方やプログラミングの練習になると言われている計算機を作ってみましょう。

まあ、細かいところまでは作りこみませんので簡単な電卓ということになります。

こんな計算機を作ることにします。

この電卓の配置は、Macの電卓の配置を参考にしています。ただし、Macの計算機には[+/-]のボタンがありますが、プログラミングが複雑になってくるので、ここでは簡単に1文字削除の機能などにしています。

ボタンの配置にrowとcolumnを考える必要があるので、次のように位置を確認しておきます。

この位置関係を材料にコードを書いていきます。

スポンサーリンク

計算機のコードを書く

それではコードを書いていきましょう。上の完成アプリと配置イメージも見比べながら書いてみましょう。

import tkinter as tk


class Application(tk.Frame):

    def __init__(self, master=None):
        super().__init__(master)
        self.master.geometry()
        self.master.title('計算機')

        self.entry = tk.Entry(self.master, justify="right")

        self.menu_bar = tk.Menu(self.master)
        self.master.config(menu=self.menu_bar)

        self.create_widgets()

tkinterのインポートから初期化の部分は先ほどと一緒です。pack()のかわりに、ここではボタンの位置を細かく指定するのでgeometry()を使っています。アプリのタイトルにtitle()を使って「計算機」と表示させます。

Entry()で入力数字の表示欄を作ります。justify=”right”で右寄せで表示します。

Menu()でPCのメニューバーのところに表示させるようにします。config()でメニュー項目を設定します。

create_widgets()で各種ボタンを設定。これは後ほど定義します。

次に進みます。

    def input(self, action):
        self.entry.insert(tk.END, action)

    def clear_all(self):
        self.entry.delete(0, tk.END)

    def clear_one(self):
        txt = self.entry.get()
        self.entry.delete(0, tk.END)
        self.entry.insert(0, txt[:-1])

    def equals(self):
        self.value = eval(self.entry.get().replace('÷', '/').replace('x', '*').replace('%', '/100'))
        self.entry.delete(0, tk.END)
        self.entry.insert(0, self.value)

ここは、実際にコードを書いていくに当たっては、ここからではなく後ろの方のコードのボタンの配置などから書いていく方が流れとしてはわかり易いかもしれません。そのあたりは後のコードと見比べて考えて見てください。ここは上から説明していきます。

まず、input()ですが、ここで各数字などのボタンを押したアクションを指定します。entryの表示欄の一番最後に押したボタンの数字などをinsertします。最後にinsertすることで続けて入力したものが表示できます。

clear_all()で表示を全削除します。電卓の[AC]の部分です。delete()で0から最後まで全ての値を削除するというコードになっています。

clear_one()で1文字削除します。電卓の[C]の部分です。まず、get()で入力されたものをtxtに一旦保持しておきます。delete()で0から最後まで削除して、insertで先ほどのtxtを表示するのですが、0から最後の一個手前をtxt[:-1]と指定することで1文字を削除しています。

equals()で[=]の部分を設定します。まず入力されている文字列をget()で取得し、eval()で計算式と評価させます。eval()は、第1引数をPythonでの式として解析して評価する関数です。一緒に、計算式にならない文字列÷、×、%をreplece()で本来の演算子に置き換えています。一旦表示をdelete()で削除して、再度置き換えて計算した値をinsertで挿入して表示させます。

そして、今度はcreate_widgets()で各種表示を設定していきます。

def create_widgets(self):
        file_menu = tk.Menu(self.menu_bar)
        file_menu.add_command(label='閉じる', command=self.master.quit)
        self.menu_bar.add_cascade(label='メニュー', menu=file_menu)

        self.entry.grid(row=0, column=0, columnspan=4, pady=3)
        self.entry.focus_set()

        tk.Button(self.master, text='7', width=4,
                  command=lambda: self.input(7)).grid(row=2, column=0)
        tk.Button(self.master, text='8', width=4,
                  command=lambda: self.input(8)).grid(row=2, column=1)
        tk.Button(self.master, text='9', width=4,
                  command=lambda: self.input(9)).grid(row=2, column=2)

まず、ファイルメニューです。Menu()で最初に定義したmenu_barを組み込んでいきます。add_command()で「閉じる」のラベルと、quitでアプリを終了するコマンドを設定します。add_cascade()でメニューがプルダウン表示されるようにします。

entry.grid()で入力表示欄の位置を設定しています。最初に示したrowとcolumnの位置を参考にすればやっていることがわかるでしょう。padyはy軸方向の外枠の幅です。focus_set()で入力待ちの表示がされます。

次はボタンです。Button()にそれぞれ設定していきます。textにボタンの表示するラベルを指定します。withでボタンの幅を指定し、commandにはここではlambdaを使って関数を与えています。textで与えたラベルの位置をgrid()を使ってrowとcolumnで指定しています。

あとは全てのボタンを同様に設定していけばいいですね。

        tk.Button(self.master, text='4', width=4,
                  command=lambda: self.input(4)).grid(row=3, column=0)
        tk.Button(self.master, text='5', width=4,
                  command=lambda: self.input(5)).grid(row=3, column=1)
        tk.Button(self.master, text='6', width=4,
                  command=lambda: self.input(6)).grid(row=3, column=2)

        tk.Button(self.master, text='1', width=4,
                  command=lambda: self.input(1)).grid(row=4, column=0)
        tk.Button(self.master, text='2', width=4,
                  command=lambda: self.input(2)).grid(row=4, column=1)
        tk.Button(self.master, text='3', width=4,
                  command=lambda: self.input(3)).grid(row=4, column=2)

        tk.Button(self.master, text='0', width=9,
                  command=lambda: self.input(0)).grid(row=5, column=0, columnspan=2)
        tk.Button(self.master, text='.', width=4,
                  command=lambda: self.input('.')).grid(row=5, column=2)
        tk.Button(self.master, text='=', width=4,
                  command=self.equals).grid(row=5, column=3)

        tk.Button(self.master, text='x', width=4,
                  command=lambda: self.input('x')).grid(row=2, column=3)
        tk.Button(self.master, text='-', width=4,
                  command=lambda: self.input('-')).grid(row=3, column=3)
        tk.Button(self.master, text='+', width=4,
                  command=lambda: self.input('+')).grid(row=4, column=3)

[0]の部分はボタンの幅とcolumnの長さが他と違うので調整しています。[=]のところは、input()ではなく、equalsを使っています。

        tk.Button(self.master, text='AC', width=4,
                  command=lambda: self.clear_all()).grid(row=1, column=0)
        tk.Button(self.master, text='C', width=4,
                  command=lambda: self.clear_one()).grid(row=1, column=1)
        tk.Button(self.master, text='%', width=4,
                  command=lambda: self.input('%')).grid(row=1, column=2)
        tk.Button(self.master, text='÷', width=4,
                  command=lambda: self.input('÷')).grid(row=1, column=3)

残りの記号の部分です。commandの部分がそれぞれ違います。

最後に、お決まりごとの部分を記述して終わりです。

root = tk.Tk()
app = Application(master=root)
app.mainloop()

この部分は最初の冒頭部分と一緒に書いて、間にコードを入力していった方がいいかもしれませんね。そうすれば、入力の途中でコードを実行してボタンの位置などの表示を確認しながら調整することができますからね。

ということで、これで簡易な計算機の完成です。

このコードを実行してみると、計算機として本当に機能するかな?

スポンサーリンク

作った計算機の全コード

最後にコード全体を示しておきます。

import tkinter as tk


class Application(tk.Frame):

    def __init__(self, master=None):
        super().__init__(master)
        self.master.geometry()
        self.master.title('計算機')

        self.entry = tk.Entry(self.master, justify="right")

        self.menu_bar = tk.Menu(self.master)
        self.master.config(menu=self.menu_bar)

        self.create_widgets()

    def input(self, action):
        self.entry.insert(tk.END, action)

    def clear_all(self):
        self.entry.delete(0, tk.END)

    def clear_one(self):
        txt = self.entry.get()
        self.entry.delete(0, tk.END)
        self.entry.insert(0, txt[:-1])

    def equals(self):
        self.value = eval(self.entry.get().replace('÷', '/').replace('x', '*').replace('%', '/100'))
        self.entry.delete(0, tk.END)
        self.entry.insert(0, self.value)

    def create_widgets(self):
        file_menu = tk.Menu(self.menu_bar)
        file_menu.add_command(label='閉じる', command=self.master.quit)
        self.menu_bar.add_cascade(label='メニュー', menu=file_menu)

        self.entry.grid(row=0, column=0, columnspan=4, pady=3)
        self.entry.focus_set()

        tk.Button(self.master, text='7', width=4,
                  command=lambda: self.input(7)).grid(row=2, column=0)
        tk.Button(self.master, text='8', width=4,
                  command=lambda: self.input(8)).grid(row=2, column=1)
        tk.Button(self.master, text='9', width=4,
                  command=lambda: self.input(9)).grid(row=2, column=2)

        tk.Button(self.master, text='4', width=4,
                  command=lambda: self.input(4)).grid(row=3, column=0)
        tk.Button(self.master, text='5', width=4,
                  command=lambda: self.input(5)).grid(row=3, column=1)
        tk.Button(self.master, text='6', width=4,
                  command=lambda: self.input(6)).grid(row=3, column=2)

        tk.Button(self.master, text='1', width=4,
                  command=lambda: self.input(1)).grid(row=4, column=0)
        tk.Button(self.master, text='2', width=4,
                  command=lambda: self.input(2)).grid(row=4, column=1)
        tk.Button(self.master, text='3', width=4,
                  command=lambda: self.input(3)).grid(row=4, column=2)

        tk.Button(self.master, text='0', width=9,
                  command=lambda: self.input(0)).grid(row=5, column=0, columnspan=2)
        tk.Button(self.master, text='.', width=4,
                  command=lambda: self.input('.')).grid(row=5, column=2)
        tk.Button(self.master, text='=', width=4,
                  command=self.equals).grid(row=5, column=3)

        tk.Button(self.master, text='x', width=4,
                  command=lambda: self.input('x')).grid(row=2, column=3)
        tk.Button(self.master, text='-', width=4,
                  command=lambda: self.input('-')).grid(row=3, column=3)
        tk.Button(self.master, text='+', width=4,
                  command=lambda: self.input('+')).grid(row=4, column=3)

        tk.Button(self.master, text='AC', width=4,
                  command=lambda: self.clear_all()).grid(row=1, column=0)
        tk.Button(self.master, text='C', width=4,
                  command=lambda: self.clear_one()).grid(row=1, column=1)
        tk.Button(self.master, text='%', width=4,
                  command=lambda: self.input('%')).grid(row=1, column=2)
        tk.Button(self.master, text='÷', width=4,
                  command=lambda: self.input('÷')).grid(row=1, column=3)


root = tk.Tk()
app = Application(master=root)
app.mainloop()

以上です。ちょっとボタンのコードの順番をみやすく書く工夫も必要かもしれません。

スポンサーリンク

まとめ

ここではPythonのtkinterを扱いました。

tkinterパッケージは、ほとんどのUnixプラットフォームやWindows上で利用できるTk GUI ツールキットをPythonで利用するためのインタフェースです。

これを使って簡単なアプリの確認と、簡易な電卓のアプリのコードを書いてみました。コードとアプリを対応させながら見ていくのも良いと思います。

(追記)

AnacondaのPython3.7はtkinterに不具合が生じることもあるようです。

MacのAnacondaをアンインストールする - Python3.7でTkinter等に不具合?
MacのAnacondaをアンインストールする方法を扱います。Python3.7にcondaでアップデートすると、TkinterやIDLEを起動するとMacがログアウトして使えない症状が出ました。Anacondaをアンインストールして公式サイトのPythonで代用します。

Python公式サイトのものをインストールすれば問題なくtkinterは利用できます。

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