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?


  • Moderators

    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.


  • Moderators

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

    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 of QWidget*).
    This connect statement should really be taken out of myWidget 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.


  • Qt Champions 2016

    @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. :)


  • Moderators

    @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*`
    

  • Qt Champions 2016

    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 objects

    I 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?


  • Moderators

    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 the parent is not a Widget* 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 :)



  • thanks for the enlightening!



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.