首先, aQWidget
是 a QObject
,QObject
s 是QObject
树中的节点。子节点由父节点管理内存,除非您在父节点有机会这样做之前释放它们。因此,内存管理是小部件或任何其他QObject
s 拥有父级的原因之一。
其次,可见的无父小部件始终是顶级窗口。相反,不可能有一个没有父级的非顶级小部件。当您显示无父窗口小部件时,它会获取自己的窗口。相反的不一定是正确的——可以给一个子部件一个Qt::Window
标志,它也成为一个顶级窗口。
推论是其他小部件中包含的任何小部件都有一个父窗口 - 否则它将是一个顶级窗口。您可能没有明确设置此父级,但仍然设置了它。
我认为你的问题可以改写为:我什么时候需要明确地给小部件构造函数一个父级?答案是:
每当小部件是您打算拥有父级的顶级窗口时。此类窗口不受布局管理的约束,因此没有为您设置该父级的机制。顶级瞬态对话框需要有父级,以便它们相对于父窗口正确定位。
每当您有一个不受布局管理约束的子小部件时。
受布局管理的小部件在插入布局时成为父级:
int main(int argc, char ** argv) {
QApplication app(argc, argv);
QWidget window;
QVBoxLayout layout(&window);
QLabel label("Hello");
QPushButton button("Goodbye");
layout.addWidget(&label);
layout.addWidget(&button);
QObject::connect(&button, &QPushButton::clicked, [&app]{ app.quit(); });
window.show();
return app.exec();
}
最后,并非所有小部件或QObject
s 都需要在堆上显式创建。由于 Qt 中的所有QObject
派生类(以及许多其他类!)都使用 PIMPL 习惯用法,因此当您在堆上单独分配它们时,实际上是在进行两次堆分配。首先分配类的实例——有时实例小到一两个指针——然后类的构造函数分配它的 PIMPL。显式堆分配是过早悲观化的一种情况。
为避免这种悲观情绪,您Widget
应该如下所示:
class Widget : public QWidget {
Q_OBJECT
QHBoxLayout m_layout;
QPushButton m_yesButton, m_noButton, m_cancelButton;
public:
Widget(QWidget * parent = 0);
};
Widget::Widget(QWidget * parent) :
QWidget(parent),
m_layout(this),
m_yesButton("&Yes"),
m_noButton("&No"),
m_cancelButton("&Cancel")
{
m_layout.addWidget(&m_yesButton);
m_layout.addWidget(&m_noButton);
m_layout.addWidget(&m_cancelButton);
}
如果你想使用PIMPL idiom,你也可以这样做:
// Widget.h - Interface
class WidgetPrivate;
class Widget : public QWidget {
{
Q_OBJECT
Q_DECLARE_PRIVATE(Widget)
QScopedPointer<WidgetPrivate> const d_ptr;
public:
Widget(QWidget * parent = 0);
~Widget();
};
// Widget.cpp - Implementation
class WidgetPrivate {
Q_DISABLE_COPY(WidgetPrivate)
Q_DECLARE_PUBLIC(Widget)
Widget * const q_ptr;
QHBoxLayout layout;
QPushButton yesButton, noButton, cancelButton;
public:
WidgetPrivate(Widget * q);
};
WidgetPrivate::WidgetPrivate(Widget * q) {
q_ptr(q),
layout(q),
yesButton("&Yes"),
noButton("&No"),
cancelButton("&Cancel")
{
layout.addWidget(&yesButton);
layout.addWidget(&noButton);
layout.addWidget(&cancelButton);
}
Widget::Widget(QWidget * parent) :
QWidget(parent),
d_ptr(new WidgetPrivate(this))
{}
Widget::~Widget() {}
// necessary, since WidgetPrivate is unknown to the interface!
当然,您应该使用QDialogButtonBox
而不是所有这些:)