Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to code 3rd connect paramater ?



  • After some struggle with basics syntax of SIGNAL ? SLOT
    I am ready to pass data between objects, more psecifcally between current - this - object a Form_Widget.
    I have #include correct header but my 3rd "connect" parameter syntax is wrong .
    Unfortunately the "extended debug" text runs out of screen and there is no "bar" to move it so it can be read.
    I just need somebody to show me correct syntax of 3rd - object _ * Form_Widget " parameter.

    Thanks

    // display remote
    connect(this,
    &DeviceDiscoveryDialog::mySignal,
    Form_Widget(),
    &Form_Widget::passDATA);



  • You need to pass a real instance of a class as 3rd parameter. something like:

    Form_Widget* formWidget = new Form_Widget(this);
    formWidget->show();
    connect(this, &DeviceDiscoveryDialog::mySignal, formWidget, &Form_Widget::passDATA);
    


  • @VRonin Thanks , but let ,me show my total ignorance .

    The class I am trying to "connect" is a dialog , called from widget .

    DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent)
    : QDialog(parent), localDevice(new QBluetoothLocalDevice),
    ui(new Ui_DeviceDiscovery)

    Should I be able to access "parent" as a receiver (3rd connect parameter ) ?
    That is where the dialog messages need to be displayed.

    I realize it is kinda backwards , but I like to work with form instead of working with dialog.



  • This post is deleted!


  • @AnneRanch said in How to code 3rd connect paramater ?:

    Unfortunately the "extended debug" text runs out of screen and there is no "bar" to move it so it can be read.

    You could have posted the code that failed to compile and as much of the error message as you could copy-n-paste. We would not have to guess, and you would not have to try to explain as much

    Should I be able to access "parent" as a receiver (3rd connect parameter ) ?

    You could mean one of two things.

    1. You are coding a slot and want it to directly access its parent object

    The code in the slot passDATA() (i.e. fourth parameter) of the object you connected to (i.e. the third parameter), can do anything that is legal C++. That includes access its own (this) object, parent object (if any), its child objects (if any) , or any other thing that it may have access to do through C++ mechanisms.

    However, if the receiver of a signal is only doing something to its parent object then you probably need to reconsider your design and connect the signal to the parent object in the first place.

    1. You are making a connection in the constructor of a QWidget to its own parent QWidget

    While you can use the parent pointer as the target of a connect() call, this will be a base QWidget pointer and you will only be able to access slots defined in a base QWidget. To access a parent that (might be) of a certain QWidget sub-class you would need to cast the parent pointer first:

    Form_Widget* form = qobject_cast<Form_Widget*>(parent);
    if (form) {
      connect(this, &DeviceDiscoveryDialog::mySignal, form, &Form_Widget::passDATA);
    }
    

    I realize it is kinda backwards

    It is very backwards, requires the child dialog to know about it the type of its parent, and unnecessarily complicated as a result. I suspect your Form_Widget constructor code looks like this:

    explicit Form_Widget::Form_Widget(QWidget *parent = nullptr)  
    {
      ...
      m_dialog = new DeviceDiscoveryDialog(this);
      ...
    }
    

    and your DeviceDiscoveryDialog constructor code looks like this (after adopting my snippet above):

    DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent = nullptr)
    {
      ...
      Form_Widget* form = qobject_cast<Form_Widget*>(parent);
      if (form) {
        connect(this, &DeviceDiscoveryDialog::mySignal, form, &Form_Widget::passDATA);
      }
    }
    

    Compare that with the more conventional Qt approach:

    explicit Form_Widget::Form_Widget(QWidget *parent = nullptr)  
    {
      ...
      m_dialog = new DeviceDiscoveryDialog(this);
      connect(m_dialog,  &DeviceDiscoveryDialog::mySignal, this, &Form_Widget::passDATA);
      ...
    }
    

    and

    DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent = nullptr)
    {
      ...
      // nothing at all in here, no awkward casts, no knowledge of any receiver
      ...
    }
    

    Wiring up connections within the UI is often done in the place, and at the time, of creation.

    (All of the code above are illustrative examples that have not been tested)



  • @AnneRanch
    @ChrisW67's explanation is correct. To summarise: you need to do the connect() inside Form_Widget and not inside DeviceDiscoveryDialog. Which means your connect() statement somewhere inside Form_Widget will look like:

    connect(m_dialog,  &DeviceDiscoveryDialog::mySignal, this, &Form_Widget::passDATA);
    

    I realize it is kinda backwards , but I like to work with form instead of working with dialog.

    You need to do it the way round we are saying.



  • This post is deleted!


  • @ChrisW67 said in How to code 3rd connect paramater ?:

    This is exactly what I have been asking about.

    The "parent" is passed to the DeviceDiscoveryDialog and I do not see why it is unconventional to use it. What is the difference between any scheme where parameter is passed ?

    But that is immaterial , because until I find out why , no matter what method I use - "item" is not available in the SLOT.
    Item is derived from plain QString and I have no issue passing QString to SIGNAL and accessing it in my SLOT.

    DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget parent = nullptr)
    {
    ...
    Form_Widget
    form = qobject_cast<Form_Widget*>(parent);
    if (form) {
    connect(this, &DeviceDiscoveryDialog::mySignal, form, &Form_Widget::passDATA);
    }
    }



  • @AnneRanch said in How to code 3rd connect paramater ?:

    The "parent" is passed to the DeviceDiscoveryDialog and I do not see why it is unconventional to use it.

    It is conventional because that is the way it is designed to be used (and also the way all the documented examples are). The receiver is sometimes the parent object of the sender, but that is far from the only way things can be. The convention covers the possibilities.

    The entire point of the signal/slot mechanism is to decouple the sender from any knowledge of the receiver or receivers (Observer Pattern). The sending object does not care about the type of the receiver(s), what object owns them, or even if they are in the same thread.

    In the specific example you have it is clearer, less confusing, and less error prone to do it the conventional way. If you want to make your life, and that of any subsequent code maintainer, harder then that is your decision.

    But that is immaterial , because until I find out why , no matter what method I use - "item" is not available in the SLOT.
    Item is derived from plain QString and I have no issue passing QString to SIGNAL and accessing it in my SLOT.

    Which is it? "Item" is not available inside the slot function, or "item" is available inside your slot function. It cannot be both.

    Here is a cut down version of your entire project. I can assure you that either connect location, and slots with or without arguments work:
    main.cpp

    #include "widget.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Form_Widget w;
        w.show();
        return a.exec();
    }
    

    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include "devicediscoverydialog.h"
    
    #include <QLineEdit>
    #include <QCheckBox>
    #include <QWidget>
    
    class Form_Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Form_Widget(QWidget *parent = nullptr);
        ~Form_Widget();
    
    public slots:
        void passDATA1(const QString& item);
        void passDATA2();
    
    private:
        QLineEdit *m_edit;
        QCheckBox *m_check;
        DeviceDiscoveryDialog* m_dialog;
    };
    #endif // WIDGET_H
    

    widget.cpp

    #include "widget.h"
    
    #include <QVBoxLayout>
    #include <QDebug>
    
    Form_Widget::Form_Widget(QWidget *parent)
        : QWidget(parent)
    {
        // Very basic form
        QVBoxLayout *layout = new QVBoxLayout(this);
        m_edit = new QLineEdit(this);
        m_check = new QCheckBox("Toggles when slot called", this);
        layout->addWidget(m_edit);
        layout->addWidget(m_check);
    
        // Create our child dialog
        m_dialog = new DeviceDiscoveryDialog(this);
        m_dialog->show(); // non-modal dialog
    
    #if 1
        // The conventional connect to two different slots
        // This slot takes an argument
        connect(m_dialog, &DeviceDiscoveryDialog::mySignal, this, &Form_Widget::passDATA1);
        // This slot does not expect an argument, there is no difference in the connect() call
        connect(m_dialog, &DeviceDiscoveryDialog::mySignal, this, &Form_Widget::passDATA2);
    #endif
    }
    
    Form_Widget::~Form_Widget()
    {
    }
    
    void Form_Widget::passDATA1(const QString &item)
    {
        qDebug() << Q_FUNC_INFO << "Called with item == " << item;
        m_edit->setText( QStringLiteral("Called with item == %1").arg(item) );
    }
    
    void Form_Widget::passDATA2()
    {
        qDebug() << Q_FUNC_INFO << "Called";
        m_check->toggle();
    }
    

    devicediscoverydialog.h

    #ifndef DEVICEDISCOVERYDIALOG_H
    #define DEVICEDISCOVERYDIALOG_H
    
    #include <QDialog>
    
    class DeviceDiscoveryDialog : public QDialog
    {
        Q_OBJECT
    public:
        explicit DeviceDiscoveryDialog(QWidget *parent = nullptr);
    
    public slots:
        void doStuff();
    
    signals:
        void mySignal(const QString &item);
    
    private:
        int m_tick;
    };
    
    #endif // DEVICEDISCOVERYDIALOG_H
    

    devicediscoverydialog.cpp

    #include "devicediscoverydialog.h"
    #include "widget.h"
    
    #include <QPushButton>
    #include <QVBoxLayout>
    
    DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent)
        : QDialog(parent)
        , m_tick(0)
    {
        // Very basic dialog
        QVBoxLayout *layout = new QVBoxLayout(this);
        QPushButton *button = new QPushButton("Push Me", this);
        layout->addWidget(button);
    
        // Make the button do something local
        connect(button, &QPushButton::clicked, this, &DeviceDiscoveryDialog::doStuff);
    
    #if 0
        // The complicated connect to two different slots
        Form_Widget* form = qobject_cast<Form_Widget*>(parent);
        if (form) {
            connect(this, &DeviceDiscoveryDialog::mySignal, form, &Form_Widget::passDATA1);
            connect(this, &DeviceDiscoveryDialog::mySignal, form, &Form_Widget::passDATA2);
        }
    #endif
    }
    
    void DeviceDiscoveryDialog::doStuff()
    {
        // Do stuff
        ++m_tick;
    
        // Tell anyone listening
        emit mySignal(QString::number(m_tick));
    }
    

    test.pro

    QT       += core gui
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    CONFIG += c++11
    DEFINES += QT_DEPRECATED_WARNINGS
    SOURCES += \
        devicediscoverydialog.cpp \
        main.cpp \
        widget.cpp
    HEADERS += \
        devicediscoverydialog.h \
        widget.h
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    
    


  • This post is deleted!


  • @AnneRanch said in How to code 3rd connect paramater ?:

    That is not how my SIGNAL is defined.

    It would really help your case if you stop telling us what your code is not, and started showing us what your code is.

    This bit of your slot code:

    QString label = QString("%1 %2").arg(info.address().toString()).arg(info.name());
    ...
    emit passLABEL(label);     // used by "parent" 
    

    is you sending a signal that has exactly the type of signature in my example, i.e. the signal sends a QString and any connected slot expecting a QString gets one.

    This pair of old-style connects:

     connect(this,
                    SIGNAL(mySignal(item)) QListWidgetItem,
                    this ,
                    SLOT(testSlot()));
            connect(this,
                    SIGNAL(pass_item()),
                    this ,
                    SLOT(testSlot_PASS_DATA() ));
    

    may compile (I expect not) but will fail at run time with a message to the debug console to the effect that the connection cannot be made. Old-style connections require the signal or slot name and the type of the arguments... not the name of the function parameter or variables involved.

    These (debugging?) connections should look more like:

    connect(
      this,  SIGNAL(mySignal(QListWidgetItem*)),   
      this , SLOT(testSlot(QListWidgetItem*)) 
    );
    

    but your actual mySignal() signature is still unknown to us. I have guessed it is like this:

    signals:
      void mySignal(QListWidgetItem*);
    

    Then, when your code does this somewhere:

    emit mySignal(some_list_widget_item_pointer);
    

    the receiver, testSlot(), is called with the value of some_list_widget_item_pointer. Note that the connect() does not send anything, it is merely plumbing, and the signal call does the sending.

    My examples, and recommended method in new code, are new style connections. The type of connect() does not change the signature of the receiving slot or how a signal is emitted.



  • Just FYI
    The following code is used in other parts of the MDI example
    to actually access the parent. Works slick without breaking the logic flow the code. Which to me is one of the "learning curve" using "connect".

    Form_Widget* form = qobject_cast<Form_Widget*>(parent);


Log in to reply