【问题标题】:Qt - Calling widget parent's slotsQt - 调用小部件父的插槽
【发布时间】:2010-04-06 12:52:25
【问题描述】:

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

小部件:

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 的问题。我错过了什么?

【问题讨论】:

  • 你为什么要调用父母的插槽?既然它已经是一个槽,为什么不从孩子发出一个信号并将这个信号连接到父母的槽?
  • 这是因为我想在每次对子小部件进行一些更改时更新父小部件中的一些变量。除了让孩子调用其父母小部件的插槽之外,我想不出任何其他方式。
  • 问题是我关心的子小部件中的变化是由子小部件中的按钮触发的,所以我需要想办法更新父小部件上的变量子小部件中的小部件。
  • 向你的信号和槽添加参数,这样你就可以将你想要的任何数据从孩子传递给父母。或者,在 parent 的 slot 中,调用 child widget 中成员的 getter 方法。
  • 我推荐阅读这里,它可能会让你更好地理解信号和槽。 doc.trolltech.com/4.6/signalsandslots.html

标签: qt signals-slots


【解决方案1】:

您永远不会为您的 customWidget 实例设置父窗口小部件。所以,this->parentWidget() 很可能返回一个 NULL 指针。进行以下更改:

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 信号连接到 Widget 构造函数中的 Widget 插槽。然后就可以从 customWidget 中调用 slot,如下所示。

emit callParentSignal();

【讨论】:

  • 它仍然崩溃,即使在明确设置其父级之后。调用addWidget(cwidget)时不应该自动设置cwidget的父级吗?
  • 我知道这不是一个好主意,但我坚持这样做,或者不得不从我正在使用的应用程序中重写大量代码
  • 我不确定 addWidget 是否是它的父代。即便如此,您确定它使用正确的小部件作为父级吗?
  • 我的意思是,该函数可能会将不同的 QWidget 设置为父级。为什么不看一下 Ui::Widget::addWidget 的源代码?
  • 顺便说一句,您是否尝试过显式设置父级以查看它是否修复了崩溃错误?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多