Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is parent for in Qt?

Tags:

Almost every QtWidgets class can have parent. And usually it's optional to set parent at object initialization. For example,If I create a class that inherits QWidget class, I will do the following on the constructor:

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); } 

I can set or not set parent. I can set cancel_button to be a child of hbox. I can too set cancel_button to be a child of yes_button, but I think it's a bad thing to do.

What's the point of this? And, is it really necessary to set parent for every QWidget based class that I create?

like image 652
Mas Bagol Avatar asked May 20 '15 15:05

Mas Bagol


People also ask

What is a parent widget?

A widget only takes another widget as its parent, which is used to implement the parent/child/owner/owned relationship for underlying native windows system. The addWidget function will reparent the widget to the widget the layout is installed to, if it is not the same as the widget's original parent.

How can I get current cursor position in Qt?

To set or get the position of the mouse cursor use the static methods QCursor::pos() and QCursor::setPos().


2 Answers

Besides helping with draw order in GUI objects, it also helps with memory management, so that when you destroy a QObject, all of it's children are destroyed too. See http://doc.qt.io/qt-4.8/objecttrees.html for more details. When something changes in the parent (e.g. when it is resized), it can notify its children to update themselves too.

To answer your question, you're not required to set the parent for everything (that's why it's an optional parameter, after all), but most of the time it's better to set it correctly.

like image 186
Vitor Avatar answered Nov 22 '22 13:11

Vitor


Firstly, a QWidget is a QObject, and QObjects are nodes in a QObject tree. The child nodes are memory-managed by the parent, unless you deallocate them before the parent has a chance to do so. Thus, memory management is one reason for widgets, or any other QObjects, to have a parent.

Secondly, visible parentless widgets are always top-level windows. Conversely, it's impossible to have a non-top-level widget that is parentless. When you show a parentless widget, it acquires its own window. The opposite is not necessarily true - it's possible to give a child widget a Qt::Window flag, and it becomes a top-level window as well.

The corollary is that any widget contained in other widgets has a parent - otherwise it'd be a top-level window. This parent might not be set explicitly by you, but it's set nevertheless.

I think that your question can be rephrased as: When do I need to explicitly give widget constructor a parent? The answer is:

  1. Whenever the widget is a top level window that you intend to have a parent. Such windows are not subject to layout management, so there's no mechanism to set that parent for you. Top-level transient dialogs need to have parents so that they are properly positioned in relation to the parent window.

  2. Whenever you have a child widget not subject to layout management.

Widgets subject to layout management are parented upon insertion into a layout:

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(); } 

Finally, not all widgets or QObjects need to be explicitly created on the heap. Since all QObject-derived classes in Qt (and many other classes, too!) use the PIMPL idiom, when you allocate them individually on the heap, you're really doing the heap allocation twice. First you allocate the instance of the class - sometimes the instance is as small as a pointer or two - and then the class's constructor allocates its PIMPL. Explicit heap allocation is a case of premature pessimization.

To avoid this pessimization, your Widget should look as follows:

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); } 

If you wished to use the PIMPL idiom, you could do that, too:

// 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! 

Of course, you should be using QDialogButtonBox instead of all this :)

like image 32
Kuba hasn't forgotten Monica Avatar answered Nov 22 '22 12:11

Kuba hasn't forgotten Monica