vandelay
vandelay

Reputation: 2065

QPixmap and GUI threading

I'm trying to get a small example up and running with a Thread doing a screenshot and sending it to the GUI application to be shown. But I am getting this "error"

QPixmap: It is not safe to use pixmaps outside the GUI thread

I've tried read around the, but are having difficulties understanding why exactly it's giving me this since the QImage is made within the main application and also the GUI thread?

I'd like my label to show the image captured by the thread.

class Main(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 280, 600)
        self.layout = QtGui.QVBoxLayout(self)

        self.testButton = QtGui.QPushButton("Click Me")
        self.connect(self.testButton, QtCore.SIGNAL("clicked()"), self.Capture)

        self.layout.addWidget(self.testButton)

        self.label_ = QLabel(self)
        self.label_.move(280, 120)
        self.label_.resize(640, 480)
        self.layout.addWidget(self.label_)


    @pyqtSlot(QImage) 
    def ChangeFrame(self, image):  
        qimg = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_RGB888)

        self.label_.setPixmap(QPixmap.fromImage(qimg))


    def Capture(self):       
        self.thread_ = CaptureScreen()        
        self.connect(self.thread_, QtCore.SIGNAL("ChangeFrame(PyQt_PyObject)"), self.ChangeFrame, Qt.DirectConnection)
        self.thread_.start()       

class CaptureScreen(QtCore.QThread):
    pixmap = pyqtSignal(QImage)

    def __del__(self):
        self.exiting = True
        self.wait()

    def run(self):    
        img = ImageGrab.grab(bbox=(100,10,400,780))
        img_np = np.array(img)
        frame = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)        

        self.emit( QtCore.SIGNAL("ChangeFrame(PyQt_PyObject)"), frame)



app = QtGui.QApplication(sys.argv)
test = Main()
test.show()
app.exec_()

Upvotes: 0

Views: 351

Answers (1)

Gary Hughes
Gary Hughes

Reputation: 4510

From the docs:

Direct Connection The slot is invoked immediately, when the signal is emitted. The slot is executed in the emitter's thread, which is not necessarily the receiver's thread.

By specifying Qt.DirectConnection when connecting your signal you're causing the connected method to be called by your CaptureScreen thread, meaning that you're creating a QPixmap outside of your GUI thread.

Does changing the connection type to Qt.QueuedConnection fix things?

Upvotes: 2

Related Questions