【OpenGL开发】PyQt在关闭应用程序时没有运行析构函数的问题

PyQt在关闭应用程序时没有运行析构函数的问题

在这里插入图片描述

一、说明

   应用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();
 
}

这也是一个解决办法,如果还有其他办法再说吧。

最近更新

  1. 《C++20设计模式》中单例模式

    2024-04-15 09:26:05       1 阅读
  2. 数字孪生技术在智能家居中的应用

    2024-04-15 09:26:05       1 阅读
  3. 单例模式的多种实现方式及其在框架中的使用

    2024-04-15 09:26:05       1 阅读
  4. 一、Prometheus和Grafana搭建

    2024-04-15 09:26:05       1 阅读
  5. 指向如此神奇:揭示Js函数this的10个惊人事实!

    2024-04-15 09:26:05       1 阅读
  6. k8s 使用 helm 文件部署 8.12.2 es 分角色集群

    2024-04-15 09:26:05       1 阅读
  7. 数据编码的艺术:sklearn中的数据转换秘籍

    2024-04-15 09:26:05       1 阅读
  8. android pdf框架-11,查看图片

    2024-04-15 09:26:05       1 阅读
  9. 深入探索:scikit-learn中递归特征消除(RFE)的奥秘

    2024-04-15 09:26:05       1 阅读

热门阅读

  1. LeetCode 128.最长连续数列

    2024-04-15 09:26:05       23 阅读
  2. UE C++ 知识杂记

    2024-04-15 09:26:05       15 阅读
  3. Dubbo技术问答系列-NO3

    2024-04-15 09:26:05       22 阅读
  4. vscode中vue3文件中没有自动提示

    2024-04-15 09:26:05       44 阅读
  5. 作为前端TypeScript开发人员学习Rust的经验

    2024-04-15 09:26:05       17 阅读
  6. C++/Qt三维点云PCL/VTK/OpenGL算法项目推荐

    2024-04-15 09:26:05       19 阅读
  7. 多线程八股文常见面试题总结(一)

    2024-04-15 09:26:05       17 阅读
  8. Android14音频进阶之Perfetto高级调试技巧(六十七)

    2024-04-15 09:26:05       19 阅读
  9. docker搭建Lazylibrarian

    2024-04-15 09:26:05       20 阅读