Qt-调用小部件父级';s槽

Qt-调用小部件父级';s槽,qt,signals-slots,Qt,Signals Slots,我编写了一个小程序来测试访问小部件家长的插槽。基本上,它有两类: 小部件: namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); QLabel *newlabel; QString foo; public slots: void changeLabel

我编写了一个小程序来测试访问小部件家长的插槽。基本上,它有两类:

小部件:

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

在main函数中,我只是创建了一个Widget实例,并对其调用show()。这个小部件实例有一个标签、一个QString、一个customWidget类的实例和两个按钮(在ui类内部,按钮和pb)。其中一个按钮在其自己的类中调用一个名为changelab()的slot,顾名思义,该slot将标签更改为包含在其中的QString中设置的任何内容。我这样做只是为了检查changeLabel()是否有效。这个按钮很好用。另一个按钮调用customWidget实例中名为callParentSlot()的插槽,该插槽反过来尝试调用其父实例中的changeLabel()插槽。因为在本例中,我知道它的父对象实际上是Widget的一个实例,所以我将parentWidget()的返回值转换为Widget*。这个按钮使程序崩溃。我在customWidget中创建了一个按钮,试图调用customWidget的父插槽,但它也会使程序崩溃。我跟踪了问题所在。我缺少什么?

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

customWidget *cwidget = new customWidget(this);
...
customWidget(QWidget *parent);
...
customWidget::customWidget(QWidget *parent) : QWidget(parent)
我还建议使用动态_cast并检查返回值。这可以防止在parent为NULL和parent不属于正确类的情况下发生崩溃

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

即使显式设置了其父级,它仍然会崩溃。当调用addWidget(cwidget)时,cwidget的父级不应该被自动设置吗?我知道这不是一个好主意,但我一直坚持这样做,或者不得不从我正在使用的应用程序中重写大量代码。我不确定addWidget是否会重新编译它。即便如此,你确定它使用了正确的小部件作为父级吗?我的意思是,该函数可能会将不同的QWidget设置为父级。为什么不看看Ui::Widget::addWidget的源代码呢?顺便说一句,您是否尝试过显式地设置父级以查看它是否修复了崩溃错误?为什么尝试调用父级的插槽?既然它已经是一个插槽了,为什么不从子窗口发出一个信号,并将该信号连接到父窗口的插槽?因为每次我在子窗口小部件中进行一些更改时,我都想更新父窗口小部件中的一些变量。除了让孩子调用其父窗口小部件的插槽,我想不出其他方法。问题是我关心的子窗口小部件中的更改是由子窗口小部件中的按钮触发的,因此,我需要找出一种方法,从子窗口小部件内部更新父窗口小部件上的变量。将参数添加到信号和插槽中,这样您就可以将所需的任何数据从子窗口传递到父窗口。或者,在父窗口中,调用子窗口小部件中成员的getter方法。我建议阅读这里的内容,它可能会让您更好地理解信号和窗口。
emit callParentSignal();