【问题标题】:Dynamically created tabs - destroy object when tab closed动态创建的选项卡 - 关闭选项卡时销毁对象
【发布时间】:2019-07-12 20:09:00
【问题描述】:

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

我已将动态创建的选项卡的属性设置为 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:')

如何确保对象被销毁?

【问题讨论】:

    标签: python memory-leaks pyqt pyqt5 qtabwidget


    【解决方案1】:

    我的回答旨在解释其他答案未说明的细节,以便您了解它如何处理内存 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(),因为这不会破坏小部件,因此当您想将已移除的小部件放置到另一个小部件时,会考虑使用该方法。

    【讨论】:

      【解决方案2】:

      试试看:

      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_())  
      

      【讨论】:

        猜你喜欢
        • 2014-05-24
        • 1970-01-01
        • 1970-01-01
        • 2019-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-11
        • 1970-01-01
        相关资源
        最近更新 更多