The concept and use of signal slots in QT

The concept of signal slots

Signal functions and slot functions are new features of Qt based on C++, similar to callback mechanisms in other languages

The use of signal slots is simpler, and communication between different component objects can be easily realized

It can be understood that the signal slot mechanism is: "If the A object..., then the B object..."

Two prerequisites for using signal slots:

  1. The communication object must be derived from QObject
  2. The beginning of the class must have the Q_OBJECT macro

function prototype

The connection of the signal slot is mainly realized through a static member function in the QObject class:

Most of the parameters with their own default values ​​​​can be ignored
The fifth parameter here is not considered, which refers to a connection method - automatic connection

QObject::connect(const QObject * sender, 
				 const char * signal, 
				 const QObject * receiver, 
				 const char * method) [static]

Parameter 1: Emitter object - the object representing the cause
Parameter 2: Signal function, when the cause is triggered, the emitter emits a signal function, which requires SIGNAL() package
Parameter 3: Receiver object - represents the object that caused the result
Parameter 4: slot function, the specific function function executed by the receiver, that is, the result triggers the function call, which needs to be wrapped by SLOT()

In fact, the slot function is a special member function

Three ways of signal slot connection

In order to facilitate the step-by-step explanation, the signal-slot connection is divided into three ways from simple to complex

Self-contained signal → self-contained slot
Self-contained signal → custom slot
custom-signal → slot

method one

Self-contained signal → self-contained slot
This method does not require programmers to manually write any function definitions, just find the corresponding function connection in the API document

[Example] Click the button to close the window

Parameter 1: Emitter, often a noun - button object
 Parameter 2: Signal function, often a past tense verb - clicked function
 Parameter 3: Receiver, often a noun - window object
 Parameter 4: Slot function, often a verb - close function

code show as below:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
// button header file
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
	// declared in the header file
    QPushButton *btn;
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
	// Resize the window in the constructor
    resize(300, 300);
    // Define the button in the constructor
    btn = new QPushButton("closure", this);
    // Set button position and width and height (x,y,w,h)
    btn->setGeometry(50, 50, 100, 50);
    // signal slot connection
    // QObject::connect(btn, SIGNAL(clicked()), this, SLOT(close()));
    // The base class function is called in the derived class, and the scope qualifier can be omitted if there is an inheritance relationship
    //overriding signal-slot connections
    connect(btn, SIGNAL(clicked()), this, SLOT(close()));
}

Dialog::~Dialog()
{
    delete btn;
}

main.cpp

#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    // show() is also a slot function, so the slot function is a special member function
    w.show(); 

    return a.exec();
}

way two

Self-contained signal → custom slot

the most used method

[Example] Click the button to move the window to the lower right corner by 10√2 pixels, and output debugging information at the same time

Parameter 1: button object
 Parameter 2: clicked function
 Parameter 3: window object
 Parameter 4: custom slot function `mySlot`

code show as below:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;

// 1. Declare slot function (law of least privilege)
private slots:
    // Scientific name: CamelCase
    // The first word is all lowercase, and the first letter of each subsequent word is capitalized
    void mySlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(200, 200);
    btn = new QPushButton("customize", this);
    btn->move(50, 50);
    // 3. Connect the signal slot
    connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));

}

// 2. Define the slot function
void Dialog::mySlot()
{
    // First get the coordinates of the current window
    int x = this->x();
    int y = this->y();
    // moving window
    move(x+10, y+10);
    // Output the position coordinates after the move
    qDebug() << this->x() << "," << this->y();
}

Dialog::~Dialog()
{
	delete btn;
}

main.cpp

#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();

    return a.exec();
}

Running results after three clicks

Starting E:\QT\Tools\QtCreator\bin\build-qtday1_4-Desktop_Qt_5_2_1_MinGW_32bit-Debug\debug\qtday1_4.exe...
862 , 399 
872 , 409 
882 , 419 
892 , 429 
E:\QT\Tools\QtCreator\bin\build-qtday1_4-Desktop_Qt_5_2_1_MinGW_32bit-Debug\debug\qtday1_4.exe exited with code 0

way three

custom-signal → slot

Only in a few cases, you need to use custom signals, the following example is forced to use custom signals to complete

[Example] Click the button to close the window

Parameter 1: button object
 Parameter 2: clicked function
 Parameter 3: window object
 Parameter 4: custom slot function `mySlot`

code show as below:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;

// 1. Declare slot function (law of least privilege)
private slots:
    // Scientific name: CamelCase
    // The first word is all lowercase, and the first letter of each subsequent word is capitalized
    void mySlot();

// 3. The signal function has no permission
signals:
    void mySignal();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(200, 200);
    btn = new QPushButton("chicken butcher knife", this);
    btn->move(50, 50);
    // 3. Connect the signal slot
    connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));

    // 5. Connect custom signal
    connect(this, SIGNAL(mySignal()), this, SLOT(close()));
}

// 2. Define the slot function
void Dialog::mySlot()
{
    qDebug() << "emit a custom signal";
    // 4. Emit a custom signal function, the signal function has no call, no function body
    emit mySignal();
}

Dialog::~Dialog()
{
    delete btn;
    qDebug() << "window is closed";
}

main.cpp

#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();

    return a.exec();
}

operation result

Starting E:\QT\Tools\QtCreator\bin\build-qtday1_4-Desktop_Qt_5_2_1_MinGW_32bit-Debug\debug\qtday1_4.exe...
emit a custom signal 
window is closed 
E:\QT\Tools\QtCreator\bin\build-qtday1_4-Desktop_Qt_5_2_1_MinGW_32bit-Debug\debug\qtday1_4.exe exited with code 0

Parameter passing

Programming Prerequisites

QPushButton of text :
QString The attribute represents the displayed text, and the corresponding getter with setter for:
getter: QString	text() const
setter: void	setText(const QString & text)
setter The function is not a slot function, so a custom slot function is required, which is called in the custom slot function text attribute setter function to change its value

global parameters

Parameter passing in a class can be through member variables or static local variables, etc.
[Example] Click the button, the number of clicks of the current button is displayed on the button

Ideas:

Member variable code example: Recommended

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;
    // count member variable
    int count;// (1) You can assign the initial value int count = 0 here;

// 1. Declare slot function (law of least privilege)
private slots:
    void mySlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0)// (2) Construct initialization list
{
    // (3) Assign count = 0 in the constructor;
    resize(200, 200);
    btn = new QPushButton("0", this);
    btn->move(50, 50);
    // 3. Connect the signal slot
    connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));
}

// 2. Define the slot function
void Dialog::mySlot()
{
    // add
    count++;
    // int integer → QString string
    QString text = QString::number(count);
    btn->setText(text);
}

Dialog::~Dialog()
{
    delete btn;
}

Static local variable code example: not recommended

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;

// 1. Declare slot function (law of least privilege)
private slots:
    void mySlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(200, 200);
    btn = new QPushButton("0", this);
    btn->move(50, 50);
    // 3. Connect the signal slot
    connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));
}

// 2. Define the slot function
void Dialog::mySlot()
{
    static int count = 0;
    // add
    count++;
    // int integer → QString string
    QString text = QString::number(count);
    btn->setText(text);
}

Dialog::~Dialog()
{
    delete btn;
}

Static local variables are not as easy to use as member variables
If there are multiple Dialog object windows, multiple windows use a static local variable, click one and all will change accordingly
Unless you want to make such effects, it is recommended to use member variables
In addition, the life cycle of static member variables is longer, and the use of member variables is more lightweight

operation result

signal slot parameter

Signal slot parameter passing is mainly used in the later stage when it is inconvenient to directly use variables to pass parameters. This is only for explanation and demonstration, not the optimal solution

[Example] Click the button, the number of clicks of the current button is displayed on the button

Idea: Different from the idea used by global variables, it is recommended to go back and compare the differences

code show as below:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn;

private slots:
    // Custom slot function 1
    void mySlot();

    // Slot function 2 connected with void valueSignal(int)
    void valueSlot(int);

signals:
    // Signal functions that can take parameters
    // The signal function does not need to be defined, does not need to be called, and can be emitted directly
    void valueSignal(int);
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(300, 300);
    btn = new QPushButton("0", this);
    btn->move(100, 100);

    connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));

    connect(this, SIGNAL(valueSignal(int)), this, SLOT(valueSlot(int)));
}

void Dialog::mySlot()
{
    // Count using static local variables
    static int count = 0;

    //  Send a custom signal
    emit valueSignal(++count);
}

// Dummy arguments cannot be used here, and the parameter name must be written, otherwise the parameter value cannot be obtained
void Dialog::valueSlot(int count)
{
    // Get the passed parameters and set the display
    QString text = QString::number(count);
    btn->setText(text);
}

Dialog::~Dialog()
{
    delete btn;
}

The result of the operation is the same as above

Compared with global parameters, the efficiency is lower. If you can use parameter passing, do not use signal slots to pass parameters.
Signal slot passing parameters is a method for use when parameter passing is inconvenient
Signal slot transfer parameters are set for more complex long-distance communication

Long distance is not the actual distance, but there is no direct relationship between two objects in programming
If two objects in a class are within reach between them, it is not called long-distance

Notice:

  1. In theory, any number of parameters can be passed, but in practice 1-2 are mostly.
  2. The number of parameters of the signal function must be greater than or equal to the number of parameters of the slot function.
  3. Parameter types must match one by one

Correspondence between signal slots

There is a one-to-many and many-to-one relationship between signal slots
One-to-many refers to a signal that can connect to multiple slot functions
Many-to-one means that multiple signals can be connected to the same slot function

One-to-many situations can be optimized to one-to-one

[Example] One-to-many and optimized into a simplified version of one-to-one

Code example:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton* btn1;
    QPushButton* btn2;

private slots:
    // two slot functions
    void mySlot1();
    void mySlot2();

    // Slot function connected with btn2
    void mySlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(200, 200);
    btn1 = new QPushButton("one-to-many", this);
    btn2 = new QPushButton("Simplified version", this);
    btn1->move(100, 50);
    btn2->move(100, 100);

    // one-to-many
    connect(btn1, SIGNAL(clicked()), this, SLOT(mySlot1()));
    connect(btn1, SIGNAL(clicked()), this, SLOT(mySlot2()));

    // All one-to-many can be reduced to one-to-one signals and slots
    connect(btn2, SIGNAL(clicked()), this, SLOT(mySlot()));
}

void Dialog::mySlot1()
{
    qDebug() << "1";
}

void Dialog::mySlot2()
{
    qDebug() << "2";
}

void Dialog::mySlot()
{
    // A slot function is a special kind of member function
    // can be called directly
    mySlot1();
    mySlot2();
}

Dialog::~Dialog()
{
    delete btn1;
    delete btn2;
}

operation result

Starting E:\QT\Tools\QtCreator\bin\build-qtday2_onetomuti-Desktop_Qt_5_2_1_MinGW_32bit-Debug\debug\qtday2_onetomuti.exe...
1 
2 
1 
2 
E:\QT\Tools\QtCreator\bin\build-qtday2_onetomuti-Desktop_Qt_5_2_1_MinGW_32bit-Debug\debug\qtday2_onetomuti.exe exited with code 0

Both Button one-to-many and Button simplified version can implement signal slots

[Example] many to one

Code example:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QDebug>
#include <QWidget>
#include <QPushButton>

#define QPushButton_STYTLE (QString("\
/*button normal state*/\
QPushButton\
{\
    font-family:Microsoft Yahei;\
    /*Font size is 20 points*/\
    font-size:10pt;\
    /*font color is white*/\
    color:white;\
    /*background color*/\
    background-color:rgb(0 , 0 , 0);\
    /*Border corner radius is 8 pixels*/\
    border-radius:20px;\
}\
/*button hover state*/\
QPushButton:hover\
{\
    /*background color*/\
    background-color:rgb(0 , 0 , 0);\
}\
/*button pressed state*/\
QPushButton:pressed\
{\
    color:black;\
    /*background color*/\
    background-color:rgb(255 , 255 , 255);\
    /*The left padding is 3 pixels, so that the word moves 3 pixels to the right when pressed*/\
    padding-left:3px;\
    /*The upper padding is 3 pixels, so that the word moves down by 3 pixels when pressed*/\
    padding-top:3px;\
}"))

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
private:
    QPushButton *btn;
    QPushButton *btn1;
    QPushButton *btn2;
    QPushButton *btn3;
    int count;
private slots:
    void mySlot();
};

#endif // DIALOG_H

dialog.h

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent),count(0)
{
    resize(640,480);
    btn=new QPushButton(NULL,this);
    btn->resize(640,480);
    btn1=new QPushButton("click",this);
    btn1->setStyleSheet(QPushButton_STYTLE);
    btn1->move(280,240);
    btn1->resize(100,50);
    btn2=new QPushButton("click",this);
    btn2->setStyleSheet(QPushButton_STYTLE);
    btn2->move(280,180);
    btn2->resize(100,50);
    btn3=new QPushButton("click",this);
    btn3->setStyleSheet(QPushButton_STYTLE);
    btn3->move(280,300);
    btn3->resize(100,50);
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(btn2,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(btn3,SIGNAL(clicked()),this,SLOT(mySlot()));
}

void Dialog::mySlot(){
    count++;
    qDebug()<<count;
    QString test=QString::number(count);
    btn1->setText(test);
    btn2->setText(test);
    btn3->setText(test);
}

Dialog::~Dialog()
{
    delete btn;
    delete btn1;
    delete btn2;
    delete btn3;
}

operation result

Starting E:\QT\Tools\QtCreator\bin\build-qtday2_onetomuti-Desktop_Qt_5_2_1_MinGW_32bit-Debug\debug\qtday2_onetomuti.exe...
1 
2 
3 
4 
E:\QT\Tools\QtCreator\bin\build-qtday2_onetomuti-Desktop_Qt_5_2_1_MinGW_32bit-Debug\debug\qtday2_onetomuti.exe exited with code 0


Summarize

there will be a period later

Tags: C++ Qt programming language

Posted by billf2007 on Sun, 25 Dec 2022 02:29:01 +0530