如何从QGraphicsView中释放QGLWidget



我看到许多关于使用OpenGL进行图形视图的Qt示例。大多数示例看起来像这样:

MyGraphicsView::MyGraphicsView(......)
{
gl = new QGLWidget();
this->setViewport(gl);
....

where QGLWidget* gl是MyGraphicsView的成员

我的问题是如何之后,我应该删除"gl"。它会被自动删除与我的类继承从QGraphicsView?手动删除MyGraphicsView解构器中的"gl"会导致崩溃。

在Qt中真的很难理解哪些对象会被自动删除,哪些不会。

在Qt中真的很难理解哪些对象会被自动删除,哪些不会。

一点也不。你只需要知道两件事:

  1. c++作用域的语义。但是你已经知道这些了——希望如此。

  2. QObject::~QObject()删除其存活的子代:

    QObject::~QObject() {
      ...
      for (auto child : children())
        delete child;
      ...
    }
    

    显然,如果子节点在进入~QObject()之前已经被销毁了,那么它就不会出现在父节点的children()列表中,也不会被双重删除。这在某种程度上似乎让大多数人感到困惑,但如果你不认为Qt是一种魔法,那么不应该。Qt做c++允许它做的事情。不多不少。

因此,如果其中一个为真,对象将被析构:

  1. 在作用域中按值保存,例如

    class MyGraphicsView : public QGraphicsView {
       QOpenGLWidget m_gl;
    public:
       MyGraphicsView(QWidget * parent = nullptr) : QGraphicsView{parent} {
          setViewport(&m_gl); // sets m_gl's parent
          Q_ASSERT(m_gl.parent());
       }
    };
    

    m_gl成员将在 ~MyGraphicsView的体返回后被销毁。下面是销毁顺序:

    this->~MyGraphicsView()
    m_gl.~QOpenGlWidget()  // the viewport widget ceases to exist here
    this->~QGraphicsView()
    this->~QAbstractScrollArea()
    this->~QFrame()
    this->~QWidget()
    this->~QObject()  // has no children to delete
    
  2. 它仍然存在,并且在父类 ~QObject()析构函数执行时已经有了父类。回想一下,所有的小部件都是QObject s。

    在上面的例子中,m_gl对象将在MyGraphicsView::~QObject运行之前被销毁——因此不再存在,因此不存在双重销毁的可能性。

    但是您也可以使用过早悲观的指针控制方法:

    // Don't code like this. It's silly.
    class MyGraphicsView : public QGraphicsView {
       QOpenGLWidget * m_gl;
    public:
       MyGraphicsView(QWidget * parent = nullptr) :
          QGraphicsView{parent},
          m_gl{new QOpenGLWidget}
       {
          setViewport(m_gl); // sets m_gl's parent
          Q_ASSERT(m_gl->parent());
       }
       ~MyGraphicsView() {
          Q_ASSERT(m_gl->parent()); // make sure ~QObject will delete the child
       }
    };
    

    销毁顺序如下:

    this->~MyGraphicsView()
    m_gl.~pointer       // a trivial destructor of a pointer value
    this->~QGraphicsView()
    this->~QAbstractScrollArea()
    this->~QFrame()
    this->~QWidget()
    this->~QObject()
      for (auto child : children())
        delete child
          ~QOpenGlWidget()  // m_gl is long gone at this point!
    

    由于m_gl成员的销毁是微不足道的,并且不会对指针本身所指向的内容做任何操作,因此QOpenGlWidget实例一直存在,直到QObject析构函数运行,此时它迭代其子列表,delete迭代每个子列表,从而删除QOpenGlWidget实例。

手动删除MyGraphicsView解构器中的"gl"会导致崩溃。

不,没有,除非你有事瞒着我们。下面的代码在Qt 4和Qt 5中都可以正常工作。手动删除是无害的,尽管完全没有必要:
// https://github.com/KubaO/stackoverflown/tree/master/questions/opengl-viewport-val-39750134
#include <QtGui>
#include <QtOpenGL>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#else
using QOpenGLWidget = QGLWidget;
#endif
// Don't code like this. It's silly.
class MyGraphicsView : public QGraphicsView {
   QOpenGLWidget * m_gl = new QOpenGLWidget;
public:
   MyGraphicsView(QWidget * parent = nullptr) : QGraphicsView{parent}
   {
      setViewport(m_gl); // sets m_gl's parent
      Q_ASSERT(m_gl->parent());
   }
   ~MyGraphicsView() {
      delete m_gl; // completely unnecessary
   }
};
int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   MyGraphicsView view;
   QGraphicsScene scene;
   scene.addText("Hello World");
   view.setScene(&scene);
   view.show();
   return app.exec();
}

相关内容

  • 没有找到相关文章

最新更新