我是Qt的新手,我对如何删除小部件非常困惑。我正在阅读视频,我想在读取视频帧时显示QProgressbar,然后在加载视频时删除此QProgressbar。
我用两种不同的方式完成了它:
使用指针
QWidget* wd = new QWidget();
QProgressBar* pB = new QProgressBar(wd);
QLabel* label = new QLabel(wd);
//setting geometry and updating the label and progressbar
wd->deleteLater();
wd->hide();
这个代码写在一个类中,我假设当这个类的析构函数被调用时,小部件将被删除所有它的孩子但是没有发生,每次我再次运行这个函数一个新的小部件是创建时没有隐藏或删除前一个(注意:我试图从小部件中删除标签和进度条,假设它们将从小部件内部消失,但这不会发生“删除(pB);”)
使用对象
QWidget wd;
QProgressBar pB(&wd);
QLabel label(wd);
//setting geometry and updating the label and progressbar
wd.deleteLater();
wd.hide();
当我运行相同的代码但使用对象代替指针时,它运行完全符合我的需要,每次运行该函数时,旧的小部件都会被销毁并创建一个新的小部件。
注意: - 当我关闭主窗口时,如果是指针,小部件wd仍然存在,程序不会终止,直到我手动关闭它们 - 如果是对象,当我关闭主窗口时,一切都关闭,程序正确终止。
我需要有人解释我为什么会发生这种情况以及如果我有一个指向小部件的指针向量来删除该向量内的所有指针而没有任何内存泄漏
答案 0 :(得分:0)
在典型的C ++中,规则是"为每delete
"写一个new
。一个更高级的规则是#34;可能不会写new
或delete
并将其隐藏在RIAA模式中而不是"。 Qt在这方面改变了规则,因为它引入了自己的内存管理范例。它基于父/子关系。 QWidget
次new
可以parentWidget()
parentWidget()
。当new
被摧毁时,它的所有孩子都将被摧毁。因此,在Qt中,通常的做法是使用delete
在堆栈上分配对象,给它们一个父级,而不要自己QLayout
内存。使用deleteLater
时规则变得更加复杂,有时候Qt对象会占用小部件,有时它们也不会。
在您的情况下,您可能不需要wd
来电。这会向Qt的内部事件循环发布消息。消息说,"当你有机会时删除我!"如果您希望班级管理this
,只需将其设为df <- data.frame(id = LETTERS[1:3], name=c("Alice", "Bob", "Carol"))
mylist=list(c(1,2,3), c(4,5), c(1,3,4))
df$numvecs <- mylist
df
# id name numvecs
# 1 A Alice 1, 2, 3
# 2 B Bob 4, 5
# 3 C Carol 1, 3, 4
的父级。删除类后,将删除整个父/子树。
答案 1 :(得分:0)
这一切都非常简单。 QObject
- 派生类与任何其他C ++类一样,但有一个例外:如果QObject
有子节点,它将删除析构函数中的子节点。请记住,QWidget
是一个QObject. If you have an instance allocated using
new`,您必须删除它,或确保某些内容(智能指针!)可以。
当然,尝试delete
你没有动态分配的东西是错误的,因此:
如果您不动态分配QObject
,不 deleteLater
或delete
。
如果您没有动态分配QObject
个孩子,请确保在对象被破坏之前它们已经消失。
此外,不会隐藏您即将破坏的小部件。这毫无意义。
要自己管理窗口小部件生命周期,您应该使用智能指针:
class MyClass {
QScopedPointer<QWidget> m_widget;
public:
MyClass() :
widget{new QWidget};
{
auto wd = m_widget->data();
auto pb = new QProgressBar{wd};
auto label = new QLabel{wd};
}
};
当您销毁MyClass
时,作用域指针的析构函数将删除小部件实例,其QObject::~QObject
析构函数将删除其子级。
当然,这些都不是必需的:您应该只是将对象创建为类的直接成员:
class MyClass {
// The order of declaration has meaning! Parents must precede children.
QWidget m_widget;
QProgressBar m_bar{&m_widget};
QLabel m_label{&m_widget};
public:
MyClass() {}
};
通常,您将使用子窗口小部件的布局:
class MyClass {
QWidget m_widget;
QVBoxLayout m_layout{&m_widget};
QProgressBar m_bar;
QLabel m_label;
public:
MyClass() {
m_layout.addWidget(&m_bar);
m_layout.addWidget(&m_label);
}
};
当您向布局添加小部件时,它会将它们重新设置为已设置布局的小部件。
编译器生成的析构函数如下所示。你不能编写这样的代码,因为编译器生成的代码会双重破坏已经被破坏的对象,但让我们假装你可以。
MyClass::~MyClass() {
m_label.~QLabel();
m_bar.~QProgressBar();
m_layout.~QVBoxLayout();
// At this point m_widget has no children and its `~QObject()` destructor
// won't perform any child deletions.
m_widget.~QWidget();
}