【问题标题】:threading: It is not safe to use pixmaps outside the GUI thread线程:在 GUI 线程之外使用像素图是不安全的
【发布时间】:2012-01-28 18:31:36
【问题描述】:

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

【问题讨论】:

  • 使用 QImage 代替 QPixmap
  • self.emit(QtCore.SIGNAL('setNewArtwork(QImage)'), icon) 既然您使用的是像素图,这一行是否应该使用 QPixmap 而不是 QImage?我不知道这些类型的执行有多难。如果 PyQT 中存在这样的概念,还要确保您使用的是排队连接。这样可以确保槽在接收者的线程中运行,而不是在调用者的线程中。
  • 当你说它对信号“不起作用”时,它在什么方面不起作用?出了什么问题?同一件事情?还有什么?
  • @FLX:你找到解决方案了吗?我有兴趣。

标签: python multithreading qt pyqt qpixmap


【解决方案1】:

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

他们可以emit Qt signals 到主线程。或者简单地(在 Linux 上)写入管道,并让主 thread 等待该管道上的输入。

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

【讨论】:

  • 我对这个有点陌生,这将如何完成?我真的可以使用一些示例代码:)
  • 我添加了一些链接。 Qt 文档比我能在几分钟内解释的要好得多!
  • 谢谢Basile,我试过了,但是不行;在原始帖子中查看我的示例 - 我在做什么愚蠢的错误?
  • 您可能必须定义信号和槽,并将信号连接到槽。您应该了解如何在 Python 中执行此操作(或使用 C++ 或 GTK 编写应用程序...)
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 这不起作用。它会返回类似:QPixmap: It is not safe to use pixmaps outside the GUI thread
    【解决方案4】:

    回答关于如何在python中发出信号的问题:

    与 C++ 不同,当发出 用户定义的 PyQt 信号(与 Qt 信号相反)时,应省略签名。

    因此,要发出信号,请执行以下操作:

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

    要连接到信号,请执行以下操作:

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

    为了清楚起见:

    为此,非 gui 线程必须发出信号,然后由主 gui 线程中的适当小部件接收。在非 gui 线程中创建 QImage 应该没问题,但切勿尝试在主线程之外调用任何与 gui 相关的方法。

    注意

    我在这里使用了旧式的信号语法,因为您似乎正在使用这种语法。但是,您可能想看看 PyQt 的 new-style signal and slot support,因为它更加灵活和 Python 化。

    【讨论】:

      猜你喜欢
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 2017-03-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-12
      相关资源
      最近更新 更多