Qt 5.14.2 学习记录 —— 사 信号与槽机制(1)

文章目录


1、概念

Qt中,控件和用户的操作都会发出信号,比如点击按钮,移动鼠标等,信号的处理函数就是槽。Qt可以用connect来把信号和槽关联起来,这样只要信号触发,就自动执行对应的槽函数。槽函数本身也是一个回调函数。对于回调来说,对应的处理方法都是提前准备好的。Qt中必须要先关联好信号和槽,再触发信号。

2、connect

connect是QObject的静态成员函数。Qt的类都是存在继承关系的,比如PushButton,LineEdit的父类都是QWidget,QWidget就是控件,QWidget的父类是QObject,所有Qt的类都直接或间接继承自QObject类,所以Qt中的类都可以直接使用connect。

最后一个参数是默认参数,暂且不考虑。

sender表示信号源,也就是哪个控件发出的信号。

signal表示信号类型。

receiver表示哪个对象接收信号,method就是信号处理函数。

写一个按钮,一点击就关闭窗口。widget.cpp:

cpp 复制代码
#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    QPushButton* button = new QPushButton(this);
    button->setText("Exit");
    button->move(330, 250);
    
    connect(button, &QPushButton::clicked, this, &Widget::close);
}

connect前两个参数和后两个参数必须是分别匹配的,button是什么类型,那么第二个参数的信号就必须是这个类型内置的信号或者它的父类的信号。

写第二个参数时,写clicked时会出现两个写法,一个是click,一个是clicked,两个前面都有一个符号,click的符号代表槽函数,clicked的符号代表信号类型。

槽函数直接用内置函数。

Qt中很多按钮存在共性内容,这些共性内容放置在QAbstractButton类中,这些按钮类都继承自这个类,clicked信号就在这个父类中。当按钮被激活时,clicked信号就会被发出。

二四两个参数是const char的参数,传的时候需要给信号搭配一个SIGNAL宏,给槽函数搭配一个SLOT宏,都转为char后才能传:

cpp 复制代码
connect(button, SIGNAL(&QPushButton::clicked), this, SLOT(&Widget::close));

但Qt5之后给connect做了重载函数,这两个参数就变成了泛型参数,允许传入任意类型的指针了。不过如果参数不匹配也不行。

3、自定义槽函数

在Widget类里写一个自定义的成员函数的声明,widget.cpp中写上实现,我们就可以直接用这个函数了。

widget.h:

cpp 复制代码
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    
    void handleClicked();

private:
    Ui::Widget *ui;
};

widget.cpp:

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

    QPushButton* button = new QPushButton(this);
    button->setText("Button");
    button->move(330, 250);

    connect(button, &QPushButton::clicked, this, &Widget::close);
}

void Widget::handleClicked()
{
    // 点击按钮就修改窗口标题
    this->setWindowTitle("Button clicked");
}

更简单的方式是直接操作图形化界面。

将PushButton拖拽过来后,右击选择转到槽

可以看到来到了它的直接的父类QAbstractButton,以及QA的父类QWidget,以及QW的父类QObject。点击click(),就来到widget.cpp文件,并且自动写出了一个函数框架,代码部分则由用户自定义。

此时连接信号和槽就不是connect,而是通过函数名字,也就是选择click()后自动转到的,Qt自动生成的函数名来连接信号和槽。函数名字得符合命名规则,如果把clicked改为click,PushButton并没有对应的函数,那么就不生效,报警告,因为无法连接上。

调用connectSlotsByName就会触发连接,在生产时的实时文件ui_widget.h中会看到该函数。

4、自定义信号

信号本质是一个函数,但和槽函数不同,槽函数在Qt 5以及更高版本中,槽函数和普通成员函数之间已经没什么区别了;但信号特殊,用户只需要写出函数声明,并能让Qt知道这是一个信号,那么函数的定义,Qt会在编译过程中自动生成,而且对于自动生成过程,用户无法进行操作。

作为信号函数,返回值必须为void,参数有无都可,且也可以支持重载。

在写信号时,现在头文件中Widget类的public部分写上signal关键字,这是Qt的关键字,qmake生成代码时扫描到类中包含signals关键字时就会自动把下面的函数声明当作信号,并生成函数定义。

cpp 复制代码
// widget.h

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void handleMySignal();

signals:
    void mySignal();

private:
    Ui::Widget *ui;
};

// widget.cpp

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

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

    // 连接好后用emit来发送信号
    emit mySignal();
}

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

运行后发现窗口标题变为处理自定义信号了。

我们也可以把发送并处理信号放到一个按钮中,按钮的自定义槽函数按照控件方式来写:

cpp 复制代码
// widget.h

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void handleMySignal();

signals:
    void mySignal();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
};

// widget.cpp

#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

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

void Widget::on_pushButton_clicked()
{
    connect(this, &Widget::mySignal, this, &Widget::handleMySignal);

    // 连接好后用emit来发送信号
    emit mySignal();
}

在Qt 5以上,不写emit也可以,因为处理signals部分时都会自动发送信号。不过也应该写,可读性更强。

结束。

相关推荐
Scott9999HH7 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社8 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海8 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖9 小时前
JDK 26 新特性详解
java·开发语言
马优晨9 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
a11177610 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao11 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
人邮异步社区11 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大12 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai12 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang