Qt学习笔记(二):信号和槽


一、创建一个基于 QWidget 的项目,不带有界面设计器:

二、在主窗口下添加两个按钮对象,连接按钮发出的信号和槽函数:

mywidget.h:

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>

// 引入按钮头文件
#include <QPushButton>

class MyWidget : public QWidget
{
    Q_OBJECT
    
public:
    MyWidget(QWidget *parent = 0);
    ~MyWidget();
    
private:
    // 声明两个按钮对象
    QPushButton b1;  // 普通对象
    QPushButton *b2; // 指针对象
};

#endif // MYWIDGET_H

mywidget.cpp:

#include "mywidget.h"

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
{
    // 通过 setParent 方法指定父对象
    b1.setParent(this);
    b1.setText("Button1");
    b1.resize(80, 40);
    b1.move(200, 100);
    
    // 通过构造函数方法指定父对象
    b2 = new QPushButton(this);
    b2->setText("Button2");
    b2->resize(80, 40);
    b2->move(30, 20);
    
    /*
     * 连接信号和槽:点击按钮的时候,关闭当前窗口
     * 参数1:信号的发送者(指针类型)
     * 参数2:发送的信号;&发送者的名字::信号名称
     * 参数3:信号的接收者(指针类型)
     * 参数4:处理信号的函数(叫做槽函数);&接收者的名字::槽函数名称
     */
    connect(&b1, &QPushButton::clicked, this, &MyWidget::close);
    
    // 连接信号和槽:按下按钮的时候,当前窗口最大化显示
    connect(b2, &QPushButton::pressed, this, &MyWidget::showMaximized);
    
    // 重置主窗口的大小
    this->resize(600, 400);
}

MyWidget::~MyWidget()
{
    
}

其中信号 &QPushButton::clicked、&QPushButton::pressed,

和槽函数 &MyWidget::close、&MyWidget::showMaximized 都是 Qt 定义好的;

可以在 Qt 帮助文档里查找:

三、我们也可以自定义槽函数:

自定义槽函数的特点:槽函数的本质就是一个普通函数,在 Qt5 里面,自定义槽函数可以是成员函数、普通全局函数、或者静态函数都行;槽函数的返回值和参数需要和信号一致;

注意:信号和槽函数都没有返回值,但是可以带参数;

在 mywidget.h 中声明一个自定义的槽函数:

在 mywidget.cpp 中连接信号和自定义槽函数:

注意:一个信号可以连接多个槽函数;

四、自定义信号:

案例:添加一个子窗口,在主窗口上点击按钮的时候,主窗口隐藏,子窗口显示;

点击子窗口上的按钮的时候,子窗口隐藏,主窗口显示;

1、在 Qt 项目上添加子窗口:

2、在子窗口头文件中添加自定义信号:

childwidget.h 文件为:

#ifndef CHILDWIDGET_H
#define CHILDWIDGET_H

#include <QWidget>
#include <QPushButton>

class ChildWidget : public QWidget
{
    Q_OBJECT
public:
    explicit ChildWidget(QWidget *parent = 0);
    
signals:
    // 自定义信号必须由 signals 关键字声明;
    // 自定义信号没有返回值,但可以有参数;
    // 自定义信号就是函数的声明,只需声明,无需定义;
    // 发送信息使用关键字 emit;
    void mySignal();
    
public slots:
    // Qt5 里面自定义槽函数不是必须由 public slots 声明;
    // 但是 Qt4 里面槽函数必须由 public slots 声明;
    void sendSignal();
    
private:
    // 创建一个按钮对象
    QPushButton btn;
};

#endif // CHILDWIDGET_H

3、在子窗口中点击按钮时,发送自定义信号:

childwidget.cpp 文件为:

#include "childwidget.h"

ChildWidget::ChildWidget(QWidget *parent) :
    QWidget(parent)
{
    this->resize(400, 300);         // 设置窗口大小
    this->setWindowTitle("子窗口"); // 设置窗口标题
    
    btn.setParent(this);
    btn.setText("切换到主窗口");
    btn.move(200, 100);

    // 点击按钮,调用自定义槽函数(sendSignal),发送自定义信号(mySignal)
    connect(&btn, &QPushButton::clicked, this, &ChildWidget::sendSignal);
}

// 自定义槽函数
void ChildWidget::sendSignal()
{
    // 发送自定义信号
    emit mySignal();
}

4、在主窗口中添加子窗口对象,并自定义槽函数处理子窗口发出的信号:

修改 mywidget.h 文件为:

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>
#include <QPushButton>
// 在主窗口中引入子窗口的头文件
#include "childwidget.h"

class MyWidget : public QWidget
{
    Q_OBJECT
    
public:
    MyWidget(QWidget *parent = 0);
    ~MyWidget();
   
    // 自定义槽函数
    void mySlot();    
    // 处理自定义信号的槽函数
    void dealSignal(); 
    
private:
    QPushButton b1;
    
    // 在主窗口中声明子窗口对象
    ChildWidget child;
};

#endif // MYWIDGET_H

5、点击主窗口上的按钮,隐藏主窗口,并显示子窗口;

同时连接子窗口发出的信号和槽函数,当接收到信号时,显示主窗口,隐藏子窗口:

修改 mywidget.cpp 文件为:

#include "mywidget.h"

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
{
    this->resize(400, 300);         // 设置窗口大小
    this->setWindowTitle("主窗口"); // 设置窗口标题

    b1.setParent(this);
    b1.setText("切换到子窗口");
    b1.move(200, 100);
    
    // 点击按钮,调用自定义槽函数(mySlot),隐藏主窗口,显示子窗口
    connect(&b1, &QPushButton::clicked, this, &MyWidget::mySlot);
    
    // 连接子窗口的自定义信号和主窗口中的自定义槽函数
    // 参数1:信号的发送者(子窗口)
    // 参数2:发送的信号(子窗口自定义的信号)
    // 参数3:信号的接收者(主窗口)
    // 参数4:处理信号的自定义槽函数
    connect(&child, &ChildWidget::mySignal, this, &MyWidget::dealSignal);
}

// 自定义槽函数
void MyWidget::mySlot()
{
    // 隐藏主窗口
    this->hide();
    // 显示子窗口
    child.show();
}

// 处理信号的自定义槽函数
void MyWidget::dealSignal()
{
    // 显示主窗口
    this->show();
    // 隐藏子窗口
    child.hide();
}

MyWidget::~MyWidget()
{
    
}

五、带参数的自定义信号和自定义槽函数:

在上面案例的子窗口头文件(childwidget.h)中自定义一个带参信号:

并在子窗口上点击按钮的时候,发送带参信号:

在主窗口头文件(mywidget.h)中自定义一个相对应的带参槽函数:

在主窗口中处理无参和有参的信号:

    // 因为信号和槽函数都重载了,所以直接使用 connect 连接信号和槽的时候会报错,
    // 因为存在二义性,不确定调用的是无参的,还是有参的;
    // 可以使用函数指针来解决:
    // 无参数的信号和槽函数的函数指针:
    void(ChildWidget::*noParamSignal)(void) = &ChildWidget::mySignal;
    void(MyWidget::*noParamSlot)(void) = &MyWidget::dealSignal;

    // 有参数的信号和槽函数的函数指针:
    void(ChildWidget::*haveParamSignal)(int, QString) = &ChildWidget::mySignal;
    void(MyWidget::*haveParamSlot)(int, QString) = &MyWidget::dealSignal;
    
    // 连接无参数的自定义信号和无参数的槽函数
    // 函数指针 noParamSignal 就表示无参的信号,
    // 函数指针 noParamSlot 就表示无参的槽函数;
    connect(&child, noParamSignal, this, noParamSlot);
    
    // 连接带参数的自定义信号和带参数的槽函数
    connect(&child, haveParamSignal, this, haveParamSlot);

测试结果如下:

老师的视频在演示的时候,qDebug() 输出 QString 数据是中文时会出现乱码,如下:

但我的可以直接输出中文;如果中文输出乱码,可以将 QString 类型转换成 char* 类型:

六、上面使用 函数指针 的方式区别无参和有参信号的方法是 Qt5 之后才有的,在 Qt4 的时候是另一种方法区分无参和有参的信号,如下:

    // 连接无参的信号和无参的槽函数
    connect(&child, SIGNAL(mySignal()), this, SLOT(dealSignal()));
    
    // 连接有参的信号和有参的槽函数
    connect(&child, SIGNAL(mySignal(int,QString)), this, SLOT(dealSignal(int,QString)));

Qt4 的这种方式用起来比较方便,但是有一个缺点:SIGNAL 和 SLOT 宏会将信号名称和槽函数名称转换成字符串,在项目编译的时候不进行错误检查;也就是说信号名称和槽函数名称写错了,也可以编译通过,但是程序会在运行的时候直接崩掉。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值