我正在构建一个音乐播放器,用SqueezePlay检查状态,SqueezePlay是一个SqueezeBox控制器应用程序。简而言之,我通过使用线程来检查Squeezeplay的状态,持续5秒。如果歌曲标题改变了,我让它更新标签(Qlabel,专辑封面(QPixmap)等等。但是,当我要求它通过线程更新它时,我得到在外面使用pixmaps是不安全的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)
答案 0 :(得分:6)
所有图形Qt操作都应该在主线程中进行。其他线程实际上不允许调用Qt图形操作(包括可能是pixmaps)。
他们可以emit Qt signals到主线程。或者简单地(在Linux上)写入管道,并让主thread等待该管道上的输入。
当然,您必须定义所需的信号(以及插槽)。在C ++代码中,您需要使用signals:
(或slots:
)标记它们,并且您的C ++代码应由moc处理。我不知道什么是Python对应物(也许python反射能力可能就足够了,我真的不知道)。然后,您必须使用排队的连接将信号连接到插槽。我不知道如何在Python中做到这一点。
答案 1 :(得分:4)
回答有关如何在python中发出信号的问题:
与C ++不同,当发出用户定义的 PyQt信号(而不是Qt信号)时,应省略签名。
因此,要发出信号,请执行以下操作:
thread.emit(QtCore.SIGNAL('newArtworkAvailable'), icon)
要连接信号,请执行以下操作:
widget.connect(thread, QtCore.SIGNAL('newArtworkAvailable'),
widget.setNewArtwork)
只是要明确:
为了使其正常工作,非gui线程必须发出信号,然后由主gui线程中的相应小部件接收该信号。在非gui线程中创建QImage
应该没问题,但绝不会尝试在主线程之外调用任何与gui相关的方法。
<强> NB 强>:
我在这里使用过旧式的信号语法,因为这就是您正在使用的内容。但是,您可能希望查看PyQt的new-style signal and slot support,因为它更加灵活和pythonic。
答案 2 :(得分:1)
您可能需要将所有绘图作业发送到主线程。
答案 3 :(得分:0)
我已经尝试过了,请告诉我是否响了铃,我已经做了类似的事情(但是我离蟒蛇很远一段时间了,所以我可能也犯了错误,如果是的话,抱歉。)
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
#
#