【Tkinter】Pythonでデスクトップアプリを作成する方法

環境

  • Windows 10
  • Python 3.10.1
  • VSCode

使用するソースコード

以下の公開リポジトリに置いています

GitHub - masayan1126/tao-py-py: 作業自動化用 Python ライブラリ
作業自動化用 Python ライブラリ. Contribute to masayan1126/tao-py-py development by creating an account on GitHub.

Tkinterとは?

PythonでGUIを組むことのできるツールキット

GUI化することにより、Pythonスクリプトファイルをコンソール等から直接実行しなくてもよくなります。

動作イメージ

下図のような簡単なランチャーを作成してみたいと思います。ボタンをクリックすると任意のpythonプログラムが実行されます

事前準備

Tkinterは通常はPythonの標準ライブラリなので、特にインストール等は不要です

基本的な使用方法

GUIウインドウの作成

  • tkinterをインポートして、オブジェクトを作成
  • GUIのウインドウタイトルの設定
  • ウインドウサイズ(横x縦)の設定
import tkinter

root = tkinter.Tk()
root.title("Window Title")
root.geometry("400x300")

-----具体的な処理の内容はこの中に記載する

root.mainloop()
具体的な実行内容の処理はroot = Tkinter.Tk()とroot.mainloop()の間に記載します

上記のプログラムを実行すると、400px * 300pxのウインドウが表示されます

ラベルの作成

  • ラベルを作成し、今日の日付を引数として渡して画面上に表示します
  • tkinter.Label(text=)に引数としてラベルに表示する値を指定します
  • 部品.pack()とすることで、ウィンドウ上に部品を配置することが可能です
import datetime

・・・割愛
root.geometry("400x300")

today = datetime.date.today()

# ラベル
label = tkinter.Label(text=today)
label.pack()

root.mainloop()
今日の日付は、datetimeモジュールで簡単に生成することが可能です

上記のプログラムを実行すると、ウインドウ上に日付のラベルが表示されます

ラベルの配置

上記で作成したラベルをpackメソッドでウインドウの右上に配置します

部品の配置のためのメソッドには、大きく分けてpack, place, gridの3パターンがあります
  • packメソッドのanchor引数にtkinter.NEと指定することで、部品を右上に配置することが可能です
  • padxで横方向のpaddingを、padyで縦方向のpaddingを指定できます
# ラベル
label = tkinter.Label(text=today)
label.pack(anchor=tkinter.NE, padx=10, pady=5)

anchor一覧

項目内容
Tk.CENTER中央(デフォルト)
Tk.W左よせ
Tk.E右よせ
Tk.N上よせ
Tk.S下よせ
Tk.NW左上
Tk.SW左下
Tk.NE右上
Tk.SE右下

ここまでで、GUIが以下のようになります

import datetime
import tkinter

root = tkinter.Tk()
root.title("Window Title")
root.geometry("700x300")
today = datetime.date.today()

# ラベル
label = tkinter.Label(text=today)
label.pack(anchor=tkinter.NE, padx=10, pady=5)

root.mainloop()

ボタンの作成と配置

  • tkinter.Button()でボタンが作成できます
  • ボタンオブジェクトは、キー名を指定していろいろな情報を設定できます(ボタン名やクリック時に実行する関数 ※いったん適当に設定)
  • grid(配置する列, 配置する行)で該当の部品を配置する場所を指定し、stickyを指定してウィンドウサイズに応じて伸縮するようにします
部品の均等配置には、gridを使用すると実装しやすいです

stickyの設定値

stickyを使用すると、スペースに余裕がある場合、どこに配置するか・どのように引き伸ばすかを指定できます
項目内容
tk.CENTER中央
tk.W左寄せ
tk.E右寄せ
tk.N上寄せ
tk.S下寄せ
tk.NW左上
tk.SW左下
tk.NE(右上
tk.SE右下

各行・列の引き延ばし設定

  • 上記のstickyで部品自体の引き延ばしの設定と合わせて、ルート要素(ウィンドウ)に対しても設定を行う必要があります
  • 今回のランチャーでは、3*3の構成にしたいので、以下のように設定します
# 各行・列の引き伸ばし設定
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
root.grid_rowconfigure(0, weight=0)
root.grid_rowconfigure(1, weight=1)
root.grid_rowconfigure(2, weight=1)
weightを使用することにより、余白を配分するときの割合を数値で指定することができます(重みづけ)

ここまでで、GUIが以下のようになります

import datetime
import tkinter

root = tkinter.Tk()
root.title("Launcher")
root.geometry("400x200")

frame = tkinter.Frame(root, bg="red")

today = datetime.date.today()
# ラベル
label = tkinter.Label(text=today)
label.grid(column=0, row=0, sticky=tkinter.E, columnspan=3)

# ボタン *6
btn1 = tkinter.Button()
btn1["text"] = "勤怠"
btn1["command"] = root.destroy
btn1.grid(column=0, row=1, sticky="NSEW")

btn2 = tkinter.Button()
btn2["text"] = "②"
btn2["command"] = root.destroy
btn2.grid(column=1, row=1, sticky="NSEW")

btn3 = tkinter.Button()
btn3["text"] = "③"
btn3["command"] = root.destroy
btn3.grid(column=2, row=1, sticky="NSEW")

btn4 = tkinter.Button()
btn4["text"] = "④"
btn4["command"] = root.destroy
btn4.grid(column=0, row=2, sticky="NSEW")

btn5 = tkinter.Button()
btn5["text"] = "⑤"
btn5["command"] = root.destroy
btn5.grid(column=1, row=2, sticky="NSEW")

btn6 = tkinter.Button()
btn6["text"] = "⑥"
btn6["command"] = root.destroy
btn6.grid(column=2, row=2, sticky="NSEW")

# 各列の引き伸ばし設定
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_columnconfigure(2, weight=1)
root.grid_rowconfigure(0, weight=0)
root.grid_rowconfigure(1, weight=1)
root.grid_rowconfigure(2, weight=1)
root.mainloop()

ボタンのクリックイベント

  • [“command”]のキーにpythonで定義した関数やメソッドを代入することで、クリックイベントを設定できます
btn1 = tkinter.Button()
btn1["command"] = login.authenticate

login.py

def authenticate(): ...割愛
commandに指定する関数には()は不要です。付与してしまうとウィンドウを起動したタイミングで関数が実行されてしまいます。
これでクリックイベントが設定できましたのでひととおり完成です。

その他の部品

主なウィジェット一覧

ウィジェット名クラス名概要
フレームFrameウィジェットを格納する枠組みを作る
ラベルLabel文字列やイメージを表示する
メッセージMessage複数行の文字列を表示する
ボタンButtonボタンを作る
ラジオボタンRadiobuttonラジオボタンを作る
チェックボタンCheckbuttonチェックボタンを作る
リストボックスListboxリストボックスを作る
スクロールバーScrollbarスクロールバーを作る
スケールScaleスケールを作る
エントリーEntry1 行の文字列の入力と編集
メニューMenuメニューを作る
メニューボタンMenubuttonメニューボタンを作る
ビットマップBitmapビットマップを作る
キャンバスCanvasキャンバスを作る
テキストTextテキストの入力と編集
ラベルフレームLabelFrameラベル付きフレーム
スピンボックスSpinboxスピンボックスを作る
ペインウィンドウPanedWindowペインウィンドウを作る
最終的には以下のようなコードになりました
今回は処理を順番に記述していくだけでしたが、メンテナンス性を向上させるためにも、専用のクラスを用意して責務を分けてコードを記述することをお勧めします。
packages\my_lanchar\main.py
import tkinter
from packages.my_lanchar.lanchar import Lanchar
from shared.Domain.i_widget import IWidget

root = tkinter.Tk()
root.title("Launcher")
root.geometry("400x200")

# パーツの設定
lanchar: IWidget = Lanchar(root=root).build()

root.mainloop()
shared\Domain\i_widget.py
from abc import *

class IWidget(metaclass=ABCMeta):
    @abstractmethod
    def build(self) -> None:
        pass

    @abstractmethod
    def label(self):
        pass

    @abstractmethod
    def btn(self):
        pass
packages\my_lanchar\lanchar.py
import datetime
import tkinter
from typing import Callable, Optional
from packages.jobcan import login
from shared.Domain.i_widget import IWidget

class Lanchar(IWidget):
    def __init__(self, root) -> None:
        self.root = root
        frame = tkinter.Frame(root)

        # # 各列の引き伸ばし設定
        root.grid_columnconfigure(0, weight=1)
        root.grid_columnconfigure(1, weight=1)
        root.grid_columnconfigure(2, weight=1)
        root.grid_rowconfigure(0, weight=0)
        root.grid_rowconfigure(1, weight=1)
        root.grid_rowconfigure(2, weight=1)

    def build(self):
        label = self.label(datetime.date.today())
        label.grid(column=0, row=0, sticky=tkinter.E, columnspan=3)

        # ボタン
        btn1 = self.btn("勤怠", login.authenticate)
        btn1.grid(column=0, row=1, sticky="NSEW")

        btn2 = self.btn("②")
        btn2.grid(column=1, row=1, sticky="NSEW")

        btn3 = self.btn("③")
        btn3.grid(column=2, row=1, sticky="NSEW")

        btn4 = self.btn("④")
        btn4.grid(column=0, row=2, sticky="NSEW")

        btn5 = self.btn("⑤")
        btn5.grid(column=1, row=2, sticky="NSEW")

        btn6 = self.btn("⑥")
        btn6.grid(column=2, row=2, sticky="NSEW")
        return self
    def label(self, text: str):
        return tkinter.Label(text=text)

    def btn(self, text: str, command: Optional[Callable] = None):
        btn = tkinter.Button()
        btn["text"] = text
        btn["command"] = command
        return btn
Tkinterへの依存度を下げるために、インターフェースを作成し、それを実装する形で構築しています

Python学習におすすめの書籍

独習Python/山田祥寛【3000円以上送料無料】
bookfan 1号店 楽天市場店
¥ 3,300(2023/01/31 18:22時点)
タイトルとURLをコピーしました