QPixmap:在GUI线程之外使用pixmaps是不安全的

时间:2014-12-29 01:04:49

标签: python c++ multithreading qt pyside

我正在使用PySide制作GUI应用程序。我有3个类:一个QWidget类,一个QThread Worker类和一个Worker类的控制器。 GUI类创建一个控制器对象,该对象在该层次结构中生成给定数量的工作线程:

class Worker(QtCore.QThread):
    # Signal that tells the controller the current progress of the
    # thread.
    sig_worker_update_progress = QtCore.Signal(int, int)

    def __init__(self, thread_id, *args, **kwargs):
        super(Worker, self).__init__(*args, **kwargs)
        self.thread_id = thread_id

    def run(self):
        # Enter
        # Loop
        self.sig_worker_update_progress.emit(self.thread_id, progress)
        # Continue
        # Loop

class Controller(QtCore.QObject):
    sig_controller_update_progress = QtCore.Signal(int, int)

    def __init__(self, num_workers, *args, **kwargs):
        super(Controller, self).__init__(*args, **kwargs)

        self.workers = []
        for i in range(num_workers):
            self.workers.append(Worker(i))
            self.workers[i].sig_worker_update_progress.connect(
                self.slot_worker_update_progress)
        for worker in self.workers:
            worker.start() 

    def slot_worker_update_progress(self, thread_id, progress):
        # Do
        # Stuff
        self.sig_controller_update_progress.emit(thread_id, progress)


class Monitor(QtGui.QWidget):
    def __init__(self, num_workers, *args, **kwargs):
        super(Monitor, self).__init__(*args, **kwargs)
        main_layout = QtGui.QVBoxLayout()
        self.setLayout(main_layout)
        self.progress_bars = []

        for _ in range(num_workers):
            progress_bar = QtGui.QProgressBar()
            main_layout.addWidget(progress_bar)
            self.progress_bars.append(progress_bar)

        self.controller = Controller(num_workers)
        self.controller.sig_controller_update_progress.connect(
            self.slot_controller_update_progress)

    def slot_controller_update_progress(self, thread_id, progress):
        self.progress_bars[thread_id].setValue(progress)

请注意,上面显示的连接调用使用QtCore.Qt.AutoConnection作为连接的type(默认情况下,因为未指定关键字参数)。上面代码中缺少的是导致线程在用户单击窗口小部件上的按钮时退出的功能,以及在单击另一个按钮时创建新线程的其他功能。

单击中断按钮时,我注意到有些项目仍保留在Signal的发射队列中。这是出乎意料的,但我发现这是Qt的标准行为,因为the connections are queued by default。我不希望任何东西留在队列中,所以我决定使用DirectConnection进行两个连接。当我这样做时,我的应用程序将运行几秒钟,然后崩溃并输出以下内容:

  

QPixmap:在GUI线程之外使用pixmaps是不安全的

     

QPixmap:在GUI线程之外使用pixmaps是不安全的

     

QPainter :: begin:画图设备返回引擎== 0,键入:2

     

QPainter :: end:画家未激活,已中止

     

分段错误(核心转储)

我研究了这个错误。显然,threads are not allowed to handle GUI objects directly。推荐的方法正是我所做的:使用信号和插槽。

更令人好奇的是,如果我对其中一个连接使用AutoConnection而另一个连接使用DirectConnection,那么应用程序运行正常(除了残留的发送项目,这会混淆我的最终输出)。

我需要来自Qt更有经验的人的启发,了解这里可能发生的事情。

0 个答案:

没有答案