几乎每个QtWidgets类都可以拥有父级。通常,在对象初始化时设置父级是可选的。例如,如果我创建一个继承Widget::Widget(QWidget* parent): QWidget(parent) {
hbox = new QHBoxLayout(this);
yes_button = new QPushButton("&Yes");
no_button = new QPushButton("&No", this);
cancel_button = new QPushButton("&Cancel", hbox);
}
类的类,我将在构造函数上执行以下操作:
cancel_button
我可以设置或不设置父级。我可以将hbox
设为cancel_button
的孩子。我也可以将yes_button
设为QWidget
的孩子,但我认为这样做很糟糕。
这是什么意思?并且,是否真的有必要为我创建的每个基于Panel PanelToCover = new Panel();
public Overlay(Panel paneltocover)
{
PanelToCover = paneltocover;
this.StartPosition = FormStartPosition.Manual;
this.AutoScaleMode = AutoScaleMode.None;
this.Location = paneltocover.PointToScreen(Point.Empty);
this.ClientSize = paneltocover.ClientSize;
paneltocover.LocationChanged += PanelCover_LocationChanged;
paneltocover.ClientSizeChanged += PanelCover_ClientSizeChanged;
this.Show(paneltocover);
paneltocover.Focus();
}
private void PanelCover_LocationChanged(object sender, EventArgs e)
{
this.Location = PanelToCover.PointToScreen(Point.Empty);
}
private void PanelCover_ClientSizeChanged(object sender, EventArgs e)
{
// This works without an issue
this.ClientSize = PanelToCover.ClientSize;
}
的类设置父级?
答案 0 :(得分:15)
除了帮助GUI对象中的绘制顺序外,它还有助于内存管理,因此当您销毁QObject时,它的所有子节点也会被销毁。有关详细信息,请参阅http://doc.qt.io/qt-4.8/objecttrees.html。当父母中的某些内容发生变化时(例如调整大小时),它也可以通知其子女自己更新。
要回答你的问题,你不需要为所有东西设置父级(毕竟这就是为什么它是一个可选参数),但大部分时间最好正确设置它。
答案 1 :(得分:8)
首先,QWidget
是QObject
,而QObject
是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
都需要在堆上显式创建。由于Qt中的所有QObject
派生类(以及许多其他类也是如此!)使用PIMPL习惯用法,当您在堆上单独分配它们时,您实际上正在进行堆分配两次< / em>的。首先分配类的实例 - 有时实例与指针一样小 - 然后类的构造函数分配其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);
}
如果你想使用the 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
而不是所有这些:)