我写了一个小程序来测试访问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);
}
和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()。这个Widget实例有一个标签,一个QString,一个customWidget类的实例,以及两个按钮(在ui类中,pushButton和pb)。其中一个按钮在其自己的类中调用一个名为changeLabel()的槽,顾名思义,它将标签更改为包含在其中的QString中设置的任何内容。我这样做是为了检查changeLabel()是否有效。这个按钮工作正常。另一个按钮调用customWidget实例中的一个名为callParentSlot()的插槽,该插槽又尝试调用其父级中的changeLabel()插槽。因为在这种情况下,我知道它的父实际上是Widget的一个实例,我将parentWidget()的返回值转换为Widget *。该按钮使程序崩溃。我在customWidget中创建了一个按钮,试图调用customWidget的父槽,但它也会崩溃程序。我按照this问题进行了跟踪。我错过了什么?
答案 0 :(得分:2)
您永远不会为customWidget
实例设置父窗口小部件。因此,this->parentWidget()
可能会返回NULL指针。进行以下更改:
customWidget *cwidget = new customWidget(this);
...
customWidget(QWidget *parent);
...
customWidget::customWidget(QWidget *parent) : QWidget(parent)
我还建议使用dynamic_cast并检查返回值。这样可以防止在父级为NULL且父级不是正确类的情况下崩溃。
void customWidget::callParentSlot()
{
Widget *w = dynamic_cast<Widget *> (this->parentWidget());
if (0 != w)
w->changeLabel();
/* else handle the error */
}
另一种方法是通过信号和插槽接口调用父插槽。将新的customWidget信号连接到Widget构造函数中的Widget插槽。然后你可以从customWidget调用插槽,如下所示。
emit callParentSignal();