这段QGraphicsScene的实现为何导致应用在退出时崩溃?

1 投票
2 回答
1265 浏览
提问于 2025-04-18 16:39

我正在使用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,但没有效果。

有没有什么建议可以帮我解决这个问题?

*我知道我发布的代码只是把图片堆叠在一起,我实际的程序是给它们随机的位置和旋转,但我想把问题简化到最小。

2 个回答

1

我想强调一下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)
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


祝好,

撰写回答