9

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?

Community
  • 1
  • 1
liewl
  • 4,021
  • 13
  • 46
  • 65
  • 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 Apr 06 '10 at 13:15
  • 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 Apr 06 '10 at 13:18
  • 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 Apr 06 '10 at 13:25
  • 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 Apr 06 '10 at 13:40
  • I recommend reading here, it might give you better understanding of signals and slots. http://doc.trolltech.com/4.6/signalsandslots.html – erelender Apr 06 '10 at 13:41
  • Thanks for the suggestion, seems like I'm not used to think in terms of signals and slots. – liewl Apr 06 '10 at 14:07

1 Answers1

2

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();
Judge Maygarden
  • 26,961
  • 9
  • 82
  • 99
  • It still crashes, even after explicitly setting its parent. Shouldn't cwidget's parent be automatically set when addWidget(cwidget) is called? – liewl Apr 06 '10 at 13:07
  • I know that it's not a good idea, but I'm stuck with doing this or having to rewrite a huge chunk of code from an app I'm working with – liewl Apr 06 '10 at 13:10
  • I'm not sure if addWidget reparents it. Even so, are you sure it uses the correct widget as a parent? – Judge Maygarden Apr 06 '10 at 13:12
  • I mean, that function could possibly set a different QWidget as the parent. Why don't you take a look at the source code for Ui::Widget::addWidget? – Judge Maygarden Apr 06 '10 at 13:33
  • BTW, have you tried explicitly setting the parent to see if it fixes the crash bug? – Judge Maygarden Apr 06 '10 at 13:34
  • I tried, it still crashes. Now that you said it, maybe when I call addWidget(cwidget), it resets the formLayout as the parent, instead of Widget, which is the parent of the formLayout. – liewl Apr 06 '10 at 13:46
  • Yes, that was it. I changed the ((Widget*)this->parentWidget())->changeLabel() to ((Widget*)this->parentWidget()->parentWidget())->changeLabel() and it worked. It's so goddamn ugly. – liewl Apr 06 '10 at 13:54
  • A very explicit solution would be to pass a Widget reference to customWidget and hold it as a member variable instead of using the Qt parent/child tree. – Judge Maygarden Apr 06 '10 at 13:54
  • I guess I still don't really know how to use the signals-slots system. Seems like the proper way to do what I want. Thanks – liewl Apr 06 '10 at 14:06