线程:在 GUI 线程之外使用像素图是不安全的

发布于 2024-12-23 00:09:21 字数 866 浏览 4 评论 0原文

我正在构建一个音乐播放器,它使用 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)

I'm building a music player, that checks the status with SqueezePlay, which is a SqueezeBox controller app. To cut a long story short, I'm checking the status of Squeezeplay ever 5 seconds by using threading. If the song title changes, I let it update the labels (Qlabel, album artwork (QPixmap), etc. However, when I ask it to update it via threading, I'm getting It is not safe to use pixmaps outside the GUI thread .

How can I do threading but still set the QPixmap?

Sample code:

#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 it doesn't work, can someone take a look what I'm 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

终止放荡 2024-12-30 00:09:21

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

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

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

All graphical Qt operations should happen in the main thread. Other threads are not really allowed to call Qt graphical operations (including probably pixmaps).

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

Of course, you have to define the signals (and also the slots) you want. In C++ code, you need to mark them with signals: (or slots:) and your C++ code should be processed by the moc. I don't know what is the Python counterpart (perhaps python reflection abilities might be enough, I really don't know). You then have to connect signals to slots, with a queued connection. I have no idea how to do that in Python.

2024-12-30 00:09:21

回答有关如何在 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 的 新式信号和槽支持 视为它更加灵活和Pythonic。

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.

逆流 2024-12-30 00:09:21

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

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

ゞ记忆︶ㄣ 2024-12-30 00:09:21

我已经尝试过了,如果它响起,请告诉我,我已经为我做了类似的事情(但我已经远离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
        #
        #

I've tried sth, please let me know if it rings a bell, i've done sth similar for mine (but im far from python for a while, so i may have made mistakes as well, 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
        #
        #
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文