Qt——信号和槽

一.信号和槽概述

谈及信号,很容易联想到在Linux系统中所分享到的信号。那么Linux信号和Qt信息有什么不同?

在 Qt 中,用户和控件的每次交互过程称为⼀个事件。比如 "用户点击按钮" 是⼀个事件,"用户关 闭窗口" 也是⼀个事件。每个事件都会发出⼀个信号,例如用户点击按钮会发出 "按钮被点击" 的信 号,用户关闭窗口会发出 "窗口被关闭" 的信号。

Qt信号同样包含三个要素:

  1. 由哪个控件发出。
  2. 信号的类型,如点击按钮信号,移动输入框光标信号等等。
  3. 信号的处理方式:槽(slot),即函数。

槽函数,就是对信号进行响应的函数,将信号与对应的槽函数关联之后,只要信号发出,就能执行对应的槽函数功能。


二.connect关联

在Qt中,想要将信号和槽函数关联起来,可以使用函数connect

connect(const QObject *sender,

const char *signal,

const QObject *receiver,

const char *method,

Qt::ConnectionType type = Qt::AutoConnection);
sender:信号的发送者;
signal:发送的信号(信号函数);
receiver:信号的接收者;
method:接收信号的槽函数;
type: 用于指定关联方式,默认关联方式为 Qt::AutoConnection,通常不需要手动设定。
disconnect()函数可以断开信号和槽的连接,参数与connect一致。
下面我们设计一个界面,界面上存在一个关闭按钮,点击按钮即可关闭界面:

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    QPushButton *myButten = new QPushButton(this);
    myButten->setText("关闭");
    myButten->move(200,200);
    connect(myButten,&QPushButton::clicked,this,&Widget::close);
}

分析这段代码,QPushButten为按钮类 ,随后为其命名为"关闭" ,并设置其在界面中的位置

在connect函数中,定义的按钮myButten为信号的发送者clicked为信号函数,即"按钮被按下"这个信号this为信号的执行者,即Widget对象,也就是界面本身close为接收到信号后要执行的槽函数,即关闭界面

运行程序,点击关闭即可关闭界面。

这里扩展一点知识:

实际上上述所给出的connect函数的参数,是老版本的Qt中的connect函数 ,能够看到参数2和参数4,是两个char* 类型的函数指针 ,但实际上所传入的函数指针,并不一定都是char*类型,在老版本中,需要通过宏来修改两个参数的类型 ,这样太过麻烦,所以在Qt5版本之后,将connect的参数改为了模版类型 ,并且带有了一定的参数检查功能,即参数2和参数4必须分别是参数1和参数3两个对象的成员函数,否则就会编译出错。


三.自定义信号和槽

在上述操作中,我们所使用的信号函数和槽函数,都是对应的控件中所自带的,但是自带的这些信号和槽,肯定不能满足我们所有的需求,所以我们还需要进行自定义。


1.自定义槽函数

槽函数的本质,还是类中的一个成员函数。

(1)代码方式

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QPushButton *myButten = new QPushButton(this);
    myButten->setText("按钮");
    myButten->move(200,200);
    connect(myButten,&QPushButton::clicked,this,&Widget::handleClick);
}

void Widget::handleClick()
{
    this->setWindowTitle("按钮被按下!");
}

注意成员函数必须要在.h文件中先进行声明。

这里我们编写了一个名为handleClick的成员函数,并由connect进行连接,代码的含义为:点击按钮就会修改界面的标题为"按钮被按下!",结果如下:


(2)界面操作

我们在界面设计中设计一个按钮,然后右键点击,能够看到一个**"转为槽"** 的选项,点击,就能得到当前的QPushButten控件,及其父控件的所有的信号函数

我们选择clicked信号,点击OK,随后就会跳转到.cpp文件,并创建一个对应的函数,同时该函数也会在.h文件中进行声明:

随后就可以在该函数中进行代码编写:

cpp 复制代码
void Widget::on_pushButton_clicked()
{
    this->setWindowTitle("按钮已经按下");
}

运行代码,结果如下:

能够看出,通过界面设计的槽函数,不需要使用connect函数进行连接,也可以直接实现槽函数对信号的响应

这与槽函数的名字有关,这样一个规则的名字命名方式,Qt就能自动把信号和槽函数建立联系。

on_pushButton_clicked


2.自定义信号

自定义信号比较少见,在实际开发中很少会需要自定义信号,因为在GUI中,用户能够进行的操作,是可以穷举的,Qt内置的信号,基本上已经覆盖到了所有可能得用户操作。

信号是一类非常特殊的函数,定义自定义信号函数时,我们只需给出函数声明即可信号函数的返回值必须是void,有没有参数都可以。

此时,我们需要告诉Qt,这是一个"信号",通过在类中使用signals关键字当代码扫描到该关键字时,就会自动把下面的函数认为是信号,随后给这些函数自动生成函数定义

Qt内置的信号,都不需要我们手动通过代码来触发,那么自定义出的信号,该如何触发呢?

通过emit关键字 + 信号函数,可以触发自定义信号,当然直接调用信号函数,也可以触发信号。

cpp 复制代码
signals:
    void mySignal();
public:
    void handleMySignal();

在类中声明信号。

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(this,&Widget::mySignal,this,&Widget::handleMySignal);

    emit mySignal();
    //mySignal();
}

void Widget::handleMySignal()
{
    this->setWindowTitle("触发自定义信号");
}

随后进行连接并触发信号,结果如下:


3.信号和槽传参

我们在使用信号时,也可以设置参数,当信号设置参数之后,对应连接的槽函数也必须拥有相同的类型的参数,参数的个数可以不一致,但信号的参数必须比槽函数的个数多

信号传参,本质是将参数的内容传递给槽函数,从而槽函数就可以使用参数内容:

cpp 复制代码
signals:
    void mySignal(const QString& text);
public:
    void handleMySignal(const QString& text);
cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(this,&Widget::mySignal,this,&Widget::handleMySignal);

    emit mySignal("信号传参");
}

void Widget::handleMySignal(const QString& text)
{
    this->setWindowTitle(text);
}

结果如下:


相关推荐
四维碎片3 分钟前
【Qt】QApplication::restoreOverrideCursor():恢复鼠标光标到原始状态的用法解析
开发语言·qt·计算机外设
HEX9CF37 分钟前
【Linux】SQLite 数据库安装教程(Ubuntu 22.04)
linux·数据库·sqlite
恬淡虚无真气从之44 分钟前
django中entity.save(using=)的使用
数据库·python·django
零希1 小时前
正则表达式
java·数据库·mysql
任错错1 小时前
flinksql-Queries查询相关实战
大数据·数据库·mysql·flink·flinksql
史迪仔01121 小时前
【SQL】SQL函数
数据库·sql
danplus1 小时前
外贸邮件营销群发:如何避免成为垃圾邮件?
服务器·api接口·邮件营销·smtp服务器·邮件接口·营销邮件·域名邮箱
琪露诺大湿1 小时前
JavaEE-多线程初阶(1)
java·linux·开发语言·jvm·数据库·java-ee·1024程序员节
代码的奴隶(艾伦·耶格尔)2 小时前
sql进阶篇
java·数据库·sql
风虎云龙科研服务器2 小时前
GPU 服务器:高性能计算的核心驱动力
运维·服务器