代码之家  ›  专栏  ›  技术社区  ›  Josh

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

  •  1
  • Josh  · 技术社区  · 10 年前

    我使用Qt的图形视图框架来显示大量图像,并使用PyQt4和Python2.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 回复  |  直到 10 年前
        1
  •  1
  •   Bandhit Suksiri    10 年前

    好的,明白了。问题是 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


    最后编辑:8/11/2014 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


    当做

        2
  •  1
  •   Ákos Tompos    6 年前

    我想在评论中强调乔希的回答。 如果通过将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)