PythonでGUIを別スレッドから更新する方法について説明します。この記事では、TkinterとAsyncioを使用して、一つのスレッドでTkinterのメインループを実行し、別のスレッドでAsyncioループを実行する例を示します。

まず、以下のコードを見てみましょう。

from tkinter import *
import asyncio
import threading
import random

class AsyncioThread(threading.Thread):
    def __init__(self, asyncio_loop, theWindow):
        self.asyncio_loop = asyncio_loop
        self.theWindow = theWindow
        self.maxData = len(theWindow.varData)
        threading.Thread.__init__(self)

    def run(self):
        self.asyncio_loop.run_until_complete(self.do_data())

    async def do_data(self):
        tasks = [self.create_dummy_data(number) for number in range(self.maxData)]
        completed, pending = await asyncio.wait(tasks)
        results = [task.result() for task in completed]
        print('\\n'.join(results))

    async def create_dummy_data(self, number):
        sec = random.randint(1, 3)
        data = '{}:{}'.format(number, random.random())
        await asyncio.sleep(sec)
        self.theWindow.varData[number].set(data)
        print('Thread-ID: {}\\tsec: {}\\n\\t{}'.format(threading.get_ident(), sec, data))
        return data

class TheWindow:
    def __init__(self, maxData):
        self.asyncio_loop = asyncio.get_event_loop()
        self.root = Tk()
        self.varData = []
        for i in range(maxData):
            self.varData.append(StringVar())
            self.varData[i].set('<default>')
        Button(master=self.root, text='Start Asyncio Tasks', command=lambda:self.do_asyncio()).pack()
        for i in range(maxData):
            Label(master=self.root, textvariable=self.varData[i]).pack()
        Button(master=self.root, text='Freezed???', command=self.do_freezed).pack()

    def do_freezed(self):
        print('Tkinter is reacting. Thread-ID: {}'.format(threading.get_ident()))

    def do_asyncio(self):
        thread = AsyncioThread(self.asyncio_loop, self)
        thread.start()

if __name__ == '__main__':
    window = TheWindow(5)
    window.root.mainloop()

このコードは、TkinterのGUIを別のスレッドから更新する方法を示しています。AsyncioThreadクラスは、非同期I/Oループを実行するためのスレッドを作成します。このループは、ダミーデータを作成し、それをTkinterのラベルに表示します。

この例では、AsyncioThreadクラスのdo_dataメソッドで複数のタスクを作成し、それらを非同期に実行します。各タスクは、ランダムな時間を待った後にダミーデータを作成し、それをTkinterのラベルに表示します。

このように、Pythonではスレッドと非同期I/Oを組み合わせて、GUIを別のスレッドから更新することが可能です。ただし、スレッド間でデータを共有する際には、データ競合を避けるために適切な同期メカニズムを使用することが重要です。

以上、PythonでGUIを別スレッドから更新する方法について説明しました。この情報が皆さんのPythonプログラミングに役立つことを願っています。

投稿者 admin

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です