【Pythonを使いこなす100日】36日目:GUIインターフェースプログラミング_Tkinterの高度な機能の操作と例

目次

 コラムガイド 

1. 高度なGUI機能

1 テーマとスタイルをカスタマイズする

2 ドラッグ&ドロップ機能を実装する

 3 マルチスレッドと非同期プログラミング

2. 実践的なプロジェクト

1.ToDoアプリ

2. 画像ビューア

3. テキストエディタ

4 アニメーションとトランジションの追加

 5 マルチインターフェイスとマルチスレッドの例  


 コラムガイド 

コラム購読アドレス:https://blog.csdn.net/qq_35831906/category_12375510.html


1. 高度なGUI機能

1 テーマとスタイルをカスタマイズする

        カスタムのテーマとスタイルを使用すると、GUI アプリケーションの見栄えを良くすることができます。Tkinter を使用する場合、ttkthemesライブラリを使用してさまざまなテーマやスタイルを適用できます。

pip install ttkthemes

次に、次のサンプル コードを試して、さまざまなテーマとスタイルを適用します。 

import tkinter as tk
from tkinter import ttk
from ttkthemes import ThemedStyle

def change_theme():
    selected_theme = theme_var.get()
    style.set_theme(selected_theme)

root = tk.Tk()
root.title("Custom Theme Example")

style = ThemedStyle(root)

# 创建一个下拉框,用于选择主题
theme_var = tk.StringVar()
theme_var.set(style.theme_use())  # 默认选中当前主题

theme_dropdown = ttk.Combobox(root, textvariable=theme_var, values=style.theme_names())
theme_dropdown.pack()

# 创建一个按钮,用于应用选定的主题
apply_button = ttk.Button(root, text="Apply Theme", command=change_theme)
apply_button.pack()

label = ttk.Label(root, text="Custom Theme Example")
label.pack(padx=20, pady=20)

root.mainloop()

出力効果は次のとおりです。 

        この例では、ユーザーが別のテーマを選択できるドロップダウン ボックスを作成します。ユーザーがテーマを選択して「テーマを適用」ボタンをクリックすると、アプリケーションは選択したテーマに従って対応するスタイルを適用します。

        この例を実行してもさまざまなテーマの効果が表示されない場合は、オペレーティング システムと Python 環境の両方が「ttkthemes」ライブラリを正しくサポートしていることを確認してください。場合によっては、特定の環境では特定のテーマが適切に動作しないことがあります。この場合、別の環境でサンプルを実行して、さまざまなテーマが正しく表示されるかどうかを確認できます。

2 ドラッグ&ドロップ機能を実装する

        ドラッグ アンド ドロップ機能を使用すると、ユーザーはコントロールをある場所から別の場所にドラッグできます。Tkinter を使用したドラッグ アンド ドロップの例を次に示します。

import tkinter as tk

def on_drag_start(event):
    event.widget.start_x = event.x
    event.widget.start_y = event.y

def on_drag_motion(event):
    delta_x = event.x - event.widget.start_x
    delta_y = event.y - event.widget.start_y
    event.widget.place(x=event.widget.winfo_x() + delta_x, y=event.widget.winfo_y() + delta_y)
    event.widget.start_x = event.x
    event.widget.start_y = event.y

root = tk.Tk()

label = tk.Label(root, text="Drag me!")
label.place(x=50, y=50)
label.bind("<Button-1>", on_drag_start)
label.bind("<B1-Motion>", on_drag_motion)

root.mainloop()

出力は次のとおりです。 

 3 マルチスレッドと非同期プログラミング

         GUI プログラミングでは、アプリケーション インターフェイスの応答性とスムーズさを確保するために、マルチスレッドと非同期プログラミングが重要です。マルチスレッドを使用してバックグラウンドで時間のかかる操作を処理し、場合によってはユーザー インターフェイスのブロックを避けるために非同期プログラミングを使用します。これら 2 つの概念について詳しく説明し、サンプル コードを提供します。

マルチスレッド化

        マルチスレッドは、Python アプリケーションでモジュールを使用してthreading実現できます。これは、GUI インターフェイスをブロックしないように、時間のかかる操作 (ネットワーク要求や計算など) をバックグラウンドで実行する場合に便利です。

以下は、threadingスレッドが GUI インターフェース上のラベルの内容を更新するモジュールの使用例です。

import tkinter as tk
import threading
import time

def update_label():
    for i in range(100):
        label.config(text=f"Count: {i}")
        time.sleep(1)

root = tk.Tk()

label = tk.Label(root, text="Count: 0")
label.pack()

thread = threading.Thread(target=update_label)
thread.start()

root.mainloop()

 出力は次のとおりです。

         この例では、メイン スレッドの GUI イベント ループをブロックせずに、ラベルのコンテンツを更新する新しいスレッドを作成します。

 非同期プログラミング

        モジュールを使用すると、asyncioPython アプリケーションで非同期プログラミングが可能になり、同時タスクをより適切に処理できるようになります。非同期プログラミングは、IO 操作 (ネットワーク リクエストなど) が完了するまで待つ必要がある状況に適しています。

asyncioコルーチンがしばらく待機してから GUI 上のラベルを更新するモジュールを        使用する簡単な例を次に示します。

import tkinter as tk
import asyncio

async def update_label():
    for i in range(10):
        label.config(text=f"Count: {i}")
        await asyncio.sleep(1)

root = tk.Tk()

label = tk.Label(root, text="Count: 0")
label.pack()

async def main():
    await update_label()

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

root.mainloop()

        この例では、asyncioモジュールを使用してコルーチンを作成し、非同期イベント ループを使用してコルーチンを実行します。

        Tkinter などの GUI フレームワークには、マルチスレッドと非同期プログラミングに関していくつかの制限がある場合があることに注意してください。マルチスレッドまたは非同期プログラミングを行う場合は、潜在的な問題を回避するために、フレームワークの関連ルールとベスト プラクティスに従ってください。

        マルチスレッドと非同期プログラミングはどちらも、応答性の高い滑らかな GUI アプリケーションを保証することを目的としており、UI をブロックすることなくバックグラウンドでタスクを実行できるようにします。

2. 実践的なプロジェクト

1.ToDoアプリ

シンプルな To Do リスト アプリを使用すると、ユーザーはタスクを追加、編集、削除し、インターフェイスに表示できます。Tkinter ベースの例を次に示します。

import tkinter as tk
from tkinter import messagebox

def add_task():
    task = entry.get()
    if task:
        tasks_listbox.insert(tk.END, task)
        entry.delete(0, tk.END)
    else:
        messagebox.showwarning("Warning", "Please enter a task.")

def delete_task():
    selected_task = tasks_listbox.curselection()
    if selected_task:
        tasks_listbox.delete(selected_task)

root = tk.Tk()
root.title("To-Do List")

entry = tk.Entry(root)
entry.pack()

add_button = tk.Button(root, text="Add Task", command=add_task)
add_button.pack()

delete_button = tk.Button(root, text="Delete Task", command=delete_task)
delete_button.pack()

tasks_listbox = tk.Listbox(root)
tasks_listbox.pack()

root.mainloop()

 出力:

2. 画像ビューア

シンプルな画像ビューアを使用すると、画像ファイルを開いて表示できます。Tkinter ベースの例を次に示します。

import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk

def open_image():
    file_path = filedialog.askopenfilename(filetypes=[("Image files", "*.png *.jpg *.jpeg")])
    if file_path:
        image = Image.open(file_path)
        photo = ImageTk.PhotoImage(image)
        label.config(image=photo)
        label.photo = photo

root = tk.Tk()
root.title("Image Viewer")

open_button = tk.Button(root, text="Open Image", command=open_image)
open_button.pack()

label = tk.Label(root)
label.pack()

root.mainloop()

3. テキストエディタ

基本的なテキスト エディタを使用すると、ユーザーはテキスト ファイルを開いて、編集し、保存できます。Tkinter ベースの例を次に示します。

import tkinter as tk
from tkinter import filedialog

def open_file():
    file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
    if file_path:
        with open(file_path, "r") as file:
            text.delete("1.0", tk.END)
            text.insert(tk.END, file.read())

def save_file():
    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
    if file_path:
        with open(file_path, "w") as file:
            file.write(text.get("1.0", tk.END))

root = tk.Tk()
root.title("Text Editor")

open_button = tk.Button(root, text="Open File", command=open_file)
open_button.pack()

save_button = tk.Button(root, text="Save File", command=save_file)
save_button.pack()

text = tk.Text(root)
text.pack()

root.mainloop()

4 アニメーションとトランジションの追加

        GUI アプリケーションにアニメーションとトランジション効果を追加すると、ユーザー エクスペリエンスが向上し、アプリケーションがより魅力的になります。次の例は、Tkinter で単純な GUI アプリケーションを作成し、アニメーションとトランジションを追加する方法を示しています。

import tkinter as tk
import time

class AnimatedApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Animated GUI App")

        self.label = tk.Label(root, text="Welcome!", font=("Helvetica", 24))
        self.label.pack(pady=50)

        self.button = tk.Button(root, text="Animate", command=self.animate)
        self.button.pack()

    def animate(self):
        initial_x = self.label.winfo_x()
        target_x = 300  # Target x-coordinate for animation

        while initial_x < target_x:
            initial_x += 5  # Increment x-coordinate
            self.label.place(x=initial_x, y=100)
            self.root.update()  # Update GUI to reflect changes
            time.sleep(0.05)  # Add a short delay for animation effect

        self.label.config(text="Animation Complete!")

root = tk.Tk()
app = AnimatedApp(root)
root.mainloop()

 5 マルチインターフェイスとマルチスレッドの例  

        複数のウィンドウと複数のスレッドが組み合わされた状況を処理するには、UI の応答性とスレッドの安全性を確保するために慎重な取り扱いが必要です。次の例は、Tkinter でマルチウィンドウ アプリケーションを作成し、複数のスレッドを使用して時間のかかる操作を実行する方法を示しています。

import tkinter as tk
import threading
import time

class MainWindow:
    def __init__(self, root):
        self.root = root
        self.root.title("Multi-Window App")
        self.root.configure(bg="lightblue")  # Set background color

        self.open_button = tk.Button(root, text="Open New Window", command=self.open_new_window)
        self.open_button.pack()

    def open_new_window(self):
        new_window = tk.Toplevel(self.root)
        child_window = ChildWindow(new_window)

class ChildWindow:
    def __init__(self, root):
        self.root = root
        self.root.title("Child Window")
        self.root.configure(bg="lightgreen")  # Set background color

        # Calculate child window position within main window
        main_x = self.root.master.winfo_rootx()
        main_y = self.root.master.winfo_rooty()
        main_width = self.root.master.winfo_width()
        main_height = self.root.master.winfo_height()

        window_width = 300
        window_height = 200

        x_position = main_x + (main_width - window_width) // 2
        y_position = main_y + (main_height - window_height) // 2

        # Ensure the child window is within the main window boundaries
        if x_position < main_x:
            x_position = main_x
        if y_position < main_y:
            y_position = main_y

        self.root.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")

        self.label = tk.Label(root, text="Child Window", font=("Helvetica", 16), bg="lightgreen", fg="black")  # Set foreground color
        self.label.pack(pady=20)

        self.start_button = tk.Button(root, text="Start Task", command=self.start_task, bg="lightblue")  # Set button color
        self.start_button.pack()

    def start_task(self):
        thread = threading.Thread(target=self.long_running_task)
        thread.start()

    def long_running_task(self):
        self.start_button.config(state=tk.DISABLED)  # Disable the button during task
        for i in range(10):
            print(f"Task running: {i}")
            time.sleep(1)
        self.start_button.config(state=tk.NORMAL)  # Enable the button after task

root = tk.Tk()
app = MainWindow(root)
root.geometry("400x300")  # Set initial main window size

root.mainloop()

        この例では、メイン ウィンドウと子ウィンドウを作成します。「新しいウィンドウを開く」ボタンをクリックすると、新しいサブウィンドウが開きます。サブウィンドウ内に「タスクの開始」ボタンがあります。これをクリックすると、マルチスレッドタスク(時間のかかる操作をシミュレート)が開始され、タスクが無効になります。タスクの進行中はボタンをクリックし、タスクが完了したらボタンを再度有効にします。

次の点に注意してください。

  • 子ウィンドウを作成するために使用しますToplevel
  • モジュールを使用してthreadingマルチスレッドを実装します。ここでのタスクは待機の単純な例にすぎず、実際には時間のかかる操作になる可能性があります。
  • スレッドセーフではないためtkinter、時間のかかるタスクを実行するにはスレッドを使用して、必ずメイン スレッドで GUI 要素を操作してください。

スレッドの競合やインターフェイスのフリーズなどの問題を回避するには、スレッドのライフサイクル、状態、および GUI との対話を注意深く管理する必要があります。

おすすめ

転載: blog.csdn.net/qq_35831906/article/details/132295778