QT界面小知识-Qt::WA_DeleteOnClose

1,551 阅读3分钟

Qt窗口属性 - Qt::WA_DeleteOnClose

今天在做项目的内存泄露检测时发现有处问题,在点击托盘图标退出时,一直曝出有内存泄露,然后一直查看此问题,最后发现原来应用程序在关闭界面时,程序并未进入析构函数。
为什么关闭界面调用了close()函数,但没有进入析构,查找下Qt助手中关于close()方法的介绍:

bool QWidget::close() Closes this widget. Returns true if the widget was closed; otherwise returns false.

First it sends the widget a QCloseEvent. The widget is hidden if it accepts the close event. If it ignores the event, nothing happens. The default implementation of QWidget::closeEvent() accepts the close event.

If the widget has the Qt::WA_DeleteOnClose flag, the widget is also deleted. A close events is delivered to the widget no matter if the widget is visible or not.

调用close()方法后首先它会向widget发送一个关闭事件(QCloseEvent)。如果widget接受了关闭事件(QCloseEvent),窗口将会隐藏(实际上调用hide())。如果widget不接受关闭事件,那么窗口将什么也不做。默认情况下widget会接受关闭事件,我们可以重写QCloseEvent事件,可以选择接受或者不接受。

如果widget设置了Qt::WA_DeleteOnClose属性,widget将会被释放。不管widget是否可见,关闭事件都会传递给widget。即接收到QCloseEvent事件后,除了调用hide()方法将窗口隐藏,同时会调用deleteLater()方法将窗口释放掉,不会再占用资源。

所以说调用close()并不一定就会将窗口对象销毁。而只有设置了 Qt::WA_DeleteOnClose属性才会删除销毁。如果这个属性没有设置,close()的作用和hide(),setvisible(false)一样,只会隐藏窗口对象而已,并不会销毁该对象。

Qt::WA_DeleteOnClose属性在Qt助手中的解释:

Qt::WA_DeleteOnClose Makes Qt delete this widget when the widget has accepted the close event (see QWidget::closeEvent()). 如果窗口设置了Qt::WA_DeleteOnClose 这个属性,在窗口接受了关闭事件后,Qt会释放这个窗口所占用的资源。

注意: qt的gui编程中,在关闭QWidget及其子类窗口时需销毁窗口,但测试发现如果是定义在栈上,退出main方法时,程序会自动销毁窗口

所以如果在进行设置Qt::WA_DeleteOnClose 这个属性,setAttribute方法会使得Qt再次销毁窗口,造成二次delete,程序将会出错:

如果定义在堆上,在关闭时main方法不会自动销毁,而是需要进行Qt::WA_DeleteOnClose 这个属性设置,Qt才会根据setAttribute设置销毁,程序不会报错:

综上:发生内存泄露的原因就是,主程序是定义在堆上,但却没有进行属性设置,所以导致Qt程序并没有进行主动销毁,起始就是进行了隐藏。故可以的出:所以如果我们在程序中通过 new 的方式创建一个窗口,可以给该窗口设置 Qt::WA_DeleteOnClose属性。这样在关闭这个窗口时Qt能够自动回收该窗口所占用的资源,这样能够及时回收无效的资源,有用利于节约内存空间。

可以做一个小测试:通过不断打开窗口,再关闭所有打开的窗口。在任务管理器中对比该应用程序所占用的资源大小。
发现:在不停地打开窗口,程序占用内存不断增加,而在所有窗口关闭的过程中,设置了 Qt::WA_DeleteOnClose属性的情况下我们发现关闭的窗口所占用的内存资源在不断回收,全部关闭后恢复到之前的状态。而没有设置Qt::WA_DeleteOnClose属性的情况下我们发现关闭的窗口所占用的内存资源并没有减少。这就说明,关闭的窗口内存未被回收。由此看来Qt::WA_DeleteOnClose属性非常重要。

参考链接:blog.csdn.net/goforwardto…