为什么QGraphicsScene的这种实现会导致应用程序在退出时崩溃?

时间:2014-08-09 12:17:07

标签: python crash pyqt qgraphicsitem qgraphicsscene

我正在使用Qt的Graphics View Framework来显示大量图像,并使用PyQt4和Python 2.7实现它。我实例化了许多QPixmapItem对象并将它们添加到我的QGraphicsScene中。它一切正常,直到我退出应用程序,程序崩溃而不是正常退出。

class ImgDisplay(QtGui.QWidget):
    NUM_ITEMS = 5000

    VIEW_WIDTH,VIEW_HEIGHT = 400, 400

    def __init__(self):
        super(ImgDisplay, self).__init__()

        self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT))

        self.view = QtGui.QGraphicsView(self.scene)
        self.view.setParent(self)

        #Load the texture
        self.texture = QtGui.QPixmap('image.png')

        self.populateScene()

    def populateScene(self):

        for i in range(0, ImgDisplay.NUM_ITEMS-1):
            item = QtGui.QGraphicsPixmapItem(self.texture)

            self.scene.addItem(item)

我在想我正在创建的所有PixMapItem都没有正确清理,或者我需要释放我加载的纹理(似乎没有一种方法可以释放它,所以我假设它发生在后台)。

我尝试在析构函数中调用self.scene.clear来删除PixmapItems,但它没有帮助。

有关如何解决此问题的任何建议?

*我知道发布的代码只是将图像全部放在一起,我的实际程序会为它们分配随机位置和旋转,但我想将其减少到最小的问题。

2 个答案:

答案 0 :(得分:1)

好的,明白了。问题是QtGui.QGraphicsPixmapItem无法清除自己必须手动,就像你说的那样,但不是析构函数。我建议使用closeEvent进行信号关闭程序,就像这样;

def closeEvent (self, eventQCloseEvent):
    self.scene.clear() # Clear QGraphicsPixmapItem
    eventQCloseEvent.accept() # Accept to close program

这实现了你的代码;

import sys
from PyQt4 import QtCore, QtGui

class ImgDisplay (QtGui.QWidget):
    NUM_ITEMS = 5000
    VIEW_WIDTH,VIEW_HEIGHT = 400, 400

    def __init__ (self):
        super(ImgDisplay, self).__init__()
        self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT))
        self.view = QtGui.QGraphicsView(self.scene)
        self.view.setParent(self)
        #Load the texture
        self.texture = QtGui.QPixmap('image.png')
        self.populateScene()

    def populateScene (self):
        for i in range(0, ImgDisplay.NUM_ITEMS-1):
            item = QtGui.QGraphicsPixmapItem(self.texture)
            self.scene.addItem(item)

    def closeEvent (self, eventQCloseEvent):
        self.scene.clear()
        eventQCloseEvent.accept()

app = QtGui.QApplication([])
window = ImgDisplay()
window.show()
sys.exit(app.exec_())

我使用PyQt4(Windows 7)。

这对于实施近距离事件很有用,希望是有帮助的;

QWidget关闭活动参考http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#closeEvent


最后编辑:2014年8月11日01:51

如果你想控制你的父母和...子窗口小部件一起删除,我必须实现析构函数方法(如你所说)。使用安全删除方法QObject.deleteLater (self),像这样;

import sys
from PyQt4 import QtCore, QtGui

class ImgDisplay (QtGui.QWidget):
    NUM_ITEMS = 5000
    VIEW_WIDTH, VIEW_HEIGHT = 400, 400

    def __init__ (self, parent = None):
        super(ImgDisplay, self).__init__(parent)
        self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT), parent = self)
        self.view = QtGui.QGraphicsView(self.scene, parent = self)
        #Load the texture
        self.texture = QtGui.QPixmap('image.png')
        self.populateScene()

    def populateScene (self):
        for i in range(0, ImgDisplay.NUM_ITEMS-1):
            item = QtGui.QGraphicsPixmapItem(self.texture)
            self.scene.addItem(item)

    def __del__ (self):
        self.deleteLater() # Schedules this object for deletion 

app = QtGui.QApplication([])
window = ImgDisplay()
window.show()
sys.exit(app.exec_())

警告:不要忘记在小部件中设置父级! (因为有些时候它不能自行删除。)

deleteLater参考http://pyqt.sourceforge.net/Docs/PyQt4/qobject.html#deleteLater


此致

答案 1 :(得分:1)

我想在评论中强调乔什的回答。 如果通过将QGraphicsView设置为父级来创建场景,则崩溃将自动消失。

 self.view = QtGui.QGraphicsView(parent = self)
 self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT), parent = self.view)
 self.view.setScene(self.scene)