new Signal/Slot syntax with parent QWidget?
-
Hi
I just try to understand how to use the "new" signal & slot syntax in QT.I have a simple QWidget that emits "pi" to a promoted subclass widget.
It works without problem with the old SIGNAL/SLOT syntax. But how to do it with the new?
I have commented out the working part. The line after it is wrong.
the code of the promoted widget "myWidget.cpp":#include "mywidget.h" #include <QDebug> #include <QWidget> #include <QLabel> #include <QVBoxLayout> myWidget::myWidget(QWidget *parent) : QWidget(parent) { //connect(parent,SIGNAL(send_pi(double)), this, SLOT(showPi(double))); connect(parent, &QWidget::send_pi(double), this, &myWidget::showPi(double)); QVBoxLayout *vl = new QVBoxLayout(this); vl->addWidget(pi_label); } void myWidget::showPi(double x){ pi_label->setText(QString::number(x)); }
I get the error
./test/mywidget.cpp:9:18: error: 'send_pi' is not a member of 'QWidget'
How do I reach the parent widget signal with the new syntax?
-
The new syntax uses pointers to member functions. This means you just give it a pointer and skip the arguments. It also means you need to know the class of the parent:
connect(parent, &WhateverParentClassIs::send_pi, this, &myWidget::showPi);
You can't use
&QWidget::send_pi
because QWidget doesn't have such signal. -
hmm okay, when I do:
qDebug() << "parent=" << this->parent()->metaObject()->className();
I get "parent= Widget".
Then the line should be:
connect(parent,&Widget::send_pi, this, &myWidget::showPi);
The parent widget should be this one:
widget.h#ifndef WIDGET_H #define WIDGET_H #include <QWidget> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; signals: void send_pi(double); private slots: void on_pushButton_clicked(); }; #endif // WIDGET_H
widget.cpp
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } void Widget::on_pushButton_clicked() { double pi = 3.141; emit send_pi(pi); }
and the missing
myWidget.h#ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> #include <QLabel> class myWidget : public QWidget { Q_OBJECT public: explicit myWidget(QWidget *parent = 0); signals: public slots: void showPi(double x); private: QLabel *pi_label = new QLabel; }; #endif // MYWIDGET_H
There is something else wrong.
-
Then the line should be:
connect(parent,&Widget::send_pi, this, &myWidget::showPi);Yup, except
parent
is a pointer to QWidget in your first code, not toWidget
. If you want to use it here you would need to cast it:connect(qobject_cast<Widget*>(parent),&Widget::send_pi, this, &myWidget::showPi);
but that is a bad idea. You can't guarantee from within the function what parent will be given as a parameter (unless you change it to
Widget*
instead ofQWidget*
).
This connect statement should really be taken out ofmyWidget
to the code that sees both the objects that are being connected and their types, e.g.:Widget foo; myWidget bar; connect(&foo, &Widget::send_pi, &bar, &myWidget::showPi);
Btw. You should really decide on your naming convention. One class is camel-case other one not, one function uses lowercase and underscores and another camel-case. It's gonna be mighty confusing what is what.
-
@Chris-Kawa said in new Signal/Slot syntax with parent QWidget?:
Yup, except parent is a pointer to QWidget in your first code, not to Widget. If you want to use it here you would need to cast it:
connect(qobject_cast<Widget*>(parent),&Widget::send_pi, this, &myWidget::showPi);
Are you sure, Chris? I'm quite convinced any
QObject *
will do. :) -
@kshegunov Pretty sure, but you had me doubting for a second there ;) So I checked and sure enough:
connect(someQObject, &SomeClass::whatever, ...
results in a compile error:
(...) cannot convert argument1 from `QObject *` to `const SomeClass*`
-
Awww, that's upcasting ... :(
Silly me! -
@Chris-Kawa said in new Signal/Slot syntax with parent QWidget?:
This connect statement should really be taken out of
myWidget
to the code that sees both the objectsI have no code that sees both, I will think about that place.
Btw. You should really decide on your naming convention. One class is camel-case other one not, one function uses lowercase and underscores and another camel-case. It's gonna be mighty confusing what is what.
I absolutely agree and I will work on it.
Thank you for the hints. Just one more question. Is the commented out connect line correct in that case? Or is that as well problematic as the new signal/slot syntax?
-
connect(parent,SIGNAL(send_pi(double)), this, SLOT(showPi(double)));
It might work in your particular case but It has exactly the same general problem i.e. if theparent
is not aWidget*
there's no such signal and the connection won't work.
The difference is that this will compile fine and only silently fail at runtime (with a warning on the output), while the new syntax won't let you even compile this, which is much better because it gives you a chance to fix it right away and not after a user of your app reports a bug :)