PySide和QProgressBar在不同的线程中更新

时间:2012-08-27 09:00:12

标签: python multithreading qt progress-bar pyside

这可能是一个很长的帖子,所以,提前感谢和我在一起直到最后。这是问题所在,(我认为这是一个相当基本的问题,只是我对PiSide和Qt的经验不足使我更难。)我有一个主窗口,其中有一个菜单项,假设为“Process”。代码如下 -

from PySide import QtCore, QtGui

class Ui_MainWindow(object):

      def setupUi(self, MainWindow, AppObj):
            .
            .
            self.statusbar = QtGui.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
            .
            .
            .
           self.actionProcess = QtGui.QAction(MainWindow)
           self.actionProcess.setObjectName("actionProcess")
           self.actionProcess.triggered.connect(self.myappObj.menuActionProcess) 
           .

这里self.myappobj指的是我创建的app类,它充当我的应用程序的主要逻辑控制器。代码 -

from PySide import QtCore, QtGui
from MainWindow import Ui_MainWindow

class App(QtGui.QDialog):
      def __init__(self, parent=None):
          self.__mainWindow = QtGui.QMainWindow()
          self.__mainWindowDesignContext = Ui_MainWindow()
          self.__mainWindowDesignContext.setupUi(self.__mainWindow, self)
          self.__mainWindow.show()
      def menuActionProcess(self):
          self.processThread = BatchProcesser()
          self.progressBar = QtGui.QProgressBar()
          statusBar.addWidget(self.progressBar)
          self.progressBar.show()
          self.progressBar.setMinimum(0)
          self.progressBar.setMaximum(100)
          QtCore.QObject.connect(self.processThread, QtCore.SIGNAL("progress(int)"),self.progressBar, QtCore.SLOT("setValue(int)"), QtCore.Qt.DirectConnection)
          if not self.processThread.isRunning():
              self.processThread.exiting = False
              self.processThread.start()

所以,很容易看出我在这里要做的是创建一个主窗口。添加一个名为“Process”的菜单,单击该菜单会触发app类中的回调menuActionProcess方法,我在其中创建一个进度条并将其附加到我主窗口的状态栏(实际代码还有很多其他内容,我在这里给出的是作为伪示例重新排列的必要部分) 最后在上面代码中提到的BatchProcesser类中,我这样做 -

from PySide.QtGui import *
from PySide.QtCore import *

class BatchProcesser(QThread):
     __errorHappened = False
     def __init__(self, parent=None):
         QThread.__init__(self, parent)
         self.exiting = False
     def run(self):
         for a in range(101):
            print a
            QThread.msleep(100)
            self.emit(SIGNAL("progress(int)"), a)
            print a

根据我的理解,这应该在与主线程不同的线程中更新状态栏附带的进度条。这将允许用户自由地与GUI交互。

现在,如果我尝试冲洗这个,一切都很好,直到我点击Process菜单。然后,进度条会缓动但不会更新,控制台已满,错误 -

  

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

     

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

     

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

     

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

     

0

     

1

     

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

     

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

     

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

     

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

     

[xcb]出队时队列中的未知请求

     

[xcb]这很可能是一个多线程客户端和XInitThreads   没有被称为

     

[xcb]流产,对不起。

     

python:../../ src / xcb_io.c:178:dequeue_pending_request:断言   `!xcb_xlib_unknown_req_in_deq'失败。

     

中止(核心倾销)

我非常需要任何帮助。我无法找出并指出错误的原因并修复相同的问题。

1 个答案:

答案 0 :(得分:5)

问题在于如何将信号连接到插槽:

      QtCore.QObject.connect(self.processThread, QtCore.SIGNAL("progress(int)"),self.progressBar, QtCore.SLOT("setValue(int)"), QtCore.Qt.DirectConnection)

在这里,您明确强制执行DirectConnection。这是错的!它使得槽在调用者的线程中被处理。这意味着progressBar的GUI更新发生在进程线程中,而不是发生在GUI线程中。但是,只能在GUI线程中进行绘图。

将信号从一个线程连接到另一个线程的插槽是完全正常的。但是,您需要AutoConnection(默认值,可识别线程并使用QueuedConnection)或QueuedConnection

此行应解决您的问题:

      QtCore.QObject.connect(self.processThread, QtCore.SIGNAL("progress(int)"),self.progressBar, QtCore.SLOT("setValue(int)"), QtCore.Qt.QueuedConnection)

请参阅http://doc.qt.io/archives/qt-4.7/qt.html#ConnectionType-enum