Python PyQt 像素图更新崩溃
Python PyQt pixmap update crashes
我有一个简单的 PyQt 应用程序。您可以使用 pageup 和 pagedown 键循环浏览图像文件夹。
我正在使用 QLabel 的像素图来显示图像。在您评论 processEvents 调用之前,以下逻辑实际上有效。
关于崩溃原因的任何想法以及为什么添加 processEvents 可以防止崩溃?
# Python version: 2.7.9
# Qt version: 4.8.6
# PyQt version: 4.11.3
import sys
import os
from PIL import Image
from PIL import ImageOps
from PIL.ImageQt import ImageQt
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4 import Qt
imagefolder = "C:/Users/alan/Desktop/imagefolder"
class QExampleLabel (QtGui.QLabel):
def __init__(self, parentQWidget = None):
super(QExampleLabel, self).__init__(parentQWidget)
self.initUI()
def initUI (self):
self.imagelist = []
for path, subdirs, files in os.walk(imagefolder):
path = path.replace("\", "/")
for file in files:
base, ext = os.path.splitext(file)
if ext.lower() == ".jpg":
jpg = path + "/" + file
self.imagelist.append(jpg)
self.i = -1
def keyPressEvent(self, keyevent):
event = keyevent.key()
if event == QtCore.Qt.Key_PageUp:
self.backward()
if event == QtCore.Qt.Key_PageDown:
self.forward()
def forward(self):
self.i = self.i + 1
if self.i >= len(self.imagelist):
self.i = len(self.imagelist) - 1
self.displayimage()
def backward(self):
self.i = self.i - 1
if self.i < 0:
self.i = 0
self.displayimage()
def displayimage(self):
photo = self.imagelist[self.i]
img = Image.open(photo)
mysize = (260,260)
method = Image.NEAREST if img.size == mysize else Image.ANTIALIAS
self.cropimage = ImageOps.fit(img, mysize, method = method, centering = (0.5,0.5))
qim = ImageQt(self.cropimage)
pix = QtGui.QPixmap.fromImage(qim)
self.setPixmap(pix)
QtGui.QApplication.processEvents() # comment this line to see setPixmap crash
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
myQExampleLabel = QExampleLabel()
myQExampleLabel.show()
myQExampleLabel.resize(260,260)
sys.exit(app.exec_())
该错误可能是由垃圾回收引起的,因为您没有保留对 Qt 图像对象的显式引用。当你从 QImage 创建一个像素图时,底层数据将保持共享,所以使用 QImage 复制构造函数来获得一个显式引用,然后保持它存活直到不再需要像素图:
self._img = QtGui.QImage(qim)
pix = QtGui.QPixmap.fromImage(self._img)
更新:
使用测试用例,我能够通过简单地保留对原始 ImageQt
对象的引用来消除崩溃:
self.qim = ImageQt(self.cropimage)
pix = QtGui.QPixmap.fromImage(self.qim)
self.setPixmap(pix)
或者,更简单地说,使用 QPixmap.detach():
qim = ImageQt(self.cropimage)
pix = QtGui.QPixmap.fromImage(qim)
pix.detach()
self.setPixmap(pix)
我有一个简单的 PyQt 应用程序。您可以使用 pageup 和 pagedown 键循环浏览图像文件夹。
我正在使用 QLabel 的像素图来显示图像。在您评论 processEvents 调用之前,以下逻辑实际上有效。
关于崩溃原因的任何想法以及为什么添加 processEvents 可以防止崩溃?
# Python version: 2.7.9
# Qt version: 4.8.6
# PyQt version: 4.11.3
import sys
import os
from PIL import Image
from PIL import ImageOps
from PIL.ImageQt import ImageQt
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4 import Qt
imagefolder = "C:/Users/alan/Desktop/imagefolder"
class QExampleLabel (QtGui.QLabel):
def __init__(self, parentQWidget = None):
super(QExampleLabel, self).__init__(parentQWidget)
self.initUI()
def initUI (self):
self.imagelist = []
for path, subdirs, files in os.walk(imagefolder):
path = path.replace("\", "/")
for file in files:
base, ext = os.path.splitext(file)
if ext.lower() == ".jpg":
jpg = path + "/" + file
self.imagelist.append(jpg)
self.i = -1
def keyPressEvent(self, keyevent):
event = keyevent.key()
if event == QtCore.Qt.Key_PageUp:
self.backward()
if event == QtCore.Qt.Key_PageDown:
self.forward()
def forward(self):
self.i = self.i + 1
if self.i >= len(self.imagelist):
self.i = len(self.imagelist) - 1
self.displayimage()
def backward(self):
self.i = self.i - 1
if self.i < 0:
self.i = 0
self.displayimage()
def displayimage(self):
photo = self.imagelist[self.i]
img = Image.open(photo)
mysize = (260,260)
method = Image.NEAREST if img.size == mysize else Image.ANTIALIAS
self.cropimage = ImageOps.fit(img, mysize, method = method, centering = (0.5,0.5))
qim = ImageQt(self.cropimage)
pix = QtGui.QPixmap.fromImage(qim)
self.setPixmap(pix)
QtGui.QApplication.processEvents() # comment this line to see setPixmap crash
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
myQExampleLabel = QExampleLabel()
myQExampleLabel.show()
myQExampleLabel.resize(260,260)
sys.exit(app.exec_())
该错误可能是由垃圾回收引起的,因为您没有保留对 Qt 图像对象的显式引用。当你从 QImage 创建一个像素图时,底层数据将保持共享,所以使用 QImage 复制构造函数来获得一个显式引用,然后保持它存活直到不再需要像素图:
self._img = QtGui.QImage(qim)
pix = QtGui.QPixmap.fromImage(self._img)
更新:
使用测试用例,我能够通过简单地保留对原始 ImageQt
对象的引用来消除崩溃:
self.qim = ImageQt(self.cropimage)
pix = QtGui.QPixmap.fromImage(self.qim)
self.setPixmap(pix)
或者,更简单地说,使用 QPixmap.detach():
qim = ImageQt(self.cropimage)
pix = QtGui.QPixmap.fromImage(qim)
pix.detach()
self.setPixmap(pix)