9
votes

I wrote a small program to test accessing a widget parent's slot. Basically, it has two classes:

Widget:

namespace Ui
{
    class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
    QLabel *newlabel;
    QString foo;

public slots:
    void changeLabel();

private:
    Ui::Widget *ui;
};

Widget::Widget(QWidget *parent)
    : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    customWidget *cwidget = new customWidget();
    newlabel = new QLabel("text");
    foo = "hello world";
    this->ui->formLayout->addWidget(newlabel);
    this->ui->formLayout->addWidget(cwidget);

    connect(this->ui->pushButton,SIGNAL(clicked()),cwidget,SLOT(callParentSlot()));
    connect(this->ui->pb,SIGNAL(clicked()),this,SLOT(changeLabel()));
}

void Widget::changeLabel(){
    newlabel->setText(this->foo);
}

and customWidget:

class customWidget : public QWidget
{
    Q_OBJECT
public:
    customWidget();
    QPushButton *customPB;

public slots:
    void callParentSlot();
};

customWidget::customWidget()
{
    customPB = new QPushButton("customPB");
    QHBoxLayout *hboxl = new QHBoxLayout();
    hboxl->addWidget(customPB);
    this->setLayout(hboxl);
    connect(this->customPB,SIGNAL(clicked()),this,SLOT(callParentSlot()));
}

void customWidget::callParentSlot(){
    ((Widget*)this->parentWidget())->changeLabel();
}

in the main function, I simply created an instance of Widget, and called show() on it. This Widget instance has a label, a QString, an instance of customWidget class, and two buttons (inside the ui class, pushButton and pb). One of the buttons calls a slot in its own class called changeLabel(), that, as the name suggests, changes the label to whatever is set in the QString contained in it. I made that just to check that changeLabel() worked. This button is working fine. The other button calls a slot in the customWidget instance, named callParentSlot(), that in turn tries to call the changeLabel() slot in its parent. Since in this case I know that its parent is in fact an instance of Widget, I cast the return value of parentWidget() to Widget*. This button crashes the program. I made a button within customWidget to try to call customWidget's parent slot as well, but it also crashes the program. I followed what was on this question. What am I missing?

1
Why are you trying to call the parent's slot? As it is already a slot, why don't you emit a signal from the child and connect this signal to the parent's slot?erelender
It's because I want to update some variables in the parent widget everytime I make some changes in the child widget. I couldn't figure out any other way other than having the child call its parents widget's slot.liewl
The problem is that the changes in the child widget that I'm concerned with are triggered by buttons in the child widget, so I need to figure out a way to update the variables that are on the parent widget from within the child widget.liewl
Add parameters to your signals & slots, that way you can pass whatever data you want from the child to the parent. Or, in parent's slot, call getter methods of members in the child widget.erelender
I recommend reading here, it might give you better understanding of signals and slots. doc.trolltech.com/4.6/signalsandslots.htmlerelender

1 Answers

2
votes

You never set the parent widget for your customWidget instance. So, this->parentWidget() is likely returning a NULL pointer. Make the following changes:

customWidget *cwidget = new customWidget(this);
...
customWidget(QWidget *parent);
...
customWidget::customWidget(QWidget *parent) : QWidget(parent)

I would also advise using a dynamic_cast and checking the return value. This went prevent your crash in both the case where parent is NULL and where parent is not of the correct class.

void customWidget::callParentSlot()
{
    Widget *w = dynamic_cast<Widget *> (this->parentWidget());
    if (0 != w)
        w->changeLabel();
    /* else handle the error */
}

Another approach would be to call the parent slot through the signals and slots interface. Connect the new customWidget signal to the Widget slot in the Widget constructor. Then you can call the slot from customWidget as follows.

emit callParentSignal();