PyQt在关闭应用程序时没有运行析构函数的问题
目录
- 一、说明
- 二、python的析构函数
- 三、QT5 存在一些问题
- 四、PyQt5 存在一些问题
- 五、OpenGL的析构问题
一、说明
应用QT做程序界面,在程序退出的时候,需要调用析构函数释放资源,这个操作在Python程序中,虽然不调用析构函数,资源也可以释放。在QOpenGLWidget中,会产生一系列的buff对象,如果不能正确释放,程序将出现状况,如何解决?
但是,出现讨厌的错误提示,比如下图:
二、python的析构函数
在PyQt中,当一个类的实例被销毁时,Python会自动调用它的析构函数(即__del__方法)。析构函数主要用于释放资源(例如关闭文件、断开网络连接等),以确保在对象被销毁之前进行必要的清理工作。
from PyQt5.QtWidgets import QApplication, QMainWindow
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
def __del__(self):
print("析构函数被调用")
app = QApplication([])
window = MyWindow()
window.show()
app.exec_()
在PyQt中,当一个类的实例被销毁时,Python会自动调用它的析构函数(即__del__方法)。析构函数主要用于释放资源(例如关闭文件、断开网络连接等),以确保在对象被销毁之前进行必要的清理工作。
三、QT5 存在一些问题
按照文库的说法,“如果子窗体初始化了父窗体的parent,只有父窗体析构时才执行自己的析构函数。”
根据我的经验,系统默认的构造函数中parent都有默认值0,而构造函数的实现中,都有初始化列表指定父类的parent为当前parent,如果不指定,也就是0。这里还不能把parent指定位父窗体,否则子窗体会作为一个父窗体当中的“部件”而存在。父类和父窗体不是一个东西。所以文库当中的说法我暂时不太明白。
我的想法是这样,既是不初始化父类的parent,它的构造函数中parent参数依然会有默认值为空指针,所以是否执行析构函数,和初始化父类构造函数我想不出联系。
但是文库中给出了解决方法,在子窗体构造函数中加一句即可:
setAttribute(Qt::WA_DeleteOnClose);
这才是最重要的。根据qt的文档,这个属性就是在close时delete。
Qt::WA_DeleteOnClose 55
Makes Qt delete this widget when the widget has accepted the close event (see QWidget::closeEvent()).
之所以说是坑,就是每次设计窗体时,总觉得想当然可以关闭时执行析构,但事实上必须加这一句,总会忘掉,特此记录,提醒自己。
四、PyQt5 存在一些问题
有时在关闭应用程序时,PyQt不会自动调用类的析构函数,可能导致一些资源无法正常释放。这可能是因为应用程序的主事件循环在关闭窗口时仍在运行,从而导致类的实例无法被销毁。
为了解决这个问题,我们可以通过重写QMainWindow的closeEvent方法来手动触发析构函数的调用。
from PyQt5.QtWidgets import QApplication, QMainWindow
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
def __del__(self):
print("析构函数被调用")
def closeEvent(self, event):
self.__del__() # 手动调用析构函数
event.accept()
app = QApplication([])
window = MyWindow()
window.show()
app.exec_()
在上面的示例代码中,我们重写了closeEvent方法,并在其中手动调用了析构函数。通过这种方式,我们可以确保在关闭窗口时,析构函数会被正确地调用。
在PyQt中,当一个类的实例被销毁时,Python会自动调用它的析构函数(即__del__方法)。析构函数主要用于释放资源(例如关闭文件、断开网络连接等),以确保在对象被销毁之前进行必要的清理工作。
五、OpenGL的析构问题
OpenGL对自身的上下文是非常敏感的,稍有不慎可能就会导致内存泄漏,或者没有释放正确,就比如 QOpenGLVertexArrayObject::destroy() failed to restore current context 问题,由于上下文的问题没有办法正确的释放QOpenGLVertexArrayObject VAO对象。
发生的原因:我想在QOpenGLWidget的析构函数 delete 掉我的网格类对象,网格类对象内使用了VAO对象也就是QOpenGLVertexArrayObject 这个类,两个类的析构大致如下
Mesh类:
Mesh::~Mesh(){
m_VBO.destroy();
m_VAO.destroy();
}
MyOpenGLWidget类:
MyOpenGLWidget::~MyOpenGLWidget(){
delete mesh;
}
在关闭窗口后控制台面板就输出了这个问题
解决方法:
这个问题的原因就是因为在OpenGL窗口结束了之后,最后在析构的时候还有使用到OpenGL的东西,就是delete mesh对象时mesh的析构又调用了QtOpenGL相关内容导致的OpenGL上下文不正确。
所以在MyOpenGLWidget的析构函数中加入下面的函数来确保上下文正确。
MyOpenGLWidget::~MyOpenGLWidget(){
// 确保释放opengl资源时上下文正确
makeCurrent();
delete mesh;
doneCurrent();
}
这也是一个解决办法,如果还有其他办法再说吧。