Что такое parent для Qt?
почти каждый класс QtWidgets может иметь Родительский. И обычно необязательно устанавливать parent при инициализации объекта. Например,если я создаю класс, который наследует QWidget
класс, я сделаю следующее В конструкторе:
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
основанный класс, который я создаю?
2 ответов
помимо помощи с порядком рисования в объектах GUI, это также помогает с управлением памятью, так что когда вы уничтожаете QObject, все его дети тоже уничтожаются. Вижу http://doc.qt.io/qt-4.8/objecttrees.html для более подробной информации. Когда что-то меняется в родителе (например, когда он изменяется), он может уведомить своих детей, чтобы обновить себя тоже.
чтобы ответить на ваш вопрос, вам не нужно устанавливать родителя для всего (вот почему это необязательно параметр, в конце концов), но в большинстве случаев лучше установить его правильно.
во-первых, a QWidget
- это 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 необходимо явно создать в куче. С тех пор все 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);
}
если вы хотите использовать идиома сутенера, Вы тоже можете это сделать:
// 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
вместо всего этого :)