Во-первых, QWidget
— это QObject
, а QObject
— это узлы в дереве QObject
. Дочерние узлы управляются памятью родителем, если только вы не освободите их до того, как родитель сможет это сделать. Таким образом, управление памятью является одной из причин, по которой виджеты или любые другие QObject
имеют родителя.
Во-вторых, видимые виджеты без родителей всегда являются окнами верхнего уровня. И наоборот, невозможно иметь виджет не верхнего уровня, который не имеет родителей. Когда вы показываете виджет без родителей, он получает собственное окно. Обратное не всегда верно — дочернему виджету можно присвоить флаг 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
должны быть явно созданы в куче. Поскольку все производные от QObject
классы в Qt (и многие другие классы тоже!) используют идиому 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, вы также можете это сделать:
// 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
вместо всего этого :)
person
Kuba hasn't forgotten Monica
schedule
20.05.2015
QWidget
происходит отQObject
? - person cmannett85   schedule 20.05.2015