看起来某物如果父级不仅仅通过布局来了解其子级,那么效果会更好。
你是对的。 AQObject
的parent不仅用于内存管理目的,这个答案总结了它的一些其他用法。这里最重要的是QWidget
的(因为您担心添加成员QWidget
's),所以如果您按照编写的方式使用第二种方法,您可能会遇到以下一些问题:
-
假设你正在实例化Widget1
并将其显示在您的主函数中,如下所示:
Widget1 w;
w.show();
这将显示一个空的小部件,其中没有按钮。与以下行为相反button
是 的孩子Widget1
对象,在哪里调用show()显示小部件父级及其所有子级。
使用时出现类似问题setEnabled(), setLayoutDirection(), ...
button.pos()不会返回相对于的坐标Widget1
,事实上该按钮甚至没有显示在其中。使用时同样问题move()
.
事件系统可能无法按预期工作。因此,如果成员小部件不处理某些鼠标/键盘事件,则该事件不会传播到parent小部件(因为没有指定父级)。
但是可以编写第二种方法来利用与 RAII 的父母关系,这样就避免了上述问题:
class Widget2 : public QWidget
{
public:
explicit Widget2(QWidget* parent = nullptr):QWidget(parent){}
private:
QPushButton button{this}; //C++11 member initializer list
};
或者,在 C++11 之前的版本中:
class Widget2 : public QWidget
{
public:
//initialize button in constructor, button's parent is set to this
explicit Widget2(QWidget* parent = Q_NULLPTR):QWidget(parent), button(this){}
private:
QPushButton button;
};
这样,两种方法之间的 Qt 框架就没有任何差异。实际上,使用第二种方法可以避免不必要时的动态分配(请注意,如果例如在某些嵌套循环中非常频繁地执行分配,这可能会具有稍好的性能。但是,对于大多数应用程序来说,性能在这里并不是真正的问题)。因此,您可能会像这样编写小部件:
class Widget : public QWidget
{
public:
explicit Widget(QWidget* parent = nullptr):QWidget(parent){
//add widgets to the layout
layout.addWidget(&button);
layout.addWidget(&lineEdit);
layout.addWidget(&label);
}
~Widget(){}
private:
//widget's layout as a child (this will set the layout on the widget)
QVBoxLayout layout{this};
//ui items, no need to set the parent here
//since this is done automatically in QLayout::addWidget calls in the constructor
QPushButton button{"click here"};
QLineEdit lineEdit;
QLabel label{"this is a sample widget"};
};
这很好,有人可能会说这些子部件/对象将被销毁两次,第一次是当它们超出范围时,第二次是当它们的父级被销毁时,使得该方法不安全。这是not一个问题是,一旦子对象被销毁,它就会从其父对象的子对象列表中删除自己,请参阅docs. So, 每个对象都会被销毁一次.