2010-04-06 147 views
7

我写了一个小程序来测试访问窗口窗口小部件的窗口。基本上,它有两类:Qt - 调用窗口小部件父窗口

的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(); 
} 
在主函数

,我只是在上面创建的)Widget实例,并称之为表演( 。这个Widget实例有一个标签,一个QString,一个customWidget类的实例和两个按钮(在ui类中,pushButton和pb)。其中一个按钮在其自己的类中调用了一个名为changeLabel()的槽,如名称所示,它将标签更改为包含在其中的QString中设置的任何值。我只是为了检查changeLabel()的工作。这个按钮工作正常。另一个按钮调用名为callParentSlot()的customWidget实例中的插槽,该插槽又会尝试调用其父级中的changeLabel()插槽。因为在这种情况下,我知道它的父实际上是一个Widget的实例,所以我将parentWidget()的返回值转换为Widget *。该按钮会使程序崩溃。我在customWidget中创建了一个按钮,以尝试调用customWidget的父插槽,但它也会使程序崩溃。我跟着this的问题。我错过了什么?

+0

你为什么要打电话给父母的插槽?由于它已经是一个插槽,为什么不从孩子发出信号并将此信号连接到父母的插槽? – erelender 2010-04-06 13:15:29

+0

这是因为我想每次在子部件中进行一些更改时,都要更新父部件中的一些变量。除了让孩子打电话给父母小工具的插槽之外,我无法想出任何其他方式。 – 2010-04-06 13:18:12

+0

问题是,我关心的子窗口小部件中的更改是由子窗口小部件中的按钮触发的,所以我需要找出一种方法来更新子窗口小部件中父控件上的变量。 – 2010-04-06 13:25:29

回答

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(); 
+0

即使在明确设置其父项之后,它仍然崩溃。在调用addWidget(cwidget)时,不应该自动设置cwidget的父级? – 2010-04-06 13:07:26

+0

我知道这不是一个好主意,但我坚持要做到这一点,或者不得不从我正在使用的应用程序重写一大段代码 – 2010-04-06 13:10:25

+0

我不确定addWidget是否能够补救它。即便如此,你确定它使用正确的小部件作为父项吗? – 2010-04-06 13:12:44