动态创建的标签页-标签页关闭时销毁对象

时间:2019-07-12 20:09:00

标签: python memory-leaks pyqt pyqt5 qtabwidget

我正在动态创建多个选项卡,我想知道当我关闭选项卡时,它是否真的破坏了对象?

我已将动态创建的标签的属性设置为QtCore.Qt.WA_DeleteOnClose

我认为设置属性没有任何作用,因为未调用closeEvent。

    self.tabWidget.tabCloseRequested.connect(self.close_handler) # connect close button to slot

    def close_handler(self, index):
        'Remove added tab if applicable'
        try:
            #self.tabWidget.widget(index).deleteLater() #does this need to be added?
            self.tabWidget.removeTab(index)
        except:
            Data.logger.exception('Exception occured:')

我如何确保该物体被销毁?

2 个答案:

答案 0 :(得分:2)

我的答案旨在解释其他答案未指明的细节,以便您了解其如何处理内存Qt。

如果您想知道是否消除了QObject,则必须使用destroyed信号。

如果要删除QObject,则必须使用deleteLater()方法。

在取消添加到QTabWidget的窗口小部件的情况下,这将通知QTabBar将其删除,因此访问非保留内存没有问题。

考虑到上述情况,可能的解决方案是:

def close_handler(self, index):
    widget = self.tabWidget.widget(index)
    widget.deleteLater()

您可以通过以下示例进行检查:

from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.tabWidget = QtWidgets.QTabWidget(tabsClosable=True)
        self.tabWidget.tabCloseRequested.connect(self.onTabCloseRequested)
        self.setCentralWidget(self.tabWidget)

        for i in range(10):
            widget = QtWidgets.QWidget()
            widget.destroyed.connect(
                lambda obj: print(
                    "deleted {}, count: {}".format(obj, self.tabWidget.count())
                )
            )
            self.tabWidget.addTab(widget, "Tab %s" % (i))

    @QtCore.pyqtSlot(int)
    def onTabCloseRequested(self, index):
        widget = self.tabWidget.widget(index)
        widget.deleteLater()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

如您所见,不必使用属性Qt :: WA_DeleteOnClose,但如果使用它,就足以关闭小部件。

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.tabWidget = QtWidgets.QTabWidget(tabsClosable=True)
        self.tabWidget.tabCloseRequested.connect(self.onTabCloseRequested)
        self.setCentralWidget(self.tabWidget)

        for i in range(10):
            widget = QtWidgets.QWidget()
            widget.setAttribute(QtCore.Qt.WA_DeleteOnClose)
            widget.destroyed.connect(
                lambda obj: print(
                    "deleted {}, count: {}".format(obj, self.tabWidget.count())
                )
            )
            self.tabWidget.addTab(widget, "Tab %s" % (i))

    @QtCore.pyqtSlot(int)
    def onTabCloseRequested(self, index):
        widget = self.tabWidget.widget(index)
        widget.close()

不必使用removeTab(),因为这不会破坏小部件,因此可以考虑使用该方法,以便在要将小部件移至另一个小部件时使用。

答案 1 :(得分:1)

尝试一下:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self.qtabwidget = QtWidgets.QTabWidget(self) 

        widget = QtWidgets.QPlainTextEdit("QPlainTextEdit 1")
        label  = 'Tab &1'
        tab_index1 = self.qtabwidget.addTab(widget, label)

        widget2 = QtWidgets.QPlainTextEdit("QPlainTextEdit 2")        
        tab_index2 = self.qtabwidget.addTab(widget2, 'Tab &2')
        self.qtabwidget.setTabIcon(tab_index2, QtGui.QIcon('im.png'))
        self.qtabwidget.setIconSize(QtCore.QSize(32, 32)) 

        self.qtabwidget.addTab(
                QtWidgets.QLabel("QLabel Tab &3", alignment=QtCore.Qt.AlignCenter), 
                QtGui.QIcon('Ok.png'),
                'Tab &3')

        self.qtabwidget.setTabShape(QtWidgets.QTabWidget.Triangular)
        self.qtabwidget.setTabPosition(QtWidgets.QTabWidget.East)          

        self.qtabwidget.setTabsClosable(True)  
        self.qtabwidget.tabCloseRequested.connect(self.close_handler)              
        self.qtabwidget.currentChanged.connect(self.qtabwidget_currentchanged)

        self.setCentralWidget(self.qtabwidget)

    @QtCore.pyqtSlot(int)
    def close_handler(self, index):
        """
            Removes a tab with the specified index, but first deletes the widget it contains. 
        """

        # gets the widget
        widget = self.qtabwidget.widget(index)

        # if the widget exists
        if widget:
            # removes the widget
            widget.deleteLater()

        # removes the tab of the QTabWidget
        self.qtabwidget.removeTab(index)


    @QtCore.pyqtSlot(int)
    def qtabwidget_currentchanged(self, index):
        print(f"The new index of the current page: {index}")



if __name__ == '__main__':
    application = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setWindowTitle('QTabWidget')
    window.resize(400, 400)
    window.show()
    sys.exit(application.exec_())  

enter image description here

enter image description here