Elemental signal and slot example



  • Hi there. I'm trying to understand the signal and slot mechanism; but I'm afraid that I have no idea of what I'm doing.

    I have set up a simple example, that doesn't work, and ends in a "the slot requires more arguments than the signal provide" error. The theoretical behavior is really simple, there is a login screen with a user and password text, and when you click the button, the widget signal those two strings to a controller, and the controller do something with it. In this case, it just show them in the stdout.

    Here is all the code I have so far:

    controller.h

    #ifndef CONTROLLER_H
    #define CONTROLLER_H
    
    #include <QObject>
    #include <QString>
    
    class Controller : public QObject
    {
        Q_OBJECT
    public:
        explicit Controller(QObject *parent = 0);
    
    signals:
    
    public slots:
        void doSomething(QString user, QString pass);
    
    };
    
    #endif // CONTROLLER_H
    

    loginScreen.h

    #ifndef LOGINSCREEN_H
    #define LOGINSCREEN_H
    
    #include <QDialog>
    
    #include "controller.h"
    
    namespace Ui {
    class LoginScreen;
    }
    
    class LoginScreen : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit LoginScreen(QWidget *parent = 0);
        ~LoginScreen();
    
    signals:
        void on_pushButton_clicked();
    
    private:
        Ui::LoginScreen *ui;
    };
    
    #endif // LOGINSCREEN_H
    

    controller.cpp

    #include "controller.h"
    
    #include <iostream>
    #include <QTextStream>
    
    Controller::Controller(QObject *parent) : QObject(parent)
    {
    
    }
    
    void Controller::doSomething(QString user, QString pass){
    
        QTextStream(stdout) << "Doing something..."<<user<<" "<<pass<< endl;
    
    }
    

    loginscreen.cpp

    #include "loginscreen.h"
    #include "ui_loginscreen.h"
    
    LoginScreen::LoginScreen(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::LoginScreen)
    {
        ui->setupUi(this);
    
    }
    
    
    LoginScreen::~LoginScreen()
    {
        delete ui;
    }
    
    void LoginScreen::on_pushButton_clicked()
    {
        emit (this->ui->userLine->text(),this->ui->passwordLine->text());
    }
    
    

    main.cpp

    
    #include "loginscreen.h"
    #include "controller.h"
    
    #include <QApplication>
    #include <QObject>
    
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        Controller mainControl;
    
        LoginScreen w;
    
    
        QObject::connect(&w, &LoginScreen::on_pushButton_clicked,
                         &mainControl, &Controller::doSomething);
    
        w.show();
    
    
    
        return a.exec();
    }
    
    

    And finally, the loginscreen.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>LoginScreen</class>
     <widget class="QDialog" name="LoginScreen">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>214</width>
        <height>146</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>Dialog</string>
      </property>
      <widget class="QLabel" name="statusLabel">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>10</y>
         <width>47</width>
         <height>13</height>
        </rect>
       </property>
       <property name="text">
        <string>Ready...</string>
       </property>
      </widget>
      <widget class="QLabel" name="userLabel">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>40</y>
         <width>47</width>
         <height>13</height>
        </rect>
       </property>
       <property name="text">
        <string>User</string>
       </property>
      </widget>
      <widget class="QLabel" name="passwordLabel">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>70</y>
         <width>47</width>
         <height>13</height>
        </rect>
       </property>
       <property name="text">
        <string>Password</string>
       </property>
      </widget>
      <widget class="QLineEdit" name="userLine">
       <property name="geometry">
        <rect>
         <x>70</x>
         <y>40</y>
         <width>113</width>
         <height>20</height>
        </rect>
       </property>
      </widget>
      <widget class="QLineEdit" name="passwordLine">
       <property name="geometry">
        <rect>
         <x>70</x>
         <y>70</y>
         <width>113</width>
         <height>20</height>
        </rect>
       </property>
      </widget>
      <widget class="QPushButton" name="pushButton">
       <property name="geometry">
        <rect>
         <x>70</x>
         <y>110</y>
         <width>75</width>
         <height>23</height>
        </rect>
       </property>
       <property name="text">
        <string>Login</string>
       </property>
      </widget>
     </widget>
     <resources/>
     <connections/>
    </ui>
    

    So the question would be, what would be the correct "connect" function? I have read, watch and follow different tutorials and documentations and I'm still really confuse on how are those two arguments suppose to pass from one place to the other.


  • Qt Champions 2016

    hi and welcome
    The reason the connect dont like you is because
    doSomething has parameters and
    on_pushButton_clicked dont.

    You just just need to define a new signal in LoginScreen ( like the slot)
    public signals:
    void doSomething(QString user, QString pass);

    then in on_pushButton_clicked(); ( which is called when u click button)
    u emit this signal
    emit doSomething (this->ui->userLine->text(),this->ui->passwordLine->text());

    and from outside u have connect the 2 "doSomething "

    so in short, the button clicked is hooked to local slot.
    The local slot will then emit your signal with parameters.
    From outside, this signal is connected to a slot with same signature. ( same params)

    Hope I explained it good enough.



  • TEMP_EDIT: How do I mark the post as solved??

    Thank you! ; it took me a little bit but I got it. I'm leaving here the final code in case someone need it:

    controller.h stays the same.
    controller.cpp stays the same.

    #ifndef LOGINSCREEN_H
    #define LOGINSCREEN_H
    
    #include <QDialog>
    
    #include "controller.h"
    
    namespace Ui {
    class LoginScreen;
    }
    
    class LoginScreen : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit LoginScreen(QWidget *parent = 0);
        ~LoginScreen();
    
    signals:
        void doSomething(QString user, QString pass);
    
    public slots:
        void on_pushButton_clicked();
    
    private:
        Ui::LoginScreen *ui;
    };
    
    #endif // LOGINSCREEN_H
    
    

    loginScreen.cpp

    #include "loginscreen.h"
    #include "ui_loginscreen.h"
    
    LoginScreen::LoginScreen(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::LoginScreen)
    {
        ui->setupUi(this);
    
    }
    
    
    LoginScreen::~LoginScreen()
    {
        delete ui;
    }
    
    void LoginScreen::on_pushButton_clicked()
    {
        emit doSomething(this->ui->userLine->text(),this->ui->passwordLine->text());
    }
    

    main.cpp

    #include "loginscreen.h"
    #include "controller.h"
    
    #include <QApplication>
    #include <QObject>
    
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        Controller mainControl;
    
        LoginScreen w;
    
        QObject::connect(&w, &LoginScreen::doSomething,
                         &mainControl, &Controller::doSomething);
    
        w.show();
    
    
    
        return a.exec();
    }
    
    

Log in to reply
 

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