Threading: It is unsafe to use pixmaps outside of a GUI thread

I am creating a music player that checks the status using SqueezePlay, which is a SqueezeBox application. In short, I check the status of Squeezeplay every 5 seconds using streams. If the name of the song changes, I let it update the labels (Qlabel, album art (QPixmap), etc. However, when I ask it to update it using streaming, I get . It is unsafe to use pixmaps outside the GUI stream .

How can I execute threads, but still set QPixmap?

Code example:

#self.sq.getArtwork() returns variable with the image coverArt = self.sq.getArtwork() coverPixMap = QtGui.QPixmap() coverPixMap.loadFromData(coverArt) self.albumArt.setPixmap(coverPixMap) 

Many thanks!

Update: I tried the following with Emit, but this will not work, can someone see what I am doing wrong?

 def setNewArtwork(self, image): coverPixMap = QtGui.QPixmap() coverPixMap.convertFromImage(image) icon = QtGui.QIcon(coverPixMap) item.setIcon(icon) def getNewArtwork(self): coverArt = self.sq.getArtwork() icon = QtGui.QImage(coverArt) self.emit(QtCore.SIGNAL('setNewArtwork(QImage)'), icon) 
+4
source share
4 answers

All Qt graphics operations must be performed in the main thread. Other threads are not allowed to invoke Qt graphics operations (including, probably, bitmaps).

They could emit Qt signals into the main stream. Or simply (on Linux) write to the pipe and have the main thread wait for input on this channel.

Of course, you need to identify the signals (as well as the slots) that you want. In C ++ code, you need to mark them with signals: (or slots: , and your C ++ code should be processed by moc . I don’t know what the Python counterpart is (perhaps the python reflection capabilities may be enough, I really don’t know). Then you need to connect the signals to the slots with connection in turn. I do not know how to do this in Python.

+4
source

To answer the question of how to emit a signal in python:

Unlike C ++, when issuing a custom PyQt signal (unlike Qt one), the signature must be omitted.

So, to emit a signal, do something like this:

 thread.emit(QtCore.SIGNAL('newArtworkAvailable'), icon) 

And to connect to the signal, do something like this:

 widget.connect(thread, QtCore.SIGNAL('newArtworkAvailable'), widget.setNewArtwork) 

And just to be clear:

For this to work, the non-gui stream must emit a signal, which then receives the corresponding widget in the main gui stream. Creating a QImage in a non-gui thread should be fine, but never try to call any gui-related methods outside the main thread.

NB

I used the old-style signal syntax because this is what you seem to be using. However, you can look at PyQt's new style and slot support , as it is much more flexible and pythonic.

+4
source

you probably need to send all your drawing tasks to the main thread.

+1
source

I tried sth, please let me know if it rings the bell, I did something similar to mine (but im far from python for a while, so I might have made a mistake too, if so, sorry.)

 class MyThread(QThread, ui): def __init__(self, ui): super(MyThread, self).__init__(self) self.ui = ui def run(self): coverArt = self.ui.getArtwork() coverPixMap = QtGui.QPixmap() coverPixmap.convertFromImage(QtGui.QIcon(coverArt)) icon = QtGui.QImage(coverPixMap) self.ui.item.setIcon(icon) // set icon self.ui.singerLabel.setText("Singer") // update label # your gui class class YourInterface(QtGui.QWidget): def __init__(self): QtGui.QWidget.__init__(self) myThread = MyThread(self) self.myButton.clicked.connect(myThread.run) # all other stuff # # 
0
source

Source: https://habr.com/ru/post/902429/


All Articles