文章目录
- Qt信号槽的优点及缺点
- Qt中的文件流和数据流区别?
- Qt中show和exec区别
- QT多线程使用的方法 (4种)
- QString与基本数据类型如何转换?
- QT保证多线程安全
- 事件与信号的区别
- connect函数的连接方式?
- 信号与槽的多种用法
- Qt的事件过滤器有哪些
- 同步和异步的网络连接区别?
- Qt网络模块中有那些类来执行异步操作?
- Qt如何执行HTTP请求?
- 什么是Qt Quick?
Qt信号槽的优点及缺点
信号槽为观察者模式。槽的本质为类成员函数,参数为任何数据类型,可以被重载,也可以是虚函数,也可以设置权限(public/private/protected)
1.Qt信号槽的优点
(1)灵活性好: 一个信号可以绑定多个槽,同时多个信号也可以关联同一个槽,提供了高度的灵活性
(2)类型安全: 信号和槽在关联时,必须确保它们的签名(包括参数类型和参数个数)完全一致,否则编译时会报错,这保证了类型的安全性。
(3)松散耦合: 信号和槽机制减弱了QT对象之间的耦合度,使得对象之间的交互更加灵活和独立。
2.Qt信号槽的缺点
执行速度慢: 信号和槽机制在执行时,特别是在多线程环境下,需要排队等待和定位接收信号的对象,因此执行速度相对较慢,效率较低。
Qt中的文件流和数据流区别?
1.Qt的文件流QTextStream
(1)文本展现方式:通过QTextStream写入文件的数据以文本方式展现,提供读写文本文件的接口
(2)操作对象:可以操作QIODevice、QString和QByteArray三种数据类型
(3)编码特性:内部使用Unicode编码处理文本数据
(4)读取模式:
块读取:使用readLine()
/readAll()
函数进行整块数据读取
字符读取:使用QChar
/char
逐个字符读取(常用于文件解析场景)
(5)格式控制:
通过setFileWidth()
/setPadChar()
设置文本宽度和填充字符
通过setFileAlignment()
设置段落文本的对齐格式
(6)适用场景:特别适合处理字符、数字等文本数据的读写操作
2.Qt中的数据流QDataStream
(1)数据类型支持:可以操作各种数据类型,包括类对象等复杂数据结构
(2)数据持久化:保存到文件的数据可以完整还原至内存
(3)操作范围:
磁盘文件操作
内存数据信息处理
(4)构造函数:
QDataStream()
:构造无IO设备的数据流
QDataStream(QIODevice *d)
:使用指定IO设备构造数据流
(5)关键控制参数:
ByteOrder
:控制读写字节顺序
FloatingPointPrecision
:设置浮点数精度
(6)状态检测:
通过Status
检测流状态(正常/数据损坏/写入失败等)
使用atEnd()
检测文件结尾
Qt中show和exec区别
1.show()针对显示非模态对话框
非模态特性: show()用于显示非模态对话框,不会阻塞程序线程,允许用户同时与其他窗口交互
对象生命周期: 若对话框创建在栈上,离开作用域后对象会被销毁,导致对话框仅短暂闪现
2.exec()针对显示填充对话框
模态特性: exec()用于显示模态对话框,会开启事件循环并阻塞线程, 模态对话框在关闭前,用户不能操作应用程序其他窗口
典型场景: 适用于必须立即处理的重要对话框,如文件保存确认
3.exec()的作用
执行流程:
进入事件循环(如return su.exec())
等待响应用户输入(Wait状态)
Qt系统处理并传递事件/消息到各窗口
退出机制: 当程序遇到exit()时,返回exec()的值终止循环
QT多线程使用的方法 (4种)
1… QRunnable和QThreadPool结合
实现方式: 继承QRunnable类并重写
run()
函数,然后通过QThreadPool来运行线程
限制条件: 该方法不能使用信号和槽机制进行线程间通信
适用场景: 适合不需要与主线程频繁交互的独立任务
- QtConcurrentRun类
特点: 无需继承类即可在另一个线程中执行函数
优势: 使用简单方便,适合快速实现多线程功能
应用场景: 特别适合在后台线程中执行单个函数的情况
- 继承QThread
核心操作: 通过继承QThread类并重写
run()
函数来实现多线程
实现要点: 需要完全重写run()函数来定义线程执行逻辑
注意事项: 这是最传统的QT多线程实现方式
- 继承QObject
关键技术: 继承QObject类后使用
moveToThread()
方法将对象移动到新线程
优势: 可以充分利用QT的信号槽机制
灵活性: 允许对象在不同线程间移动,适合复杂的线程交互场景
5.操作系统线程和进程区分
系统架构: 操作系统可同时执行多个任务(进程),每个进程又可包含多个任务(线程)
执行特性: 线程之间相互独立,采用抢占式执行方式
硬件影响:
单核CPU同一时刻只能执行一个线程
多核CPU可真正实现多线程并行
性能考量: 单核CPU上线程切换会降低执行效率,耗时操作应放在独立线程中防止界面卡死
6.阻塞和非阻塞
非阻塞定义: 一个线程的操作不会阻塞其他线程对事件的接收和处理
阻塞现象:
公共资源同时只能被一个线程访问
其他线程访问会被挂起直到当前访问结束
主线程界面刷新也可能因此被挂起
实际影响: 阻塞操作可能导致界面假死,应尽量避免在主线程中进行
7.同步和异步
同步执行: 必须等待操作完成才能继续执行后续代码
异步特点: 函数调用后不等待结果直接执行后续代码
关键区别:
同步:等待操作完成 → 顺序执行
异步:不等待结果 → 并行执行
应用建议: 耗时操作应采用异步方式避免阻塞主线程
QString与基本数据类型如何转换?
1.QString与数字之间转换
QString 转换为 int: toInt()
int 转换为 QString: QString::number(int)
// 1: QString转换为int double float
QString qstr1("2980");
int itemp1 = qstr1.toInt() + 700;
qDebug()<<"itemp1="<<itemp1<<endl;
// int-->QString
QString qstr2=QString::number(itemp1);
qDebug()<<"qstr2="<<qstr2<<endl;
2.QDateTime与QString之间转换
QString 转换为 QDateTime: QDateTime::fromString(QString, QString)
QDateTime 转换为 QString: toString(QString)(需要指定格式)
// 2: QString--->2: QDateTime
QString qstr3="2023-03-16 17:03:28";
QDateTime qdatetime1=QDateTime::fromString(qstr3,"yyyy-MM-dd hh:mm:ss");
qDebug()<<"qdatetime1="<<qdatetime1<<endl;
// QDateTime -->QString
QDateTime qdatetime2=QDateTime::currentDateTime(); // 获取当前时间
QString qstr4=qdatetime2.toString("yyyy-MM-dd hh:mm:ss");
qDebug()<<"qstr4="<<qstr4<<endl;
- QString与QByteArray之间转换
QString 转换为 QByteArray: toUtf8()
QByteArray 转换为 QString: QByteArray可以直接赋值给QString
// 3: QString--->QByteArray
QString qstr5("main qt creator");
QByteArray bytes1=qstr5.toUtf8();
qDebug()<<"bytes1="<<bytes1<<endl;
// QByteArray--->QString
QByteArray bytes2("QString ByteArray");
QString qstr6=bytes2;
qDebug()<<"qstr6="<<qstr6<<endl;
4.QString与char*转换
QString 转换为 char*: toLatin1().data()
char* 转换为 QString: QString(QLatin1String(char*))
// 4: QString--->char*
QString qstr7("Analyze Qt Creator");
char* char1;
QByteArray qbt=qstr7.toLatin1(); // 这步必须操作
char1=qbt.data();
qDebug()<<"char1="<<char1<<endl;
// char*--->QString
QString qstr8=QString(QLatin1String(char1));
qDebug()<<"qstr8="<<qstr8<<endl;
QT保证多线程安全
1.QT如何保证多线程安全
(1)使用互斥锁:通过QMutex类实现资源访问的互斥性,避免数据竞争或死锁
(2)使用读写锁:当有线程需要写入时,其他所有线程(包括读取线程)都会被阻塞
(3)使用信号和槽机制:避免直接操作共享数据
(4)使用显式线程切换:通过QThread类显式创建和管理线程,禁止直接操作线程,依赖信号槽通信
事件与信号的区别
1.什么是信号
信号是一种抽象、用于实现对象异步通信机制(由QObject类所定义)
2.什么是事件
事件是由QEvent及相关子类所定义的消息,主要用于处理对象的事件。
3.区别是什么?
(1)事件与信号的实现机制不同:①事件处理则需要通过派生和覆盖QObject的event()函数来实现。②信号的实现由Qt框架负责。当信号被发射时,Qt的元对象系统会自动调用连接到该信号的槽函数。
(2)事件与信号的触发机制不同:①事件则需要对象本身通过事件驱动的方式来触发,是被动处理的。对象需要覆盖event()函数来处理特定类型的事件。②信号是由发送对象直接通知接收对象的,是一种主动发送的机制。当信号被发射时,Qt框架会自动调用连接到该信号的槽函数。③信号就像打电话,主动通知对方。例如,按钮点击后会发射一个信号,通知其他对象执行相应的操作;事件就像接收邮件,需要自己去查看和处理。例如,窗口需要处理鼠标移动事件,以响应用户的操作。
(3)事件与信号的消息类型不同:①事件有具体明确的消息类型,如单击、双击等。事件对象(如QEvent及其子类)携带了描述整个事件的数据和事件类型。②信号是一种抽象的消息,没有特定的类型。可以使用任意的参数来传递信息,使得信号非常灵活
(4)事件与信号的应用场景及时机不同:①在实现窗口部件时,我们必须考虑如何处理事件。事件更多地用于处理对象内部的具体行为,如鼠标移动、键盘输入等。②在编程中,特别是使用窗口部件时,我们经常要使用信号,并遵守信号与槽之间的机制。信号通常用于对象间的异步通信,如按钮点击后触发某个动作。
connect函数的连接方式?
五种类型:直接连接、自动连接、队列连接、保留连接、自动类型转换连接
(1)直接连接:当信号被发射时,槽函数会立即在发射信号的线程的当前执行上下文中被调用。信号发射和槽函数执行是同步的。语法如下:
QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot, Qt::DirectConnection);
(2)自动连接:这是Qt的默认连接方式。Qt会根据发射信号的对象和接收槽的对象所在的线程来决定采用直接连接还是队列连接。
①同一线程: 如果发射信号的对象和接收槽的对象位于同一个线程,则自动采用直接连接 (Direct Connection)。
②不同线程: 如果发射信号的对象和接收槽的对象位于不同的线程,则自动采用队列连接 (Queued Connection)。QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot);
(3)队列连接:当信号被发射时,Qt不会立即执行槽函数。而是将一个包含信号信息和参数的事件(QEvent::MetaCall)放入接收槽的对象所在的线程的事件队列中。该线程的事件循环在后续某个时刻处理这个事件时,才会调用槽函数。信号发射和槽函数执行是异步的。
QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot, Qt::QueuedConnection);
(4)保留连接: 用于确保信号和槽之间最多只有一个连接。如果尝试创建第二个连接,connect 会返回 false,并且不会创建新的连接。
QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot, Qt::UniqueConnection);
(5)自动类型转换连接:为了向后兼容旧版本的Qt而设计的。
QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot, Qt::AutoCompatConnection);
(6)核心区别:
直接连接:立即执行,线程不安全但高效
自动连接:智能选择,默认推荐方式
队列连接:线程安全,适合跨线程
保留连接:特殊场景使用
类型转换:兼容旧代码
信号与槽的多种用法
信号与槽机制用于对象间通信,共有6种使用方法
1.普通方式
连接方法:直接使用connect函数将信号与槽连接
实现要点:通过函数建立标准连接关系
特点:最基本的信号槽连接方式,适用于简单的一对一通信场景
connect(button, &QPushButton::clicked, label, &QLabel::setText);
2.一个信号连接多个槽
执行机制:当信号被触发时,所有连接的槽函数都会被执行
注意事项:多个槽的执行顺序不确定,不应依赖执行顺序编写逻辑
应用场景:适用于需要广播通知多个接收者的情形
connect(lineEdit, &QLineEdit::textChanged, statusBar, &QStatusBar::showMessage);
connect(lineEdit, &QLineEdit::textChanged, logger, &Logger::logInput);
connect(lineEdit, &QLineEdit::textChanged, displayWidget, &DisplayWidget::updateDisplay);
3.带参数的信号和槽
参数传递:信号可以携带参数传递给槽函数
类型匹配:连接信号和槽时,它们的参数类型必须完全匹配(或者可以隐式转换)。参数的个数也必须一致。
语法示例: 可以通过重载信号和槽函数来实现不同参数类型的连接。
// 信号声明 (在头文件中)
signals:
void valueChanged(int newValue);
void textChanged(const QString &newText);
// 槽函数声明 (在头文件中)
slots:
void updateValue(int value);
void updateText(const QString &text);
// 连接示例
connect(slider, &QSlider::valueChanged, this, &MyClass::updateValue);
connect(lineEdit, &QLineEdit::textChanged, this, &MyClass::updateText);
4.断开连接
断开方法:使用QObject::disconnect()
函数来断开之前建立的信号与槽的连接。
使用场景: 在对象的生命周期管理中,或者在需要动态改变对象间通信关系时使用。例如,当某个对象即将被销毁时,应该断开它发出的信号与其他对象的连接,以避免悬空指针或意外行为。
注意事项: 断开连接后,该信号将不再触发对应的槽函数,但其他未断开的连接仍然有效。
// 断开特定的信号槽连接
disconnect(button, &QPushButton::clicked, label, &QLabel::setText);
// 断开 button 对象发出的所有信号与 label 对象的所有槽的连接
disconnect(button, nullptr, label, nullptr);
// 断开 button 对象发出的 clicked 信号与所有接收者的连接
disconnect(button, &QPushButton::clicked, nullptr, nullptr);
5.信号连接信号 (Signal Connected to Signal)
别名: 也常被称为“信号转发”或“信号传递”。
工作机制: 当源信号被发射时,目标信号也会被自动发射。
特点: 实现了信号的链式传递。可以用于信号转发(一个对象接收信号后,将其转发给另一个对象)或信号预处理(在信号传递路径中加入处理逻辑)。
应用价值: 增强了信号处理的灵活性和模块化程度。可以构建复杂的信号处理链。
6.自定义信号及槽
声明方式:使用signals:
和slots:
关键字在类定义中声明
实现步骤:
继承自QObject
类
使用signals
关键字声明信号
使用slots
关键字声明槽函数
使用emit
关键字触发信号
Qt的事件过滤器有哪些
核心功能: 在一个对象接收到事件前进行拦截/处理/修改的机制
实现方式: 通过QObject的eventFilter()
方法处理事件
用途:主要用于提高程序的可维护性和可扩展性
- QEvent类别
监视范围: 仅监视特定类型事件
典型示例: 鼠标事件
特点: 事件类型针对性过滤,如键盘/鼠标等硬件事件- QApplication级别
监视范围: 整个QT应用程序的所有事件
应用场景: 需要全局监控时使用
特点: 可捕获应用启动/退出等系统级事件- QObject级别
监视范围: 任何QObject对象上的事件
覆盖性: 包含但不限于QWidget对象
灵活性: 可监控所有继承自QObject的类实例- QWidget级别
监视范围: 仅限QWidget及其子类对象
典型应用: 窗口组件的事件处理
区别点: 比QObject范围更专一,针对可视化组件- QGraphicsItem级别
监视范围: 仅限QWidget及其子类对象
图形框架: 专用于图形视图框架中的图元
特殊用途: 处理复杂图形交互场景
同步和异步的网络连接区别?
- 同步连接
定义: 同步连接是一种阻塞式的网络连接方式。
特点: 程序在执行同步操作的过程中会被暂停,直到网络请求完成并返回结果后才继续执行下一步操作。即当前线程会被阻塞,直到网络操作完成。- 异步连接
定义: 异步连接是一种非阻塞式的网络连接方式。
特点:
程序在执行异步操作的时候不会被暂停。当网络操作返回结果时,系统会发出一个信号通知应用程序,并且在另一个线程中处理网络数据。
优势: 异步连接是一种更加高效的网络连接方式,它可以避免线程的阻塞,提升系统的并发性能。
同步与异步的区别: 两者唯一的区别在于网络操作执行的时候,是否会阻塞当前线程。
Qt网络模块中有那些类来执行异步操作?
在QT网络编程当中,直接使用QNetworkAccessManager
和QNetworkReply
来执行异步网络操作。
QNetworkAccessManager
类
用于管理网络请求的类,可以发出异步请求和接收服务器响应。提供对cookie的支持和多种网络功能,可通过Qt文档搜索获取详细信息。
管理机制: 所有请求都会使用内部的QNetworkCookieJar进行cookie管理QNetworkRequest
类
用于向URL发送请求的类,可指定用户代理字符串、可设置HTTP请求头、可包含请求数据等参数。QNetworkReply
类
包含发送给QNetworkAccessManager
的数据和首部信息QNetworkCookieJar
类
专门用于管理HTTP cookie的类。可以存储和读取cookie,
能够将cookie与请求一起发送。
Qt如何执行HTTP请求?
- 核心组件
管理组件: 使用QNetworkAccessManager作为HTTP请求的核心管理器,负责协调网络操作。
请求封装: QNetworkRequest用于封装HTTP请求的详细信息,包括URL和请求头等。- 执行步骤
(1)实例创建: 首先需要创建QNetworkAccessManager的实例,作为所有网络请求的入口点。
(2)地址获取: 通过QUrl类获取目标URL地址,确保地址格式正确。
(3)请求发送: 使用QNetworkRequest执行GET请求,并通过get()函数发送请求。
(4)循环处理: 通过while循环确保应用程序不会被阻塞,直到网络操作完成。
(5)数据读取: 操作完成后通过QNetworkReply实例读取响应数据。
(6)内存管理: 操作完毕后需要及时清除内存,避免资源泄漏。
什么是Qt Quick?
Qt Quick 是一个用于创建现代用户界面(UI)的模块,它是Qt框架的一部分。Qt Quick 的主要目标是提供一种高效、灵活且易于使用的方式来开发动态的、具有丰富动画效果的界面。
基于QML和JS。能够创建自定义组件、动画、交互元素的工具及API。