QT学习回顾(一)信号和槽


(1)命名规范及快捷键、QT基本模块

类名 : 首字母大写,单词与单词之间的首字母大写

函数名: 变量名称 首字母小写,单词和单词之间首字母大写

快捷键:

  1. 注释:ctrl+/
  2. 运行:ctrl+r
  3. 编译:ctrl+b
  4. 字体缩放:ctrl+鼠标滚轮
  5. 查找:ctrl+f
  6. 整行移动:ctrl+shift+↑或↓
  7. 帮助文档:F1
  8. 自动对齐:ctrl+i
  9. 同名之间的.h和.cpp切换 :F4

qt模块组成图如下:
在这里插入图片描述


(2)创建一个QT程序

  • 创建QT项目的注意事项:
  1. 点击创建项目后,选择项目路径以及 给项目起名称
  2. 名称 - 不能有中文 ,不能有空格
  3. 路径 - 不能有中文路径
  4. 默认创建有窗口类,myWidget,基类有三种选择: QWidget 、QMainWindow、QDialog
  5. main函数:
    5.1 QApplication a 应用程序对象,有且仅有一个
    5.2 myWidget w;实例化窗口对象
    5.3 w.show()调用show函数 显示窗口
    5.4 return a.exec() 让应用程序对象进入消息循环机制中,代码阻塞到当前行
#include "widget.h"	
#include <QApplication>//应用程序对象的头文件

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}


(3)按钮控件常用API

  1. 创建 QPushButton * btn = new QPushButton
  2. 设置父亲 setParent(this)
  3. 设置文本 setText(“文字”)
  4. 设置位置 move(宽,高)
  5. 重新指定窗口大小 resize
  6. 设置窗口标题 setWindowTitle
  7. 设置窗口固定大小 setFixedSize
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //创建一个按钮
    QPushButton*btn = new QPushButton;
//    btn->show();
    btn->setParent(this);
    btn->setText("第一个按钮");

    //创建第二个按钮
    QPushButton*btn2=new QPushButton("第二个按钮",this);
    //移动btn2按钮
    btn2->move(100,100);
    //重置窗口大小
    resize(600,400);
    //设置固定窗口大小
    setFixedSize(600,400);
    //设置窗口标题
    setWindowTitle("第一个窗口");

    //创建一个自己的按钮对象
    myPushButton*mybtn=new myPushButton;
    mybtn->setText("我自己的按钮");

    mybtn->move(200,0);
    mybtn->setParent(this);//设置到对象树中

}

(4)对象树和坐标系

  • 当创建的对象在堆区时候,如果指定的父亲是QObject派生下来的类或者QObject子类派生下来的类,可以不用管理释放的操作,将对象会放入到对象树中。

  • 一定程度上简化了内存回收机制

对象树图如下:
在这里插入图片描述

  • Qt中的坐标系 左上角为 0 , 0 点 (x以右为正方向 ,y以下为正方向)

(5)信号和槽

  1. connect函数的介绍:
    • 参数1 信号的发送者
    • 参数2 发送的信号(函数地址)
    • 参数3 信号的接受者
    • 参数4 处理的槽函数 (函数的地址)

示例实现:点击按钮 关闭窗口的案例

    //connect(mybtn,&QPushButton::clicked,this,&QWidget::close);
    connect(mybtn,&myPushButton::clicked,this,&Widget::close);

(6)自定义信号和槽

  • 自定义信号注意事项

    • 自定义信号,写到signals下
    • 返回值void 只需要声明,不需要事先
    • 可以有参数,可以有重载
  • 自定义槽函数的注意事项

    • 返回值void,需要声明,也需要实现
    • 可以有参数,可以发生重载
    • 写到 public slot下 或者public 或者全局函数
  • 触发自定义的信号

    • emit 自定义信号
  • 示例实现:
    下课后,老师触发饿了信号,学生响应信号,请客吃饭

Teacher类中:
			signals:
			    //自定义信号,写到signals下
			    //返回值void 只需要声明,不需要事先
			    //可以有参数,可以有重载
			    void hungry();
Student类中:		
			public slots:
			    //返回值void,需要声明,也需要实现
			    //可以有参数,可以发生重载
			    void treat();
Student类的函数实现:
			void Student::treat(){
			    qDebug()<<"请客吃饭";
			}
Widget类的函数实现:			
			void Widget::classIsOver(){
			    //触发emit
			   emit tea->hungry();
			}
Widget类的构造函数中:
			//创建一个老师对象
			    this->tea=new Teacher(this);
			
			    //创建一个学生对象
			    this->stu=new Student(this);
			
			    //信号和槽
   connect(tea,&Teacher::hungry,stu,&Student::treat);
		    //调用下课函数
		    classIsOver();

(7)当自定义信号和槽出现重载

  • 1、当自定义信号和槽出现重载时如果用回(6)中的方法操作就会出现报错,因此为了解决这样错误我们需要利用函数指针明确指向函数的地址,因为connect中的发送信号与槽函数都是地址,什么是指向地址的呢,也就只有指针指向地址而已

  • 函数指针指向函数地址
    void(Student::*studentSlot)(QString)=&Student::treat;
    void(Teacher::*teacherSingal)(QString)=&Teacher::hungry;

  • 接着信号和槽连接
    connect(tea,teacherSingal,stu,studentSlot);

  • 同样示例实现:

Teacher类中:
			signals:
			    //自定义信号,写到signals下
			    //返回值void 只需要声明,不需要事先
			    //可以有参数,可以有重载
			    void hungry();
			    void hungry(QString foodName);
Student类中:		
			public slots:
			    //返回值void,需要声明,也需要实现
			    //可以有参数,可以发生重载
			    void treat();
			    void treat(QString foodName);
Student类的函数实现:
			void Student::treat(){
			    qDebug()<<"请客吃饭";
			}
			void Student::treat(QString foodName){
    			qDebug()<<"请老师吃饭,老师吃的是"<<foodName;					
}
Widget类的函数实现:			
			void Widget::classIsOver(){
			    //触发emit
	//		   emit tea->hungry();
	    		emit tea->hungry("宫保鸡丁");
			}
Widget类的构造函数中:
			//创建一个老师对象
			    this->tea=new Teacher(this);
			
			    //创建一个学生对象
			    this->stu=new Student(this);
			
   void(Student::*studentSlot)(QString)=&Student::treat;
   void(Teacher::*teacherSingal)(QString)=&Teacher::hungry;

    connect(tea,teacherSingal,stu,studentSlot);
//    //调用下课函数
    classIsOver();

运行后出现食物会加双引号:
在这里插入图片描述
要想去除这双引号就要将

  • QString 转成 char*
  • ToUtf8() 转为 QByteArray
  • Data() 转为 Char *
    qDebug()<<"请老师吃饭,老师吃的是"<<foodName.toUtf8().data();
  • 2、信号可以连接信号、断开信号 disconnect
 void(Student::*studentSlot2)(void)=&Student::treat;
    void(Teacher::*teacherSingal2)(void)=&Teacher::hungry;

    connect(tea,teacherSingal2,stu,studentSlot2);
    //信号连接信号
    connect(btn,&QPushButton::clicked,tea,teacherSingal2);
    // 断开信号
    disconnect(tea,teacherSingal2,stu,studentSlot2);

(8)信号与槽的拓展以及低版本写法

  • 信号可以连接信号
  • 一个信号可以连接多个槽函数
  • 多个信号可以连接同一个槽函数
  • 信号和槽函数的参数 必须类型一一对应
  • 信号和槽的参数个数 是不是要一致?信号的参数个数 可以多余槽函数的参数个数
  • 信号槽可以断开连接 disconnect

connect( 信号的发送者, 发送的信号SIGNAL( 信号) ,信号接受者, 槽函数SLOT(槽函数) )

  • 优点 参数直观

  • 缺点 编译器不会检测参数类型

信号和槽总结图如下:
在这里插入图片描述


(9)lambda表达式

[]标识符 匿名函数
= 值传递 & 引用传递
() 参数 {} 实现体
mutable 修饰 值传递变量 ,可以修改拷贝出的数据,改变不了本体
返回值 ->int {}

示例实现:

    //利用lambda表达式实现点击按钮,关闭窗口
    QPushButton*btn2=new QPushButton;
    btn2->setText("关闭");
    btn2->move(400,0);
    btn2->setParent(this);
    connect(btn2,&QPushButton::clicked,this,[=](){
        btn2->setText("aa");
    });
<think>好的,我现在需要帮助用户了解如何在Qt中使用信号机制。首先,我得回顾下自己关于Qt信号的知识,并参考提供的引用内容,确保回答准确。 用户的问题是关于信号的使用方法,所以我要分步骤解释。根据引用[1]、[2]、[3],信号Qt的核心机制,用于对象间通信,尤其是事件处理。需要覆盖声明信号的方法,连接方式,以及实际例子。 首先,声明部分:用户可能需要在类中声明信号。引用[2]提到使用signalsslots关键字,而信号不需要实现,需要。同时,需要包含Q_OBJECT宏。这部分很重要,因为这是基础。 接下来是连接信号。根据引用[3],使用QObject::connect函数,并说明参数顺序:发送者、信号、接收者、。同时,新的Qt5语法可以使用函数指针,更安全,但旧的字符串语法在元编程时可能有用。还要提到连接规则,比如信号参数可以多于,但不能相反,多个信号可以互相连接。 然后,实际应用示例。引用[2]提到可以通过“转到”自动生成槽函数,但用户可能需要手动编写代码的例子。比如按钮点击触发槽函数,或者自定义信号。需要给出代码示例,比如个按钮的点击信号连接到窗口的关闭,或者自定义信号发射。 注意事项方面,Q_OBJECT宏的必要性,连接参数类型匹配,内存泄漏问题(比如Lambda表达式中的引用捕获导致悬垂指针),还有连接方式对线程的影响,比如自动连接类型(Qt::AutoConnection)会根据是否同线程决定直接调用还是队列连接。 可能用户会遇到的问题包括:忘记添加Q_OBJECT导致信号无效,参数不匹配导致连接失败,或者跨线程通信的问题。需要提醒这些点,帮助用户避免常见错误。 最后,生成相关问题。根据用户可能的后续疑问,比如参数传递、多线程使用、连接错误排查、性能优化,以及自定义信号的应用场景。这些问题需要围绕核心知识点展开,帮助用户深入理解。 检查是否有遗漏的引用内容。引用[1]提到信号的类型安全、灵活性应用场景,如GUI交互、MVC、多线程。引用[2]详细说明了连接规则,如参数数量、多对多连接,以及代码实现的例子。引用[3]强调松散耦合基本概念。需要将这些内容整合到回答中,确保覆盖全面。 总结回答结构:声明信号,连接方式,代码示例,注意事项,相关问题。确保每个部分都有引用支持,并在适当的地方添加引用标识。例如,连接规则部分引用[2],信号概念引用[3]。</think>### 如何在 Qt 中使用信号机制? Qt信号机制是其核心特性,用于实现对象间的高效通信,特别适用于事件驱动编程(如 GUI 开发)[^1]。以下是具体使用方法: --- #### **1. 声明信号** - **信号(Signals)**: 在类头文件中使用 `signals` 关键字声明,无需实现。例如: ```cpp class MyWidget : public QWidget { Q_OBJECT // 必须包含 Q_OBJECT 宏以支持信号 signals: void mySignal(int value); // 声明个带参数的信号 }; ``` - **(Slots)**: 使用 `public/protected/private slots` 关键字声明,需实现函数体。例如: ```cpp class MyReceiver : public QObject { Q_OBJECT public slots: void mySlot(int value) { /* 处理逻辑 */ } }; ``` --- #### **2. 连接信号** 通过 `QObject::connect` 函数建立连接,语法如下: ```cpp QObject::connect(发送者, &发送者类::信号, 接收者, &接收者类::); ``` - **示例**:按钮点击关闭窗口 ```cpp QPushButton *button = new QPushButton("退出"); QObject::connect(button, &QPushButton::clicked, qApp, &QApplication::quit); ``` - **连接规则**: - 信号参数数量可以多于槽函数,但类型需兼容[^2]。 - 支持对多、多对信号信号连接。 --- #### **3. 自定义信号与触发** - **发射信号**:使用 `emit` 关键字触发信号: ```cpp emit mySignal(42); // 触发信号并传递参数 ``` - **应用场景**: 例如,数据更新后通知界面刷新: ```cpp class DataModel : public QObject { Q_OBJECT signals: void dataUpdated(); }; ``` --- #### **4. 注意事项** 1. **必须添加 `Q_OBJECT` 宏**: 否则无法生成元对象代码,导致信号失效[^3]。 2. **参数类型匹配**: 信号的参数类型需致或可隐式转换(如 `QString` 到 `const char*`)。 3. **Lambda 表达式**: Qt5 支持直接连接 Lambda 表达式作为: ```cpp connect(button, &QPushButton::clicked, [=]() { qDebug() << "按钮被点击"; }); ``` 4. **跨线程通信**: 若信号在不同线程,需使用 `Qt::QueuedConnection` 连接方式。 --- #### **代码示例** ```cpp // 自定义信号的完整示例 class Sender : public QObject { Q_OBJECT signals: void valueChanged(int); }; class Receiver : public QObject { Q_OBJECT public slots: void handleValue(int v) { qDebug() << "接收值:" << v; } }; // 连接方式 Sender sender; Receiver receiver; QObject::connect(&sender, &Sender::valueChanged, &receiver, &Receiver::handleValue); emit sender.valueChanged(100); // 输出:接收值:100 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值