【Python】Tkinter画面遷移-複数ウィンドウをクラス化

当サイトで紹介する商品・サービス等の外部リンクは、アフィリエイト広告を含む場合があります。
スポンサーリンク
本記事を読むと以下の実行ができます

数値を入れて開始をするとウィンドウを切り替えてカウントダウンをする

Tkinterで画面切り替え

TkinterはPythonを使って、デスクトップアプリケーションを作ることができるライブラリです。

Tkinterの1つのウィンドウを使ってソフトを動かすことが可能ですが、
画面遷移を用いて、複数のウィンドウを表示する方が利便性が良いことがあります。

例えば、ログインフォームを作るとき画面を2つにして、
ログイン情報を入力、認証ができたら画面遷移で個人ページに進む。

このように画面の切り替えは、ユーザーが使いやすいGUIの作成につながります。

本記事では、複数のウィンドウを扱う方法(画面遷移)について紹介します。

本記事は次の人におすすめ
  • Pythonでデスクトップアプリケーションを作れるようになりたい
  • Tkinterの画面切り替え(画面遷移)で複数ウィンドウを操作したい
  • 画面遷移のクラス化をしたい
Udemyで学習する
スポンサーリンク

Tkinter画面切り替え

Tkinterの画面切り替えするには、pack_forget()メソッドを使用します。
稼働させるウィンドウの数だけ関数を作り、この関数を表示・非表示を入れ替えて行います。

単純な画面切り替え

以下に、簡単なコードを紹介します。

import tkinter as tk

def show_screen_a():
    screen_a.pack()
    screen_b.pack_forget()

def show_screen_b():
    screen_a.pack_forget()
    screen_b.pack()

root = tk.Tk()
root.title("画面切り替え")
root.geometry("250x50")

# スクリーンAのフレーム
screen_a = tk.Frame(root)
screen_a.pack()

label_a = tk.Label(screen_a, text="ScreenA")
label_a.pack()

button_a = tk.Button(screen_a, text="To B", command=show_screen_b)
button_a.pack()

# スクリーンBのフレーム
screen_b = tk.Frame(root)
screen_b.pack()

label_b = tk.Label(screen_b, text="ScreenB")
label_b.pack()

button_b = tk.Button(screen_b, text="To A", command=show_screen_a)
button_b.pack()

# 最初はスクリーンAを表示
show_screen_a()

root.mainloop()

show_screen_a()とshow_screen_b()関数を使用して、
スクリーンAとスクリーンBの表示を切り替えています。

ラベル表示が変わっていますが、文字を変えているのではなく、
ボタンをクリックすることで画面が遷移しています。

Tkinterのラベル表示についてまとめています。

ボタンのcommandパラメータにそれぞれの関数を指定し、
ボタンが押されて関数show_screen_a()の時はスクリーンBに関するものは非表示、
show_screen_b()の時はスクリーンAに関するものは非表示としています。

Tkinterのボタン表示とボタンとdef関数を連携についてまとめています。

クラス化した場合の画面遷移

Tkinterにおけるクラス化とは、PythonのGUIライブラリであるTkinterをオブジェクト指向プログラミングの方法で使うために、
Tkinterのウィジェットやイベント処理をクラスとして定義することを指します。

Tkinterをクラス化する場合、tk.Tkを継承したクラスを作成し、
そのクラス内でウィジェットやイベント処理を定義します。

クラス化のメリット
  • 可読性の向上: GUI要素やイベント処理が分かりやすく整理される。
  • 再利用性の向上: 同じクラスを他のプロジェクトや異なるウィンドウのテンプレートとして使える。
  • メンテナンスがしやすい: 複雑なアプリケーションでもコードが整理され、修正や機能追加が容易になる。
import tkinter as tk

class ChangeScreen(tk.Tk):
    def show_screen_a(self):
        self.screen_a.pack()
        self.screen_b.pack_forget()

    def show_screen_b(self):
        self.screen_a.pack_forget()
        self.screen_b.pack()
        
    def __init__(self):
        super().__init__()
        self.title("画面切り替え")
        self.geometry("250x50")


        # スクリーンAのフレーム
        self.screen_a = tk.Frame(self)
        self.screen_a.pack()

        self.label_a = tk.Label(self.screen_a, text="ScreenA")
        self.label_a.pack()

        self.button_a = tk.Button(self.screen_a, text="To B", command=self.show_screen_b)
        self.button_a.pack()

        # スクリーンBのフレーム
        self.screen_b = tk.Frame(self)
        self.screen_b.pack()

        self.label_b = tk.Label(self.screen_b, text="ScreenB")
        self.label_b.pack()

        self.button_b = tk.Button(self.screen_b, text="To A", command=self.show_screen_a)
        self.button_b.pack()

        # 最初はスクリーンAを表示
        self.show_screen_a()

if __name__ == "__main__":
    app = ChangeScreen()
    app.mainloop()

このコードでは、ChangeScreenクラスがアプリケーションのメインクラスになります。
Pythonで関数を登録する際は、def関数を使いますが、多用してしまうとコードが読みづらくなります。
def関数の代わりに、Classで一つにまとめれば、コードが見やすくなります。

クラス化すると、「if name==”main”:」というコードを使うようになります。
消去してもプログラムは正常に処理されますが、classを使う場合は入れておくべきです。

そもそも、「if name==”main”:」は、他のスクリプトからインポートされた場合、if文以下が実行されないようにします。

例えば、あるスクリプトがモジュールとして他のスクリプトでインポートした場合、そのスクリプトだけで有効な初期化処理や関数定義があると、これらが不用意に実行されてしまいます。

この問題を避けるためにも処理をクラス化した場合は、「if name==”main”:」を使用しましょう。

画面遷移型カウントダウンタイマー

画面切り替え(画面遷移)は、ユーザーからテキストボックスで入力されて、
ボタンを押すことで、画面が切り替わるというプログラムが多いです。

本記事ではユーザーに数値を入力してボタンが押されると、
その値を取得し、画面遷移をして、カウントを進めるタイマーを作成します。
また、タイマーが終了した際はウィンドウが通知を流します。

一定時間処理を止めるsleep関数(timeモジュール)を使うことでもカウントダウンタイマーは作成可能です。

ソースコード

import tkinter as tk
from tkinter import messagebox

# メインウィンドウを作成する
root = tk.Tk()
root.title("カウントダウンタイマー")

#ウィンドウのサイズ
root.geometry("300x150")

def start_countdown():
    global time_remaining

    # 入力した時間を取得
    input_time = int(entry.get())

    if input_time > 0:
        # 入力した時間を設定
        time_remaining = input_time +1

        # 入力画面を非表示にし、カウントダウン画面を表示する
        entry.pack_forget()
        start_button.pack_forget()
        label.pack(padx=20, pady=40)

        # カウントダウンを開始する
        countdown()
    else:
        messagebox.showerror("エラー", "正の数を入力してください。")

def countdown():
    global time_remaining

    # 残り時間を1秒減らす
    time_remaining -= 1

    # ラベルのテキストを更新する
    label.config(text=str(time_remaining))

    if time_remaining > 0:
        # 1秒後に再びcountdown関数を呼び出す
        root.after(1000, countdown)
    else:
        # カウントダウンが0になったらメッセージボックスを表示する
        messagebox.showinfo("終了", "カウントダウンが終了しました!")
        # ラベルを非表示にし、再度入力画面を表示する
        label.pack_forget()
        entry.pack()
        start_button.pack()

# 入力欄を作成する
entry = tk.Entry(root, font=("Helvetica", 24))
entry.pack(padx=20, pady=20)

# カウントダウンを開始するボタンを作成する
start_button = tk.Button(root, text="開始", command=start_countdown)
start_button.pack(side="bottom")

# 残り時間を表示するためのラベルを作成する
label = tk.Label(root, font=("Helvetica", 48))

# Tkinterのイベントループを開始する
root.mainloop()

UdemyでPythonを学習

Udemyは、オンデマンド式の学習講座です。
趣味から実務まで使えるおすすめの講座を紹介します。




解説

はじめに、ライブラリとモジュールをインポートします。
messageboxモジュールは、メッセージボックスを表示、関数をします。
カウントが終了したときと0を含めた、負の数字を入力したときユーザーに知らせます。

参考ページ:「tkinter.messagebox — Tkinterのメッセージプロンプト

import tkinter as tk
from tkinter import messagebox

つづいて、tk.Tk()を呼び出して、メインウィンドウを作成します。
title()メソッドでウィンドウのタイトルを設定します。
geometry()メソッドでウィンドウのサイズを設定します。

# メインウィンドウを作成する
root = tk.Tk()
root.title("カウントダウンタイマー")

#ウィンドウのサイズ
root.geometry("300x150")

start_countdown()関数は、カウントダウンを開始するために呼び出されます。
入力した時間を取得し、時間が正の数であるかどうかを確認します。正の数であれば、カウントダウン画面を表示し、countdown()関数を呼び出してカウントダウンを開始します。
時間が0以下(負の値)の場合はエラーメッセージを表示します。

複数の関数で変数を共有するときはグローバル変数を使います。必要に応じて変数を変更や参照が可能です。ただし、ローカル変数とは異なり、グローバル関数はプログラムの可読性や保守性に影響を与える可能性があるため、注意が必要です。

def start_countdown():
    global time_remaining

    # 入力した時間を取得
    input_time = int(entry.get())

    if input_time > 0:
        # 入力した時間を設定
        time_remaining = input_time +1

        # 入力画面を非表示にし、カウントダウン画面を表示する
        entry.pack_forget()
        start_button.pack_forget()
        label.pack(padx=20, pady=40)

        # カウントダウンを開始する
        countdown()
    else:
        messagebox.showerror("エラー", "正の数を入力してください。")

countdown()関数は、カウントダウンを実行するために呼び出されます。残り時間を1秒減らし、config()メソッドを使用して「time_remaining」の数値をラベルのテキストを更新します。
ただし、str()関数を使っているので、数字ではなく文字列の変数です。

時間が0より大きい場合は、1秒後に再びcountdown()関数を呼び出します。時間が0になった場合は、終了メッセージを表示し、入力画面を再表示します。

def countdown():
    global time_remaining

    # 残り時間を1秒減らす
    time_remaining -= 1

    # ラベルのテキストを更新する
    label.config(text=str(time_remaining))

    if time_remaining > 0:
        # 1秒後に再びcountdown関数を呼び出す
        root.after(1000, countdown)
    else:
        # カウントダウンが0になったらメッセージボックスを表示する
        messagebox.showinfo("終了", "カウントダウンが終了しました!")
        # ラベルを非表示にし、再度入力画面を表示する
        label.pack_forget()
        entry.pack()
        start_button.pack()

tk.Entry()を呼び出して、入力欄を作成します。fontパラメータでフォントの設定を行い、pack()メソッドでウィンドウに配置します。

# 入力欄を作成する
entry = tk.Entry(root, font=24)
entry.pack(padx=20, pady=20)

tk.Button()を呼び出して、カウントダウンを開始するボタンを作成します。
ボタンのテキストは「開始」に設定し、commandパラメータにはカウントダウンを開始するためにstart_countdown()関数を指定します。
pack()メソッドを使用してボタンをウィンドウの底部に配置します。

# カウントダウンを開始するボタンを作成する
start_button = tk.Button(root, text="開始", command=start_countdown)
start_button.pack(side="bottom")

tk.Label()を呼び出して、残り時間を表示するためのラベルを作成します。fontパラメータでフォントの設定を行います。

# 残り時間を表示するためのラベルを作成する
label = tk.Label(root, font=48)

最後に、mainloop()メソッドを呼び出して、Tkinterのイベントループを開始します。これにより、ウィンドウが表示され、ユーザーの入力やボタンのクリックなどのイベントが処理されます。

# Tkinterのイベントループを開始する
root.mainloop()

まとめ

今回は、Tkinterの画面切り替えて複数ウィンドウを扱う方法を紹介しました。

Tkinterの画面切り替え(画面遷移)は、pack_forget()メソッドを使用します。
稼働させるウィンドウの数だけの関数を扱い、この関数を表示、非表示を入れ替えて行います。

A、Bの画面において、Aが表示されるとBに関するラベルやボタンは非表示。Bが表示されると、Aに関するラベルやボタンは非表示。という処理が行われます。

Udemyで学習する
タイトルとURLをコピーしました