QT信号与槽的详细使用示例

QT信号与槽机制的使用

概述

  1. 信号与槽(Signal & Slot)是 Qt 的一种编程机制(即发布-订阅模式),该方式使得在 Qt 中处理界面各个组件的交互操作时变得更加直观和简单。

  2. 信号(Signal)就是在特定情况下被发射的事件(或者说动作、行为),例如PushButton 最常见的信号就是鼠标单击动作,会触发一个名为 clicked的信号。自定义发射信号使用Qt的emit关键字。定义信号使用QT的signals关键字,仅声明不需实现,且不能有返回值,只能为void类型。信号默认是public类型,因此前面不能加Public、Private等关键字。信号的使用:emit + 信号名称;

  3. 槽(Slot)就是信号响应的函数。槽就是一个函数,与一般的C++函数是一样的,可以声明在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。声明槽的关键字为slots,在QT5中不强制要求,但是推荐使用,便于区分。槽函数要与信号的参数和返回值一致,所以槽函数也没有返回值。

  4. 槽函数与一般的函数唯一的不同就是是否与信号进行关联connect:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。

  5. 信号与槽的关联可以是一对一、多对一、或者一对多,甚至信号也可以关联信号,构成一个顺序执行的触发序列。

  6. 使用信号与槽机制必须是QObject类及其子类派生出的类才可以使用,另外,还必须在类定义的最开始的地方添加Q_OBJECT宏。

标准信号与槽的使用

所谓标准信号与槽就是QT中提供的信号以及槽函数,下面以QPushButton的信号和QWidget的槽函数进行说明。
新建一个Widget工程,在UI中随便拖入几个控件,例如pushbutton、progressbar、label等。
在这里插入图片描述
通过connect关联关闭按钮的按压信号pressed以及窗口的关闭槽函数,如下所示:

  //手动关联标准信号与槽
    connect(ui->pushButton_Close,&QPushButton::pressed,this,&Widget::close);

ui->pushButton_Close:信号发出者,指针类型,此处指关闭按钮;
&QPushButton::pressed:信号,&发出者的类名::信号的名字;
this:信号接受者,指针类型,this表明是本部件,此处指窗口widget;
&Widget::close:槽函数,&信号接收者的类名::槽函数的名字。

标准信号和槽函数,均可以在类帮助中找到,通过F1快捷键转到即可,如果在当前类找不到signals与slots,去其父类中找。
还有一种自动关联槽函数的方式,最直接的实现方法就是通过设计器直接转到槽函数添加,这种槽函数的格式为:“on_对象名_事件名”(也可以通过程序手动添加)。

在这里插入图片描述

//自动关联标准信号与槽
void Widget::on_mPushButton_pressed()
{
    ui->label->setText("Hello");
}

函数体里面直接添加想要实现的内容,例如上述代码的槽函数就是更改label控件的显示内容。

自定义槽函数

自定义槽函数就是声明一个与所用信号参数一致的函数,然后将其与信号关联即可。
例如为QPushbutton的clicked信号自定义一个槽函数,clicked信号定义如下
在这里插入图片描述
其形参具备默认值,故其槽函数可以不带形参。

//在头文件中声明
public  slots:
    void M_SelfDefinedSlot();
//自定义槽函数
void Widget::M_SelfDefinedSlot()
{
    ui->progressBar->setValue(99);//改变进度条的值
}
//关联自定义槽函数
connect(ui->mPushButton,&QPushButton::clicked,this,&Widget::M_SelfDefinedSlot);

自定义信号

在项目中新建一个widget,命名为subwidget,此处选择Qt设计界面类会自动生成源文件、头文件以及ui文件。
在这里插入图片描述同样在ui中拖几个按钮控件。
在这里插入图片描述
在子窗体头文件中自定义一个信号:

    signals:
    void mSelfDefinedSignal();

在切换到主窗体的按钮的点击事件响应中发射该信号:

void SubWidget::on_pushButton_clicked()
{
    emit mSelfDefinedSignal();//发射自定义信号
}

在主窗体widget中关联该信号,并自定义槽函数去响应它,实现一个显隐功能。如下所示:

    //创建子窗体
    sw = new SubWidget();

    connect(sw,&SubWidget::mSelfDefinedSignal,this,&Widget::DealSelfDefinedSignal);

在头文件中声明槽函数并实现

//自定义子窗体信号处理槽函数
void Widget::DealSelfDefinedSignal()
{
    //隐藏子窗体
    sw->hide();
    //显示主窗体
    this->show();
}

自定义信号(带参数)

信号是可以带参数的,但只需要声明参数的类型即可,例如:

	signals:
    void mSelfDefinedSignalP(int,QString);

信号的使用:

    emit mSelfDefinedSignalP(10,"子窗口传参");

关联:

    //关联带参数的自定义信号
    connect(sw,&SubWidget::mSelfDefinedSignalP,this,&Widget::DealSelfDefinedSignalP);

其槽函数的类型需要与信号一致:

    void DealSelfDefinedSignalP(int value,QString str);

void Widget::DealSelfDefinedSignalP(int value, QString str)
{
    //toUtf8()将QString转成字节数组QByteArray
    //.data()将字节数组QByteArray转成char*
    qDebug()<<value<<str.toUtf8().data();
}

自定义信号(重载信号)

信号是可以被重载的,例如:

    signals:
    void mSelfDefinedSignal();
    void mSelfDefinedSignal(QString);

对于重载信号的关联要使用函数指针,如下所示:

    //处理重载信号
    //函数指针:其本质是一个指向函数的指针,
    //"::"是用来限定作用域的
    //void (SubWidget::* mSignal)(函数指针的参数)
    //&SubWidget::mSelfDefinedSignal:表示信号(函数)的名字:将其看成一个变量名.SubWidget::是用来告诉编译器函数是SubWidget类中的
    //(SubWidget::* mSignal):为函数指针名.
    void(SubWidget::* mSignal)() = &SubWidget::mSelfDefinedSignal;//函数指针
    connect(sw,mSignal,this,&Widget::DealSelfDefinedSignal);

    void(SubWidget::* mSignalP)(QString) = &SubWidget::mSelfDefinedSignal;//函数指针
    connect(sw,mSignalP,this,&Widget::DealSignalP);

结果就是在控制台打印子窗口传递过来的参数:

void Widget::DealSignalP(QString str)
{
     qDebug()<<str.toUtf8().data();
}

使用Lambda表达式实现信号与槽

lambda表达式为C++11之后的特性,需要在项目的.pro文件中添加:

CONFIG += c++11
    //使用Lambda表示式关联信号,可以不用声明槽函数
    connect(ui->mPushButton_Lambda,&QPushButton::clicked,
            []()
            {
                qDebug()<<123456;
            }
    );

代码格式: [capture] (parameters) mutable -> return-type {statement}

  • [capture]:捕捉列表,捕捉列表总是出现在Lambda函数的开始处,实际上,[]是Lambda引出符,编译器根据该引出符判断接下来的代码是否是Lambda函数,捕捉列表能够捕捉上下文中的变量以供Lambda函数使用。
  • (parameters):参数列表,与普通函数的参数列表一致,如果不需要参数传递,则可以连同括号 () 一起省略。
  • mutable:mutable修饰符,默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空)。
  • ->return-type:返回类型,用追踪返回类型形式声明函数的返回类型,我们可以在不需要返回值的时候也可以连同符号 -> 一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。
  • {statement}:函数体,内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
    当参数void的时候,可以省略() ,即以下两种写法均正确;
auto fun1 = [](){ return 1; };
auto fun2 = []{ return 1; };  // 省略()

当需要在lambda函数内用到外部变量时,需要注意[]内的表达。
[] 不捕获任何变量。
[&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
[=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
[=,&temp] 按值捕获外部作用域中所有变量,并按引用捕获temp 变量。
[var] 按值捕获 var 变量,同时不捕获其他变量。
[this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lambda 中使用当前类的成员函数和成员变量。
此种方式的connect函数只有三个参数。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
QT中的信号机制是QT框架核心的一个特性。它提供了一种在对象之间进行通信的简洁、高效的方式。自定义信号是在QT中扩展信号机制的一种方式,可以灵活地将自定义的信号连接到相应的函数上。 在QT中,自定义信号示例可以如下所示: ```cpp #include <QObject> #include <QPushButton> class MyButton : public QPushButton { Q_OBJECT public: MyButton(QWidget *parent = nullptr) : QPushButton(parent) {} signals: void clickedWithMessage(const QString& message); // 自定义信号 public slots: void onClicked() // 函数 { emit clickedWithMessage("Button is clicked!"); // 发射自定义信号,并传递消息 } }; class MyWidget : public QWidget { Q_OBJECT public: MyWidget(QWidget *parent = nullptr) : QWidget(parent) { MyButton *button = new MyButton(this); connect(button, &MyButton::clickedWithMessage, this, &MyWidget::onButtonClicked); // 连接自定义信号函数 } public slots: void onButtonClicked(const QString& message) // 函数 { qDebug() << "Received message:" << message; } }; ``` 在这个示例中,我们自定义了一个派生自QPushButton的类MyButton,并在其中声明了一个自定义信号`clickedWithMessage`。当按钮被点击时,会发射该自定义信号,并传递一个消息。 然后,在MyWidget的构造函数中,我们创建了一个MyButton实例,通过`connect`函数将该按钮的自定义信号与MyWidget的函数`onButtonClicked`进行连接。 当按钮被点击时,MyWidget的函数`onButtonClicked`会被调用,接收到传递的消息并打印出来。 通过自定义信号,我们可以自由地在不同的对象之间实现消息的传递与处理,使得代码更加模块化和可维护。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值