\

PythonのGUIライブラリであるPySideでは、時間のかかる処理をスレッド化するためにQThreadを使用します。Pythonの標準モジュールにはthreadingがありますが、PySideを使っている場合や、Signal/Slotなど、Qtとの対話を行う場合はQThreadを使った方が良いとされています。

QtにはQtConcurrentというQThreadよりも高レベルなAPIがありますが、PySideでは提供されていないようです。そのため、この記事ではQThreadを使ったマルチスレッド処理について説明します。

以下に、QThreadmoveToThreadを使ったスレッド化のサンプルコードを示します。

import sys, threading
from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QVBoxLayout
from PySide6.QtCore import Qt, QObject, QThread, Signal, Slot
import shiboken6
import time

class Worker(QObject):
    """バックグラウンドで処理を行うクラス"""
    countup = Signal(int)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.__is_canceled = False

    def run(self):
        print(f'worker started, thread_id={threading.get_ident()}')
        count = 0
        while not self.__is_canceled:
            count += 1
            self.countup.emit(count)
            time.sleep(0.001)
        print(f'worker finished, thread_id={threading.get_ident()}')

    def stop(self):
        self.__is_canceled = True

class MainWindow(QWidget):
    """メインウィンドウ"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.__thread = None
        layout = QVBoxLayout()
        button = QPushButton('Start')
        button.clicked.connect(self.__start)
        layout.addWidget(button)
        button = QPushButton('Stop')
        button.clicked.connect(self.__stop)
        layout.addWidget(button)
        self.__label = QLabel()
        layout.addWidget(self.__label)
        self.setLayout(layout)

    def __start(self):
        """開始"""
        print(f'start, thread_id={threading.get_ident()}')
        self.__stop()
        self.__thread = QThread()
        self.__worker = Worker()
        self.__worker.moveToThread(self.__thread)  # 別スレッドで処理を実行する
        # シグナルスロットの接続(self.__countup をスレッド側で実行させるために Qt.DirectConnection を指定)
        self.__worker.countup.connect(self.__countup, type=Qt.DirectConnection)
        # スレッドが開始されたら worker の処理を開始する
        self.__thread.started.connect(self.__worker.run)
        # スレッドが終了したら破棄する
        self.__thread.finished.connect(self.__worker.deleteLater)
        self.__thread.finished.connect(self.__thread.deleteLater)
        self.__thread.start()

    def __stop(self):
        """停止"""
        if self.__thread is not None:
            self.__worker.stop()
            self.__thread.quit()
            self.__thread.wait()
            self.__thread = None
            self.__worker = None

    def __countup(self, count):
        """カウントアップ"""
        self.__label.setText(str(count))

このコードでは、Workerクラスがバックグラウンドで時間のかかる処理を行い、その結果をメインウィンドウに通知します。WorkerクラスはQObjectを継承しており、QThreadに移動(moveToThread)されて別スレッドで実行されます。

以上がPythonとQtのQThreadを使ったマルチスレッド処理の基本的な使い方です。GUIアプリケーションの応答性を保つためには、このようなマルチスレッド処理が重要となります。

投稿者 admin

コメントを残す

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