您的位置:首页 > 健康 > 美食 > 个人介绍网页设计报告_接外包活去什么平台_网络游戏推广员是做什么的_seo推广软件哪个好

个人介绍网页设计报告_接外包活去什么平台_网络游戏推广员是做什么的_seo推广软件哪个好

2024/12/26 21:44:27 来源:https://blog.csdn.net/Xiaomo1536/article/details/144718250  浏览:    关键词:个人介绍网页设计报告_接外包活去什么平台_网络游戏推广员是做什么的_seo推广软件哪个好
个人介绍网页设计报告_接外包活去什么平台_网络游戏推广员是做什么的_seo推广软件哪个好

嵌入式学习-QT-Day03

三、信号槽

1、概念

2、函数原型

3、实现

3.1 自带信号→自带槽

3.2 自带信号→自定义槽

3.3 自定义信号

4、信号槽传参

5、对应关系

5.1 一对多

5.2 多对一

三、信号槽

1、概念

信号和槽是两种函数,这是Qt在C++的基础上新增的特性,类似于其他技术中的回调的概念。

信号槽通过程序员提前设定的“约定”,可以实现对象之间的通信,有两个先决条件:

  • 通信的对象必须是从QObject类中派生出来的。
  • 类中要有Q_OBJECT宏。

2、函数原型

信号槽需要在使用前进行“约定”,这个“约定”也被称为连接,使用下面的函数实现:

【例子】:如果静宜考试考了100分,那么方宇请客吃日料。

// 参数1:发射者。【静宜】
// 参数2:信号函数,通常是一个动词函数表示(考试考100),使用SIGNAL()包裹
// 参数3:接收者。【方宇】
// 参数4:槽函数,通常是一个动词函数表示(请吃日料),使用SLOT()包裹
QMetaObject::Connection QObject::connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method)[static]

第五个参数(了解)

QMetaObject::Connection QObject:: connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection)
第五个参数type就是用来指定连接的类型。它可以是以下几种枚举值之一:Qt::AutoConnectionQt将自动选择连接类型。如果信号和槽在同一线程中,那么使用Qt::DirectConnection,否则使用Qt::QueuedConnectionQt::DirectConnection:直接连接。当信号发出时,槽函数会立即在发射信号的线程上被调用。这意味着如果信号和槽位于不同线程,那么可能会出现线程安全问题。Qt::QueuedConnection:队列连接。当信号发出时,Qt会将事件放入接收对象的事件队列中,然后等待目标对象所在的线程处理该事件。因此,槽函数的执行将延迟到接收对象所在的线程中执行,这通常用于跨线程连接。Qt::BlockingQueuedConnection:阻塞队列连接。与Qt::QueuedConnection类似,但是发送者将被阻塞,直到接收者处理完槽函数为止。Qt::UniqueConnection:确保每个连接只建立一次,避免重复连接。

3、实现

为了学习,把信号槽分为三种实现的方式。

  • 自带信号→自带槽
  • 自带信号→自定义槽
  • 自定义信号

3.1 自带信号→自带槽

这种连接方式是最简单的,因为信号函数和槽函数都是Qt内置的,只需要在文档中查询到对应的函数后,使用connect函数连接即可。

【例子】点击按钮,关闭窗口。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    QPushButton *btn;
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口宽高
    resize(500,500);    btn = new QPushButton("关闭",this);
    // 设置按钮的位置
    btn->move(200,250);    // 连接信号槽【点击按钮,关闭窗口】
    // 参数1:按钮对象
    // 参数2:点击信号函数clicked
    // 参数3:窗口对象
    // 参数4:槽函数
    connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}Dialog::~Dialog()
{
    delete btn;
}

3.2 自带信号→自定义槽

Qt不可能内置所有执行的动作代码,特别是一些复杂的动作,需要开发者手动编写槽函数,这种方式也是所有连接方式中使用的最多的。

槽函数实际上也是一个特殊的成员函数,在声明的时候权限的作用是修饰其作为普通成员函数使用的效果,不影响信号槽的连接效果。

【例子】点击按钮,向右和向下移动窗口10个像素。同时输出当前窗口的坐标。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    QPushButton *btn;private slots:      // 最小权限法则:能用私有就用私有权限,其次用保护,最后是公有
    void mySlot();  // 槽函数,小驼峰:第一个单词首字母小写,其他单词首字母大写
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口宽高
    resize(500,500);    btn = new QPushButton("移动",this);
    // 设置按钮的位置
    btn->move(200,250);    // 连接槽函数
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}// 槽函数类外定义
void Dialog::mySlot()
{
    // 获取当前的坐标
    int x1 = this->x();
    int y1 = this->y();    // 移动坐标位置
    move(x1+10,y1+10);    // 输出当前坐标
    qDebug() << x1+10 << y1+10;
}Dialog::~Dialog()
{
    delete btn;
}

3.3 自定义信号

为了讲解,强行使用自定义信号,并非问题的最优解,主要学习写法。

信号函数是一种非常特殊的函数,因为其只有声明,没有定义,即没有函数体,因此无法调用,只能使用emit关键字发射。

【例子】点击按钮,关闭窗口。

3.1 节的信号连接方式。

本节强行在中间加一层自定义信号的转发过程。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    QPushButton *btn;private slots:      // 最小权限法则:能用私有就用私有权限,其次用保护,最后是公有
    void mySlot();  // 槽函数,小驼峰:第一个单词首字母小写,其他单词首字母大写    // 自定义信号
signals:
    void mySignal();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口宽高
    resize(500,500);    btn = new QPushButton("杀鸡用牛刀",this);
    // 设置按钮的位置
    btn->move(200,250);    // 连接槽函数
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    // 第二个信号槽连接
    connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}// 槽函数类外定义
void Dialog::mySlot()
{
    // 发射自定义信号
    emit mySignal();
}Dialog::~Dialog()
{
    delete btn;
}

4、信号槽传参

【例子】点击按钮,按钮上显示点击的次数。

正确解法:

QPushButton的文字属性为text : QString ,QString可以使用setter函数更改按钮内容。

void	setText(const QString & text)

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    QPushButton *btn;private slots:      // 最小权限法则:能用私有就用私有权限,其次用保护,最后是公有
    void mySlot();  // 槽函数,小驼峰:第一个单词首字母小写,其他单词首字母大写};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口宽高
    resize(500,500);    btn = new QPushButton("0",this);
    // 设置按钮的位置
    btn->move(200,250);    // 连接槽函数
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}// 槽函数类外定义
void Dialog::mySlot()
{
    // 静态局部变量
    static int count = 0;
    count++;    // 类型转换int -> QString
    QString text = QString::number(count);    // 更改按钮文字
    btn->setText(text);}Dialog::~Dialog()
{
    delete btn;
}

把上面的案例强行改为信号槽传参。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    QPushButton *btn;private slots:      // 最小权限法则:能用私有就用私有权限,其次用保护,最后是公有
    void mySlot();  // 槽函数,小驼峰:第一个单词首字母小写,其他单词首字母大写
    void mySlot2(int);  // 声明带参数的槽函数signals:
    void mySignal(int); // 带参数的信号函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    // 设置窗口宽高
    resize(500,500);    btn = new QPushButton("0",this);
    // 设置按钮的位置
    btn->move(200,250);    // 连接槽函数
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));    connect(this,SIGNAL(mySignal(int)),
            this,SLOT(mySlot2(int)));
}// 槽函数类外定义
void Dialog::mySlot()
{
    // 静态局部变量
    static int count = 0;
    count++;    // 发射带参数的信号
    emit mySignal(count);
}// 带参数槽函数定义
void Dialog::mySlot2(int count)
{
    // 类型转换int -> QString
    QString text = QString::number(count);
    // 更改按钮文字
    btn->setText(text);
}Dialog::~Dialog()
{
    delete btn;
}

需要注意的是:

  • 理论上可以传递任意多个参数。建议最多写两个参数,多了会很冗余。如果非得传递多个参数,可以定义成一个类,传递对象。
  • 信号的参数个数必须大于等于槽的参数个数。
  • 信号的参数类型要与槽的参数类型匹配。

传递类对象的代码如下:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Demo
{
public:
    int a = 10;
    int b = 20;
    double c = 3.23;
    float d = 1.1;
};class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();private:
    QPushButton *btn;private slots:
    void mySlot();  // 自定义槽函数
    void mySlot2(const Demo &); // 与mySignal(int)连接的自定义槽函数signals:
    void mySignal(const Demo &); // 带参数的信号函数
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500,500);
    btn = new QPushButton("0",this);
    btn->move(150,150);    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    connect(this,SIGNAL(mySignal(const Demo &)),this,SLOT(mySlot2(const Demo &)));
}void Dialog::mySlot()
{
    Demo demo;
    // 发射带参数的自定义信号函数
    emit mySignal(demo);
}void Dialog::mySlot2(const Demo &demo)
{
    qDebug() << demo.a;
    qDebug() << demo.b;
    qDebug() << demo.c;
    qDebug() << demo.d;
}Dialog::~Dialog()
{
    delete btn;
}

5、对应关系

5.1 一对多

一对多指的是一个信号可以连接多个槽函数。

对于一对多的连接,可以合并为一对一,因为槽函数也是一个成员函数,可以整合到一个槽函数中进行连接。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();private:
    QPushButton *btn;
    QPushButton *btn2;private slots:
    void mySlot1();
    void mySlot2();
    void mySlot3();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500,500);    btn = new QPushButton("一对多",this);
    btn->move(200,200);    btn2 = new QPushButton("一对一",this);
    btn2->move(200,250);    // 一对多
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot1()));
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot2()));    // 一对多这种连接方式的优势是可以灵活处理每个对应关系
    // 例如可以断开某个信号槽的连接
    // 断开连接的函数与连接函数一样,只需要在函数名称前面加一个dis
    disconnect(btn,SIGNAL(clicked()),this,SLOT(mySlot1()));    // 一对一
    connect(btn2,SIGNAL(clicked()),this,SLOT(mySlot3()));
}Dialog::~Dialog()
{
    delete btn;
}void Dialog::mySlot1()
{
    qDebug() << "A";
}void Dialog::mySlot2()
{
    qDebug() << "B";
}void Dialog::mySlot3()
{
    mySlot1();
    mySlot2();
}

5.2 多对一

多对一指的是多个信号连接同一个槽函数,多对一的问题在于槽函数无法直接判断那个信号出发的槽函数调用,但是可以通过sender函数在槽函数中获得发射者对象,通过对象的比对判断来源。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QPushButton>
#include <QDebug>class Dialog : public QDialog
{
    Q_OBJECTpublic:
    Dialog(QWidget *parent = 0);
    ~Dialog();private:
    QPushButton *btn1;
    QPushButton *btn2;private slots:
    void btnClickedSlot();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(500,500);
    btn1 = new QPushButton("多对一A",this);
    btn1->move(200,200);    btn2 = new QPushButton("多对一B",this);
    btn2->move(200,250);    // 多对一
    connect(btn1,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));    connect(btn2,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}Dialog::~Dialog()
{
    delete btn1;
    delete btn2;
}void Dialog::btnClickedSlot()
{
    // 通过sender函数可以获得发射者对象
    if(sender() == btn1)
    {
        qDebug() << "A";
    }
    else if(sender() == btn2)
    {
        qDebug() << "B";
    }
    else
    {
        qDebug() << "对象错误";
    }
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com