简体   繁体   中英

Altering PySide.QtGui.QListWidget with an emitted signal from a multiprocessing.Pool async call results in Runtime Error?

I have:

from PySide.QtCore import Signal, QObject
from multiprocessing import Pool

def some_computation():
    pass
    # ..some computations
    return 'result'

class MyClass(QObject):

    my_signal = Signal()

    def __init__(self):
        self.mylistwidget = # ... QListWidget from somewhere

        # bind the signal to my slot
        self.my_signal.connect(self.on_my_signal)

    # this is called after computation thread is finished
    def my_callback_fct(result):
        # ..bla bla
        self.my_signal.emit()

    # this is the function I call
    def do_some_async_computation(self)
        pool = Pool(processes=2)
        pool.apply_async(target=some_computation, callback=my_callback_fct)

    # this is the slot
    def on_my_signal(self):
        self.mylistwidget.clear()

I read around stackoverflow that in order to change the gui from a secondary execution thread one must use slot-signal mechanism, which is what I did in MyClass , although when I call do_some_async_computation I would expect the pool to initiate a secondary thread for some_computation function ..which happens, after the computation is finished the my_callback_fct is executed accordingly, which emits a my_signal signal that is connected to the on_my_signal slot, which is executed as expected, but when altering the self.mylistwidget it gives a Runtime Error / QWidget runtime error redundant repaint detected

I haven't observed your actual error, but in a similar scenario we use a QueuedConnection to ensure the signal is passed correctly from one thread to the other. This is done automagically for some people if the objects in question belong to different threads (QObject have a notion of the QThread that owns them). But in your case, all is done on one object, so Qt can't know. Do

from PyQt5.QtCore import Qt
...
self.my_signal.connect(self.on_my_signal, Qt.QueuedConnection)

I solved this by using a QtCore.QThread instead of multiprocessing.Pool . I was thinking about the mechanism you talked about @deets and I said to myself that it should be in in the same context in order for Qt.QueuedConnection to work, so that's why I wanted to go with QThread .

class MyComputationalThread(PySide.QtCore.QThread):

    data_available = PySide.QtCore.Signal(str)
    def run(self):
        result = # ... do computations
        serialized_result = json.dumps(result) #  actually I use JSONEncoder here
        self.data_available.emit(serialized_result)

... and in my MyClass :

class MyClass(QObject):
    # ...
    mythread = MyComputationalThread()
    # ...

    def __init__(self):
        # ...
        self.mythread.connect(do_something_with_serialized_data, PySide.QtCore.Qt.QueuedConnection)
        # ...

It works like a charm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM