Qt-вызов родительских слотов виджета


Я написал небольшую программу для тестирования доступа к родительскому слоту виджета. В основном, он имеет два класса:

Виджет:

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

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

В основной функции я просто создал экземпляр виджета и вызвал show () на нем. Этот экземпляр виджета имеет метку, в QString, а экземпляр класса customWidget, и две кнопки (внутри класса пользовательского интерфейса, кнопки и ПБ). Одна из кнопок вызывает слот в своем собственном классе под названием changeLabel (), который в качестве имени предлагает, изменяет метку на то, что установлено в QString, содержащемся в нем. Я сделал это только для того, чтобы проверить, что changeLabel() работает. Эта кнопка работает нормально. Другая кнопка вызывает слот в экземпляре customWidget с именем callParentSlot (), который в свою очередь пытается вызвать слот changeLabel () в своем родителе. Поскольку в этом случае я знаю, что его родитель на самом деле является экземпляром Widget, я приведу возвращаемое значение parentWidget() к Widget*. Эта кнопка завершает работу программы. Я сделал кнопку в customWidget, чтобы попытаться вызвать Родительский слот customWidget, а также, но он также аварийно завершает работу программы. Я следил за тем, что было на этом вопросе. Чего мне не хватает?

1 7

1 ответ:

Вы никогда не устанавливаете Родительский виджет для вашего экземпляра customWidget. Таким образом, this->parentWidget(), скорее всего, возвращает нулевой указатель. Внесите следующие изменения:

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

Я бы также посоветовал использовать dynamic_cast и проверять возвращаемое значение. Это предотвратит ваш сбой как в случае, когда parent равен NULL, так и в случае, когда parent не относится к правильному классу.

void customWidget::callParentSlot()
{
    Widget *w = dynamic_cast<Widget *> (this->parentWidget());
    if (0 != w)
        w->changeLabel();
    /* else handle the error */
}
Другой подход заключается в вызове родительского слота через интерфейс сигналов и слотов. Подключите новый сигнал customWidget к Слот виджета в конструкторе виджетов. Затем вы можете вызвать слот из customWidget следующим образом.
emit callParentSignal();