Widget parenting

From qtnode

Jump to: navigation, search

Contents

Getting Started

The issue of widget parenting is often an elusive subject to a newer Qt programmer, but with a little guidance, you will be on your way to correctly understanding and implementing Qt’s powerful system of object ancestry. We will use QPushButton to demonstrate proper widget parenting. There are three constructors that can be used to instantiate a QPushButton object:

QPushButton ( QWidget * parent = 0 )
QPushButton ( const QString & text, QWidget * parent = 0 )
QPushButton ( const QIcon & icon, const QString & text, QWidget * parent = 0 )

Notice that in each of the constructors, there is an argument that sets its QWidget * parent equal to 0. This means that if you do not provide an argument in that position of the parameter list, the QPushButton constructor will automatically be passed the argument 0 for you.

Basic Parenting

If the parent of a widget is set to 0, then the widget will become a window (unless it is reparented later). Typically, you want a push button to be displayed on a window with other widgets. In this simple example, you would set the parent to the window in which you would like for it to be displayed:

QDialog * myDialog = new QDialog;  //parent = 0, so it is a window

QPushButton * myPushButton = new QPushButton(myDialog);  //parent = myDialog
myPushButton->setText(QString(tr(“&Open”)));

myDialog->show();

Notice that we passed myDialog into the constructor of our QPushButton. The compiler will compare our argument list to the constructors and use the one that matches it, which in this case is the first constructor listed above. Since we have set the parent of myPushButton to be myDialog, we know that when myDialog is deleted, myPushButton will also be deleted automatically. Qt handles the automatic deletion of a parent’s children when the parent is deleted.

Custom Widgets

If we want to subclass QDialog (a typical scenario), and instantiate our push button from the constructor of our custom dialog class, we could instead use the this pointer as the parent. this is a pointer that points to the object in which the statement is invoked. For example:

class MyDialog : public QDialog 
{
    Q_OBJECT

public:
    MyDialog(QWidget *parent = 0);
};

MyDialog::MyDialog(QWidget *parent) : QDialog(parent)
{
    QPushButton * myPushButton = new QPushButton(this);  //now we use the this pointer
    myPushButton->setText(QString(tr(“&Open”)));
}

In this case, the this pointer refers to our MyDialog object.

Bring it all Together

A more useful scenario is to use a QLayout to manage the visual organization of the widgets on our dialog:

MyDialog::MyDialog(QWidget *parent) : QDialog(parent)
{
    QPushButton * myPushButton = new QPushButton;  //parent = 0
    myPushButton->setText(QString(tr(“&Open”)));

    QPushButton * mySecondPushButton = new QPushButton;  //parent = 0
    mySecondPushButton->setText(QString(tr(“&Save”)));

    QHBoxLayout * myHorzLayout = new QHBoxLayout;  //parent = 0
    myHorzLayout->addWidget(myPushButton);  //myPushButton parent still = 0    
    myHorzLayout->addWidget(mySecondPushButton);  //mySecondPushButton parent still = 0

    this->setLayout(myHorzLayout);
}

We create our push buttons with no arguments, so the default constructor is invoked, setting the parent to 0. When we add these widgets to our horizontal box layout, the buttons are automatically re-parented to the parent of the layout. However, it is a typical practice to set the layout manager's parent to 0 when it is instantiated, and allow the setLayout function to automatically handle reparenting for us. We call setLayout, setting myHorzLayout as the layout manager for our MyDialog object. This will reparent the myHorzLayout to this. As a consequence, all widgets that are managed by our myHorzLayout are reparented to the parent of myHorzLayout, so the end result is that our two push buttons now also have this as their parent.


In the last statement, this is written explicitly for clarity. The common practice is to omit the this pointer when invoking a class member function from within its definition, so the last statement would be written simply as:

setLayout(myHorzLayout);

Note, however, that this is an academic example. The use of setLayout is unnecessary, for instance, as we could have specified this as the parent of myHorzLayout when we created it to have the same effect. Furthermore, instantiating widgets without a parent and later parenting them is less efficient than specifying their parent in the constructor. The above example could have been written as:

MyDialog::MyDialog(QWidget *parent) : QDialog(parent)
{
    QPushButton * myPushButton = new QPushButton(QString(tr(“&Open”)), this);
    QPushButton * mySecondPushButton = new QPushButton(QString(tr(“&Save”)), this);

    QHBoxLayout * myHorzLayout = new QHBoxLayout(this);
    myHorzLayout->addWidget(myPushButton);
    myHorzLayout->addWidget(mySecondPushButton);
}

Note how the different constructor for QPushButton was used to automatically set their text and assign the dialog as the widget's parent. Also note that you should always specify the widget the new widget is to be placed upon as the parent, as layouts cannot be parents of widgets.

Personal tools