如何从 QGraphicsView 释放 QGLWidget
how to release QGLWidget from QGraphicsView
我看到很多关于使用 OpenGL 进行图形视图的 Qt 示例。
大多数示例如下所示:
MyGraphicsView::MyGraphicsView(......)
{
gl = new QGLWidget();
this->setViewport(gl);
....
其中 QGLWidget* gl 是 MyGraphicsView 的成员。
我的问题是我应该如何删除 "gl"。
它会随着我从 QGraphicsView 继承的 class 自动删除吗?
在 MyGraphicsView descructor 中手动删除 "gl" 会导致崩溃。
在 Qt 中真的很难理解哪些对象会被自动删除,哪些不会。
In Qt really difficult to understand which object will be autodeleted and which not.
完全没有。你只需要知道两件事:
C++ 作用域的语义。但您已经知道这些 - 希望如此。
即QObject::~QObject()
删除其幸存的children:
QObject::~QObject() {
...
for (auto child : children())
delete child;
...
}
显然,如果 child 在 进入 ~QObject()
之前被销毁 ,那么它不会出现在 parent' s children()
列表,不会是 doubly-deleted。这在某种程度上似乎让大多数人望而却步,但如果有人不认为 Qt 是一种魔法,它不应该。 Qt 做 C++ 允许它做的事情。仅此而已。
因此,如果任一条件为真,object 将为您销毁:
你在范围内按值保存它,例如
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
它仍然存在并且在 parent 的 ~QObject()
析构函数执行时有一个 parent。回想一下,所有小部件都是 QObject
s.
在上面的示例中,m_gl
object 将在 MyGraphicsView::~QObject
到达 运行 之前被销毁并因此不复存在,因此不可能double-destruction.
但您也可以使用 prematurely-pessimized held-by-pointer 方法:
// 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
析构函数 运行s,此时它迭代其 child 列表和每个 child 的 delete
s - 从而删除 QOpenGlWidget
实例。
Manual delete for "gl" in MyGraphicsView descructor causes crash.
不,它不会,除非你没有告诉我们什么。以下内容在 Qt 4 和 Qt 5 中都可以正常工作。手动删除是无害的,尽管完全没有必要:
// https://github.com/KubaO/Whosebugn/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();
}
我看到很多关于使用 OpenGL 进行图形视图的 Qt 示例。 大多数示例如下所示:
MyGraphicsView::MyGraphicsView(......)
{
gl = new QGLWidget();
this->setViewport(gl);
....
其中 QGLWidget* gl 是 MyGraphicsView 的成员。
我的问题是我应该如何删除 "gl"。 它会随着我从 QGraphicsView 继承的 class 自动删除吗? 在 MyGraphicsView descructor 中手动删除 "gl" 会导致崩溃。
在 Qt 中真的很难理解哪些对象会被自动删除,哪些不会。
In Qt really difficult to understand which object will be autodeleted and which not.
完全没有。你只需要知道两件事:
C++ 作用域的语义。但您已经知道这些 - 希望如此。
即
QObject::~QObject()
删除其幸存的children:QObject::~QObject() { ... for (auto child : children()) delete child; ... }
显然,如果 child 在 进入
~QObject()
之前被销毁 ,那么它不会出现在 parent' schildren()
列表,不会是 doubly-deleted。这在某种程度上似乎让大多数人望而却步,但如果有人不认为 Qt 是一种魔法,它不应该。 Qt 做 C++ 允许它做的事情。仅此而已。
因此,如果任一条件为真,object 将为您销毁:
你在范围内按值保存它,例如
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
它仍然存在并且在 parent 的
~QObject()
析构函数执行时有一个 parent。回想一下,所有小部件都是QObject
s.在上面的示例中,
m_gl
object 将在MyGraphicsView::~QObject
到达 运行 之前被销毁并因此不复存在,因此不可能double-destruction.但您也可以使用 prematurely-pessimized held-by-pointer 方法:
// 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
析构函数 运行s,此时它迭代其 child 列表和每个 child 的delete
s - 从而删除QOpenGlWidget
实例。
Manual delete for "gl" in MyGraphicsView descructor causes crash.
不,它不会,除非你没有告诉我们什么。以下内容在 Qt 4 和 Qt 5 中都可以正常工作。手动删除是无害的,尽管完全没有必要:
// https://github.com/KubaO/Whosebugn/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();
}