15

複数のスレッドを生成するPySide(Qt)GUIがあります。スレッドはGUIを更新する必要がある場合があります。私はこれを次の方法で解決しました:

class Signaller(QtCore.QObject) :
    my_signal = QtCore.Signal(QListWidgetItem, QIcon)
signaller = Signaller()

class MyThread(threading.Thread):
    def __init__(self):
        super(IconThread, self).__init__()
        # ...

    def run(self) :
        # ...

        # Need to update the GUI
        signaller.my_signal.emit(self.item, icon)

#
# MAIN WINDOW        
# 
class Main(QtGui.QMainWindow):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        # ...

        # Connect signals
        signaller.my_signal.connect(self.my_handler)

    @QtCore.Slot(QListWidgetItem, QIcon)
    def my_handler(self, item, icon):
        item.setIcon(icon)

    def do_something(self, address):
        # ...

        # Start new thread 
        my_thread = MyThread(newItem)
        my_thread.start()

    # ...

もっと簡単な方法はありますか?シグナル、ハンドラーを作成し、それらを接続するには、数行のコードが必要です。

4

2 に答える 2

19

最近PySideでコーディングを開始しましたが、PyGObjectのGLib.idle_add動作と同等のものが必要でした。私はあなたの答え(https://stackoverflow.com/a/11005204/1524507)に基づいてコードを作成しましたが、これはキューを使用する代わりにイベントを使用します。

from PySide import QtCore


class InvokeEvent(QtCore.QEvent):
    EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())

    def __init__(self, fn, *args, **kwargs):
        QtCore.QEvent.__init__(self, InvokeEvent.EVENT_TYPE)
        self.fn = fn
        self.args = args
        self.kwargs = kwargs


class Invoker(QtCore.QObject):
    def event(self, event):
        event.fn(*event.args, **event.kwargs)

        return True

_invoker = Invoker()


def invoke_in_main_thread(fn, *args, **kwargs):
    QtCore.QCoreApplication.postEvent(_invoker,
        InvokeEvent(fn, *args, **kwargs))

これは、上記の回答リンクで同じように使用されます。

于 2012-08-26T02:06:05.993 に答える
7

これは私がこれまでに持っているものです。ヘルパー モジュールのどこかに次のコードを書きました。

from Queue import Queue
class Invoker(QObject):
    def __init__(self):
        super(Invoker, self).__init__()
        self.queue = Queue()

    def invoke(self, func, *args):
        f = lambda: func(*args)
        self.queue.put(f)
        QMetaObject.invokeMethod(self, "handler", QtCore.Qt.QueuedConnection)

    @Slot()
    def handler(self):
        f = self.queue.get()
        f()
invoker = Invoker()

def invoke_in_main_thread(func, *args):
    invoker.invoke(func,*args)

その後、私のスレッドは非常に簡単にコードを実行して、メイン スレッドで GUI を更新できます。操作ごとに信号を作成して接続する必要はありません。

class MyThread(threading.Thread):
    def __init__(self):
        super(IconThread, self).__init__()
        # ...

    def run(self) :
        # ...

        # Need to update the GUI
        invoke_in_main_thread(self.item.setIcon, icon)

このようなものはとてもいいと思います。

于 2012-06-12T21:32:57.143 に答える