Blog
ブログ

2021年5月31日

【Python入門】PythonでGUIアプリを作ってみよう!

こんにちは!AI部に所属しているTです!


普段の業務では、今AI系で流行りのプログラム言語Pythonをよく使っています。


みなさん、実はPythonでも簡単にGUIアプリケーションを作れるって知ってましたか?


今回は、PythonでのGUI作成の紹介と、個人的に少しわかりづらいと感じたところを簡単に解説したいと思います。


それでは、さっそく見ていきましょう!


PythonでもGUIを作れる!

Pythonには、いくつかGUI作成用ライブラリがありますが、今回は、デフォルトでPythonに入っているtkinterというライブラリを使って作成していきます。


まずは、試しに名前を入力すると挨拶を返してくれるGUIアプリを作ってみます。


ソースコードはこんな感じです。


import tkinter as tk

# 挨拶ボタンが押された時の処理
def greet():
    text_label["text"] = f"Hi {input_area.get()}!"

# ウィンドウの作成
app = tk.Tk()
app.geometry("200x200")

# 挨拶用ページ
greeting_frame = tk.Frame(app)
greeting_frame.pack(anchor="center", expand=True)

# 挨拶用のテキスト表示ラベル
text_label = tk.Label(greeting_frame, text="")
text_label.grid(row=0, column=0)

# 自分の名前を入れるテキストボックス
input_area = tk.Entry(greeting_frame)
input_area.grid(row=1, column=0)

# 挨拶ボタン
button = tk.Button(greeting_frame, text="挨拶", command=greet)
button.grid(row=1, column=1)

# GUIアプリの実行
app.mainloop()

これを実行すると…



入力してボタンを押すと…


詳しい説明は省きますが、こんな感じで、tkinterなら簡単にGUI作成を試すことができます。

基本はページを作って、その上に要素をぺたぺた貼っていくイメージです。

私が悩んだところ

1ページで完結する簡単なアプリならいいのですが、ちょっと複雑なアプリを作ろうとすると、少しわかりづらいところもあります。


ここでは、私が実際にGUIを作成していくなかで、少し悩んだ部分を共有したいと思います。


複数ページ間の遷移

最初にGUIでボタンやテキストをページに追加していった後、次にやりたくなるのが、違うページに移動することだと思います。


そういうときには、次の2パターンの方法が考えられます。


紙芝居方式

この方法は、ページをあらかじめ作っておいて、表示させたいページを最前面に持ってくることで、ページを移っていきます。


イメージとしてはこんな感じです。


実際にコードにすると下のような感じになります。

import tkinter as tk

# 指定したページを最前面に持ってくる関数
def changePage(page):
page.tkraise()

# アプリケーションの設定
app = tk.Tk()
app.geometry("200x200")
app.grid_columnconfigure(0, weight=1)
app.grid_rowconfigure(0, weight=1)

# メインページの作成
main_frame = tk.Frame(app, bg="white")
main_frame.grid(row=0, column=0, sticky="nsew")

main_label = tk.Label(main_frame, text="main")
main_label.pack(anchor="center", expand=True)

main_button = tk.Button(main_frame, text="change page", command=lambda:changePage(sub_frame))
main_button.pack(anchor="center", expand=True)

# サブページの作成
sub_frame = tk.Frame(app, bg="yellow")
sub_frame.grid(row=0, column=0, sticky="nsew")

sub_label = tk.Label(sub_frame, text="sub")
sub_label.pack(anchor="center", expand=True)

sub_button = tk.Button(sub_frame, text="change page", command=lambda:changePage(main_frame))
sub_button.pack(anchor="center", expand=True)

# 最初にメインページを最前面に持ってくる
main_frame.tkraise()

# アプリケーションの開始
app.mainloop()

 


作っては消す方式

この方法は、別のページを表示させるときは、今表示しているページを削除して、新しいページを作って表示させます。


イメージ図としてはこんな感じです。


実際にコードにすると下のような感じになります。

import tkinter as tk

# ページを削除する関数
def destroyPage(page):
    page.destroy()

# メインページを生成する関数
def make_main_frame():
    main_frame = tk.Frame(app, bg="white")
    main_frame.grid(row=0, column=0, sticky="nsew")

    main_label = tk.Label(main_frame, text="main")
    main_label.pack(anchor="center", expand=True)

    main_button = tk.Button(main_frame, text="change page", command=lambda:[make_sub_frame(), destroyPage(main_frame)])
    main_button.pack(anchor="center", expand=True)

# サブページを生成する関数
def make_sub_frame():
    sub_frame = tk.Frame(app, bg="yellow")
    sub_frame.grid(row=0, column=0, sticky="nsew")

    sub_label = tk.Label(sub_frame, text="sub")
    sub_label.pack(anchor="center", expand=True)

    sub_button = tk.Button(sub_frame, text="change page", command=lambda:[make_main_frame(), destroyPage(sub_frame)])
    sub_button.pack(anchor="center", expand=True)

# アプリケーションの設定
app = tk.Tk()
app.geometry("200x200")
app.grid_columnconfigure(0, weight=1)
app.grid_rowconfigure(0, weight=1)

# 最初にメインページを生成
make_main_frame()

# アプリケーションの開始
app.mainloop()

新しいウィンドウの生成

より複雑なアプリケーションを作ろうとすると、新しいウィンドウを生成して、そこにユーザにデータを入力してもらうなどを実装する必要がでてくると思います。


そういうときに、使うのが、tk.Toplevelです。


実際に使ってみたサンプルコードがこちらです。

import tkinter as tk

# サブウィンドウの生成
def makeWindow():
    sub_window = tk.Toplevel(app)
    sub_window.geometry("200x200")
    sub_window.configure(background="red")

    sub_label = tk.Label(sub_window, text="sub")
    sub_label.pack(anchor="center", expand=True)

# アプリケーションの設定
app = tk.Tk()
app.geometry("200x200")

# メインページを作成
main_frame = tk.Frame(app)
main_frame.pack(anchor="center", expand=True)

main_button = tk.Button(main_frame, text="make window", command=makeWindow)
main_button.pack(anchor="center", expand=True)

# アプリケーションの作成
app.mainloop()

クラス化で分かりやすく

PythonのGUIアプリケーションの作り方を調べていると、クラスを作成せずに「ぺたー」とコードを書いているサンプルによく出会います。(ここまでのサンプルとか)


とりあえず動かす分には問題ないですが、ある程度複雑なGUIアプリを作成しようとすると、管理や修正などが大変になり、自分以外の人がソースコードを見ても何がなんだか分からないものになってしまいます。


そこで、各ページはクラスにまとめて、分かりやすくするといいと思います。


試しに、ここまでで作ったソースコードをクラス化してみると次のような感じです。

import tkinter as tk

# メインページクラス
class MainPage(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.configure(bg="white")

        self.label = tk.Label(self, text="main")
        self.label.pack(anchor="center", expand=True)

        self.change_page_button = tk.Button(self, text="change page", command=lambda:changePage(master.sub_page))
        self.change_page_button.pack(anchor="center", expand=True)


# サブページクラス
class SubPage(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.configure(bg="yellow")

        self.label = tk.Label(self, text="sub")
        self.label.pack(anchor="center", expand=True)

        self.change_page_button = tk.Button(self, text="change page", command=lambda:changePage(master.main_page))
        self.change_page_button.pack(anchor="center", expand=True)

        self.make_window_button = tk.Button(self, text="make window", command=lambda:makeWindow(master))
        self.make_window_button.pack(anchor="center", expand=True)

# サブウィンドウクラス
class SubWindow(tk.Toplevel):
    def __init__(self, master):
        tk.Toplevel.__init__(self, master)
        self.geometry("200x200")
        self.configure(bg="red")

        self.label = tk.Label(self, text="sub window")
        self.label.pack(anchor="center", expand=True)

# アプリケーションクラス
class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.geometry("200x200")
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)

        # メインページ
        self.main_page = MainPage(self)
        self.main_page.grid(row=0, column=0, sticky="nsew")

        # サブページ
        self.sub_page = SubPage(self)
        self.sub_page.grid(row=0, column=0, sticky="nsew")

        self.main_page.tkraise()

# ページの移動
def changePage(page):
    page.tkraise()

# 新しいウィンドウの生成
def makeWindow(master):
    sub_window = SubWindow(master)

if __name__ == "__main__":
    # アプリケーションを開始
    app = App()
    app.mainloop()

おわりに

今回は、tkinterでのGUI作成を少し紹介しましたが、Pythonには他にもGUI作成のためのライブラリがあります。


Jupyter NotebookやGoogle Colabで簡単にPythonを試してみるだけでも楽しいですが、GUIアプリを作ってみると達成感もひとしおです。


皆さんも、ぜひ今流行りのPythonのいろんな一面を調べて使ってみてください!

このページの先頭へ