如何从QGraphicsView发布QGLWidget

时间:2016-09-28 14:16:16

标签: qt destructor qgraphicsview qglwidget

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

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

其中QGLWidget * gl是MyGraphicsView的成员。

我的问题是在那之后我应该删除" gl"。 我的类继承自QGraphicsView会自动删除吗? 手动删除" gl"在MyGraphicsView中,descructor导致崩溃。

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

1 个答案:

答案 0 :(得分:1)

  

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

完全没有。你只需要知道两件事:

  1. C ++范围的语义。但是你已经知道了 - 希望如此。

  2. QObject::~QObject()删除了幸存的孩子:

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

    显然,如果一个孩子在输入~QObject()之前被销毁,那么它就不会在父母的children()列表中,并且不会被双重删除。这在某种程度上似乎让大多数人失望,但如果没有人认为Qt不是魔术,那么就不应该。 Qt做了C ++允许它做的事情。没什么,没什么。

  3. 因此,如果其中任何一个为真,对象将被破坏:

    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运行之前被销毁 - 因此不再存在 - 因此不存在双重破坏的可能性。< / p>

      但是你也可以采用过早悲观的指针式方法:

      // 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实例。

    3.   

      手动删除&#34; gl&#34;在MyGraphicsView中,descructor导致崩溃。

      不,它没有,除非你没有告诉我们什么。以下在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();
      }