【问题标题】:Why is this implementation of a QGraphicsScene causing the app to crash on exit?为什么 QGraphicsScene 的这种实现会导致应用程序在退出时崩溃?
【发布时间】:2026-01-18 19:35:01
【问题描述】:

我正在使用 Qt 的图形视图框架来显示大量图像,并使用 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)

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

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

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

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

【问题讨论】:

    标签: python crash pyqt qgraphicsitem qgraphicsscene


    【解决方案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 Referencehttp://pyqt.sourceforge.net/Docs/PyQt4/qobject.html#deleteLater


    问候,

    【讨论】:

    • 由于某种原因,我的 closeEvent() 重新实现没有在退出时运行。 (至少我放入其中的打印语句从未显示过。)我确实设法通过在从主窗口到 QGraphicsScene 的链中显式调用 setParent() 来防止崩溃。有了父层次结构,场景就会自动清理。
    • 你可以在 Destructor 中使用 'QObject.deleteLater (self)' 来安排这个对象的删除。当对象被删除时。请阅读我上次编辑的答案。
    【解决方案2】:

    我想在 cmets 中强调 Josh 的回答。 如果您通过将 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)
    

    【讨论】:

      最近更新 更多