Потоки: использование пиксельных карт вне потока GUI небезопасно - PullRequest
4 голосов
/ 28 декабря 2011

Я создаю музыкальный проигрыватель, который проверяет состояние с помощью SqueezePlay, который является приложением контроллера SqueezeBox. Короче говоря, я проверяю состояние Squeezeplay каждые 5 секунд, используя потоки. Если название песни меняется, я позволяю ей обновлять метки (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 ]

6 голосов
/ 28 декабря 2011

Все графические операции Qt должны выполняться в главном потоке.Другие потоки на самом деле не могут вызывать графические операции Qt (включая, возможно, растровые изображения).

Они могут излучать сигналы Qt в основной поток.Или просто (в Linux) запишите в канал и попросите основной поток дождаться ввода в этот канал.

Конечно, вы должны определить сигналы (а также слоты)ты хочешь.В коде C ++ вам нужно пометить их signals: (или slots:), а ваш код C ++ должен быть обработан moc .Я не знаю, что является аналогом Python (возможно, будет достаточно возможностей отражения Python, я действительно не знаю).Затем вам необходимо подключить сигналы к слотам с помощью очереди .Я понятия не имею, как это сделать в Python.

4 голосов
/ 28 декабря 2011

Чтобы ответить на вопрос о том, как излучать сигнал в python:

В отличие от C ++, при испускании пользовательского PyQt сигнала (в отличие от Qt) подпись должна быть опущена.

Итак, чтобы испустить сигнал, сделайте что-то вроде этого:

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

А для подключения к сигналу сделайте что-то вроде этого:

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

И просто для ясности:

Чтобы это работало, не-GUI-поток должен излучать сигнал, который затем принимается соответствующим виджетом в основном GUI-потоке. Создание QImage в потоке, не связанном с GUI, должно быть нормальным, но никогда не пытайтесь вызывать какие-либо связанные с GUI методы вне основного потока.

NB

Я использовал здесь синтаксис сигналов старого стиля, потому что это то, что вы используете. Тем не менее, вы можете захотеть взглянуть на поддержку сигналов и слотов нового стиля PyQt , поскольку она гораздо более гибкая и питоническая.

1 голос
/ 28 декабря 2011

вам, вероятно, нужно отправить все задания по рисованию в основной поток.

0 голосов
/ 28 декабря 2011

Я попробовал что-то, пожалуйста, дайте мне знать, если он звонит в колокольчик, я сделал что-то подобное для моего (но я на некоторое время далеко от питона, так что, возможно, я тоже допустил ошибки, если так, извините.)

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
        #
        #
...