Qt - 调用小部件父级的插槽

lie*_*ewl 7 qt signals-slots

我写了一个小程序来测试访问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);
}
Run Code Online (Sandbox Code Playgroud)

和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();
}
Run Code Online (Sandbox Code Playgroud)

在main函数中,我只创建了一个Widget实例,并在其上调用了show().这个Widget实例有一个标签,一个QString,一个customWidget类的实例,以及两个按钮(在ui类中,pushButton和pb).其中一个按钮在其自己的类中调用一个名为changeLabel()的槽,顾名思义,它将标签更改为包含在其中的QString中设置的任何内容.我这样做是为了检查changeLabel()是否有效.这个按钮工作正常.另一个按钮调用customWidget实例中的一个名为callParentSlot()的插槽,该插槽又尝试调用其父级中的changeLabel()插槽.因为在这种情况下,我知道它的父实际上是Widget的一个实例,我将parentWidget()的返回值转换为Widget*.该按钮使程序崩溃.我在customWidget中创建了一个按钮,试图调用customWidget的父槽,但它也会崩溃程序.我关注了这个问题.我错过了什么?

Jud*_*den 2

您从未为您的实例设置父小部件customWidget。因此,this->parentWidget()很可能返回一个 NULL 指针。进行以下更改:

customWidget *cwidget = new customWidget(this);
...
customWidget(QWidget *parent);
...
customWidget::customWidget(QWidget *parent) : QWidget(parent)
Run Code Online (Sandbox Code Playgroud)

我还建议使用dynamic_cast并检查返回值。这可以防止在父级为 NULL 和父级不属于正确的类的情况下发生崩溃。

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

另一种方法是通过信号和槽接口调用父槽。将新的 customWidget 信号连接到 Widget 构造函数中的 Widget 槽。然后您可以从 customWidget 调用该插槽,如下所示。

emit callParentSignal();
Run Code Online (Sandbox Code Playgroud)