5

我正在构建一个音乐播放器,它使用 SqueezePlay 来检查状态,这是一个 SqueezeBox 控制器应用程序。长话短说,我使用线程每 5 秒检查一次 Squeezeplay 的状态。如果歌曲标题发生变化,我让它更新标签(Qlabel,专辑插图(QPixmap)等。但是,当我要求它通过线程更新它时,我得到在GUI线程之外使用像素图是不安全的.

如何进行线程处理但仍设置 QPixmap?

示例代码:

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

非常感谢!

更新: 我用 Emit 尝试了以下操作,但它不起作用,有人可以看看我做错了什么吗?

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

4 回答 4

7

所有图形 Qt 操作都应该发生在主线程中。其他线程实际上不允许调用 Qt 图形操作(可能包括像素图)。

他们可以向主线程发出 Qt 信号。或者简单地(在 Linux 上)写入管道,并让主线程等待该管道上的输入。

当然,您必须定义所需的信号(以及插槽)。在 C++ 代码中,您需要用signals:(或slots:) 标记它们,并且您的 C++ 代码应该由moc处理。我不知道 Python 对应的是什么(也许 Python 反射能力可能就足够了,我真的不知道)。然后,您必须使用排队连接将信号连接到插槽。我不知道如何在 Python 中做到这一点。

于 2011-12-27T21:03:24.897 回答
4

To answer the question regarding how to emit the signal in python:

Unlike C++, when emitting a user-defined PyQt signal (as opposed to a Qt one), the signature should be omitted.

So, to emit the 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 thread must emit the signal, which is then received by the appropriate widget in the main gui thread. Creating a QImage in the non-gui thread should be okay, but never attempt to call any gui-related methods outside of the main thread.

NB:

I have used old-style signal syntax here because that is what you appear to be using. However, you might want to look at PyQt's new-style signal and slot support as it is much more flexible and pythonic.

于 2011-12-28T00:08:39.560 回答
1

您可能需要将所有绘图作业发送到主线程。

于 2011-12-27T21:07:18.000 回答
0

我已经尝试过了,如果它响了,请告诉我,我已经为我做过类似的事情(但我离python有一段时间了,所以我可能也犯了错误,如果是这样,对不起。)

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
        #
        #
于 2011-12-27T23:05:29.403 回答