QT开发:深入详解QtCore模块事件处理,一文学懂QT 事件循环与处理机制
Qt 是一个跨平台的 C++ 应用程序框架,QtCore 模块提供了核心的非 GUI 功能。事件处理是 Qt 应用程序的重要组成部分。Qt 的事件处理机制包括事件循环和事件处理,它们共同确保应用程序能够响应用户输入、定时器事件和其他事件。
1. 事件循环(Event Loop)
Qt 的事件循环是一个无限循环,它从操作系统获取事件并分发给应用程序中的合适对象。事件循环由 QCoreApplication 或其子类(如 QApplication)管理。
2. 事件对象(Event Object)
Qt 使用 QEvent 类及其子类来封装事件信息。例如,QMouseEvent 用于鼠标事件,QKeyEvent 用于键盘事件。每个事件类型都有一个唯一的类型标识符。
3. 事件处理(Event Handling)
事件处理包括两个核心部分:事件过滤(Event Filtering)和事件处理(Event Handling)。Qt 提供了几个机制来处理事件:
- 事件过滤器(Event Filters):可以在事件到达目标对象之前拦截事件。
- 事件处理器(Event Handlers):对象可以通过重写特定的事件处理方法来处理事件。
4. 事件循环的实现
以下是事件循环的基本实现:
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 创建一个定时器,定时发出超时信号并退出应用程序QTimer::singleShot(5000, &a, &QCoreApplication::quit);qDebug() << "Event loop starting.";// 进入事件循环int ret = a.exec();qDebug() << "Event loop exited.";return ret;
}
5. 事件处理机制
下面是一个详细的事件处理示例,包含自定义事件、事件过滤器和事件处理器。
自定义事件
首先,我们定义一个自定义事件:
#include <QEvent>
#include <QString>// 自定义事件类,继承自 QEvent
class MyCustomEvent : public QEvent {
public:// 定义一个唯一的事件类型static const QEvent::Type MyEventType = static_cast<QEvent::Type>(QEvent::User + 1);// 构造函数,接受一个消息字符串MyCustomEvent(const QString &message): QEvent(MyEventType), message(message) {}// 获取消息QString getMessage() const { return message; }private:QString message; // 事件携带的消息
};
自定义对象
接下来,创建一个自定义对象,重写 event() 函数来处理自定义事件:
#include <QObject>
#include <QDebug>// 自定义对象类,继承自 QObject
class MyObject : public QObject {Q_OBJECTprotected:// 重写 event() 方法,处理自定义事件bool event(QEvent *event) override {if (event->type() == MyCustomEvent::MyEventType) {MyCustomEvent *myEvent = static_cast<MyCustomEvent*>(event);qDebug() << "Custom event received with message:" << myEvent->getMessage();return true; // 事件已处理}return QObject::event(event); // 传递给父类处理}
};
事件过滤器
创建一个事件过滤器类:
#include <QObject>
#include <QEvent>
#include <QDebug>// 自定义事件过滤器类,继承自 QObject
class MyEventFilter : public QObject {Q_OBJECTprotected:// 重写 eventFilter() 方法,过滤自定义事件bool eventFilter(QObject *obj, QEvent *event) override {if (event->type() == MyCustomEvent::MyEventType) {MyCustomEvent *myEvent = static_cast<MyCustomEvent*>(event);qDebug() << "Event filter caught custom event with message:" << myEvent->getMessage();return true; // 阻止事件进一步传播}return QObject::eventFilter(obj, event); // 传递给父类处理}
};
主程序
最后,在主程序中使用这些类:
#include <QCoreApplication>
#include <QTimer>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);MyObject obj;MyEventFilter filter;// 安装事件过滤器obj.installEventFilter(&filter);// 创建并发送自定义事件MyCustomEvent *event = new MyCustomEvent("Hello, Qt!");QCoreApplication::postEvent(&obj, event);// 创建一个定时器,定时退出应用程序QTimer::singleShot(5000, &a, &QCoreApplication::quit);return a.exec(); // 进入事件循环
}
注释与总结
QCoreApplication:管理事件循环。QEvent:所有事件的基类,自定义事件继承自QEvent。event():重写此方法以处理特定事件。eventFilter():重写此方法以在事件到达目标对象之前拦截事件。postEvent():将事件放入事件队列中。singleShot():创建一个单次定时器,用于触发事件或动作。通过以上示例,我们详细展示了 Qt 中事件循环和事件处理的基本机制。
事件循环的应用场景
Qt 事件循环在各种应用场景中都有广泛应用,包括 GUI 应用程序、定时任务、异步操作、并发处理、自定义事件、数据库操作和文件 I/O 等。以下是一些具体的应用场景和对应的示例代码:
1. GUI 应用程序
在 GUI 应用程序中,事件循环用于捕获和处理用户交互事件,如鼠标点击、键盘输入、窗口移动和调整大小等。
#include <QApplication>
#include <QPushButton>int main(int argc, char *argv[])
{QApplication app(argc, argv);// 创建一个按钮QPushButton button("Hello, Qt!");button.show();// 进入事件循环return app.exec();
}
2. 定时任务
Qt 提供了定时器功能,通过 QTimer 类可以设置定时任务。事件循环会捕获定时器的超时事件,并调用预设的槽函数。
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);QTimer timer;QObject::connect(&timer, &QTimer::timeout, [](){qDebug() << "Timer timeout!";});timer.start(1000); // 每隔一秒触发一次return app.exec(); // 进入事件循环
}
3. 异步操作
Qt 的 QNetworkAccessManager 提供了对网络请求的支持。通过事件循环处理网络请求的响应,避免了阻塞主线程。
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QUrl>
#include <QDebug>int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);QNetworkAccessManager manager;QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("https://www.qt.io")));QObject::connect(reply, &QNetworkReply::finished, [=]() {qDebug() << "Network request finished";qDebug() << reply->readAll();reply->deleteLater();app.quit();});return app.exec(); // 进入事件循环
}
4. 并发处理
Qt 提供了多线程支持,通过事件循环可以实现线程间的通信。例如,主线程和工作线程之间的信号和槽连接。
#include <QCoreApplication>
#include <QThread>
#include <QDebug>class Worker : public QObject {Q_OBJECT
public slots:void doWork() {qDebug() << "Work done in thread:" << QThread::currentThread();}
};int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);QThread workerThread;Worker worker;worker.moveToThread(&workerThread);QObject::connect(&workerThread, &QThread::started, &worker, &Worker::doWork);QObject::connect(&worker, &Worker::doWork, &app, &QCoreApplication::quit);workerThread.start();return app.exec(); // 进入事件循环
}#include "main.moc"
5. 自定义事件
除了 Qt 提供的标准事件类型,用户也可以定义自己的事件类型,并在事件循环中处理它们。
#include <QCoreApplication>
#include <QEvent>
#include <QDebug>class MyCustomEvent : public QEvent {
public:static const QEvent::Type MyEventType = static_cast<QEvent::Type>(QEvent::User + 1);MyCustomEvent(const QString &message) : QEvent(MyEventType), message(message) {}QString getMessage() const { return message; }private:QString message;
};class MyObject : public QObject {Q_OBJECT
protected:bool event(QEvent *event) override {if (event->type() == MyCustomEvent::MyEventType) {MyCustomEvent *myEvent = static_cast<MyCustomEvent*>(event);qDebug() << "Custom event received with message:" << myEvent->getMessage();return true;}return QObject::event(event);}
};int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);MyObject obj;MyCustomEvent *event = new MyCustomEvent("Hello, Custom Event!");QCoreApplication::postEvent(&obj, event);QTimer::singleShot(2000, &app, &QCoreApplication::quit); // 定时退出应用程序return app.exec(); // 进入事件循环
}#include "main.moc"
6. 数据库操作
通过事件循环,可以在不阻塞用户界面的情况下执行数据库查询。需要将查询操作放到另一个线程中执行。
#include <QCoreApplication>
#include <QtSql>
#include <QDebug>
#include <QThread>class DbWorker : public QObject {Q_OBJECT
public:void runQuery() {QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName(":memory:");if (!db.open()) {emit error("Failed to open database");return;}QSqlQuery query;query.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");query.exec("INSERT INTO test (value) VALUES ('Hello, Database')");QSqlQuery asyncQuery(db);asyncQuery.exec("SELECT value FROM test WHERE id=1");if (asyncQuery.next()) {emit resultReady(asyncQuery.value(0).toString());} else {emit error("Query failed");}}signals:void resultReady(const QString &result);void error(const QString &errMsg);
};int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);QThread workerThread;DbWorker worker;worker.moveToThread(&workerThread);QObject::connect(&workerThread, &QThread::started, &worker, &DbWorker::runQuery);QObject::connect(&worker, &DbWorker::resultReady, [&](const QString &result) {qDebug() << "Query result:" << result;workerThread.quit();});QObject::connect(&worker, &DbWorker::error, [&](const QString &errMsg) {qDebug() << errMsg;workerThread.quit();});QObject::connect(&workerThread, &QThread::finished, &app, &QCoreApplication::quit);workerThread.start();return app.exec(); // 进入事件循环
}#include "main.moc"
7. 文件 I/O 操作
通过事件循环,可以在不阻塞用户界面的情况下读取或写入文件。需要将文件读取操作放到另一个线程中执行。
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QThread>class FileWorker : public QObject {Q_OBJECT
public:FileWorker(const QString &filePath) : filePath(filePath) {}public slots:void doWork() {QFile file(filePath);if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {emit error("Failed to open file");return;}QTextStream in(&file);QString content = in.readAll();file.close();emit fileRead(content);}signals:void fileRead(const QString &content);void error(const QString &errMsg);private:QString filePath;
};int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);QThread workerThread;FileWorker worker("test.txt");worker.moveToThread(&workerThread);QObject::connect(&workerThread, &QThread::started, &worker, &FileWorker::doWork);QObject::connect(&worker, &FileWorker::fileRead, [&](const QString &content) {qDebug() << "File content:" << content;workerThread.quit(); // 文件读取完成后退出线程});QObject::connect(&worker, &FileWorker::error, [&](const QString &errMsg) {qDebug() << errMsg;workerThread.quit(); // 发生错误时退出线程});QObject::connect(&workerThread, &QThread::finished, &app, &QCoreApplication::quit);workerThread.start();return app.exec(); // 进入事件循环
}#include "main.moc"
总结
Qt 事件循环广泛应用于各种场景,如 GUI 应用程序的用户交互、定时任务、网络通信、并发处理、自定义事件、异步数据库查询和异步文件 I/O 等。通过合理利用事件循环,可以确保应用程序在处理各种事件时高效、顺畅地运行。希望这些示例能帮助你更好地理解 QtCore 模块中的事件处理机制及其应用场景。
相关文章:
QT开发:深入详解QtCore模块事件处理,一文学懂QT 事件循环与处理机制
Qt 是一个跨平台的 C 应用程序框架,QtCore 模块提供了核心的非 GUI 功能。事件处理是 Qt 应用程序的重要组成部分。Qt 的事件处理机制包括事件循环和事件处理,它们共同确保应用程序能够响应用户输入、定时器事件和其他事件。 1. 事件循环(Ev…...
小米,B站网络安全岗位笔试题目+答案
《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…...
微信小程序中巧妙使用 wx:if 和 catchtouchmove 实现弹窗禁止页面滑动功能
大家好,今天我要和大家分享的是在微信小程序开发过程中,如何利用 wx:if 或 wx:elif 来条件性地渲染不同的元素,并结合 catchtouchmove 事件处理函数来解决弹窗弹出时禁止背后页面滑动,而弹窗消失时恢复滑动的功能。 在微信小程序…...
唯徳知识产权管理系统 DownloadFileWordTemplate 文件读取漏洞复现
0x01 产品简介 唯徳知识产权管理系统,由深圳市唯德科创信息有限公司精心打造,旨在为企业及代理机构提供全方位、高效、安全的知识产权管理解决方案。该系统集成了专利、商标、版权等知识产权的全面管理功能,并通过云平台实现远程在线办公,提升工作效率。是一款集知识产权申…...
我在高职教STM32——准备HAL库工程模板(2)
新学期已开始,又要给学生上 STM32 嵌入式课程了。这课上了多年了,一直用的都是标准库来开发,已经驾轻就熟了。人就是这样,有了自己熟悉的舒适圈,就很难做出改变,老师上课也是如此,排斥新课和不熟悉的内容。显然,STM32 的开发,HAL 库已是主流,自己其实也在使用,只不过…...
数字化转型的实战法则:全面剖析《数字化专业知识体系》中的落地策略与最佳实践
开启数字化成功的实践路径 随着全球经济加速迈向数字化,企业不再仅仅依赖传统商业模式,而是通过技术创新提升竞争力与市场地位。然而,数字化转型的成功不仅依赖于战略思维,更需要精准的实战执行。《数字化专业知识体系》…...
远程桌面内网穿透是什么?有什么作用?
远程桌面内网穿透指的是通过特定技术手段,将处于内网中的电脑或服务器,通过外部网络(互联网)进行访问。内网穿透的主要作用是解决在内网环境下,远程设备与外部互联网之间的连接问题,允许用户从外部访问内网…...
【算法专场】分治(上)
目录 前言 什么是分治? 75. 颜色分类 算法分析 算法步骤 算法代码 912. 排序数组 - 力扣(LeetCode) 算法分析 算法步骤 算法代码 215. 数组中的第K个最大元素 - 力扣(LeetCode) 算法分析 算法步骤 编辑…...
腾讯云软件工程师面试问题收集记录-数据库
SQL是什么:结构化查询语言,是一种专门用于管理关系型数据库管理系统的编程语言 MySQL操作命令 数据库操作 登陆数据库:mysql -u 用户面 -p创建数据库:CREATE DATABASE testdb; SQLite操作命令 数据库操作 创建数据库:…...
Sourcetree安装教程及使用
下载链接:源代码树 |适用于 Mac 和 Windows 的免费 Git GUI (sourcetreeapp.com) Sourcetree安装教程及使用_sourcetree 安装使用-CSDN博客...
TryHackMe 第1天 | Introduction to Cyber Security
偶然之间了解到了TryHackMe这个网站,尝试跟着其中的学习路径进行学习,发现还是挺适合入门网络安全这一领域的。但是这个网站包含了很多内容,如果不用一些东西记录下来,那么很容易忘记,所以打算在此记录一下学习过程。 …...
ASP.NET MVC 迅速集成 SignalR
在现代 Web 应用程序中,实时更新数据是一个常见需求。本文将详细介绍如何在 ASP.NET MVC 项目中使用 SignalR 实现定时任务操作数据库并将数据更新到网页。我们将逐步讲解如何配置 SignalR、创建定时任务、操作数据库以及在前端显示实时数据。 目录 项目初始化安装…...
[数据集][目标检测]葡萄成熟度检测数据集VOC+YOLO格式1123张3类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):1123 标注数量(xml文件个数):1123 标注数量(txt文件个数):1123 标注…...
【Python 数据分析学习】Matplotlib 的基础和应用
题目 1 Matplotlib 主要特性2 Matplotlib 基础知识2.1 导入模块2.2 图形构成2.2.1 图形(Figure)2.2.2 轴 (Axes)2.2.3 轴线(axis) 2.5 中文设置2.5.1 借助rcParams修改字体实现设置2.5.2 增加一个fontprope…...
HarmonyOS应用开发者基础认证
目录 一、判断二、单选三、多选 一、判断 1、HarmonyOS提供了基础的应用加固安全能力,包括混淆、加密和代码签名能力。正确 2、可以通过ohpm uninstall 指令下载指定的三方库。错误 3、支持模块化开发是指一个应用通常会包含多种功能,将不同的功能特性…...
gin基本使用
中文文档:https://gin-gonic.com/zh-cn/docs/ 下载和安装gin模块 go get -u github.com/gin-gonic/gin简单接口demo package mainimport "github.com/gin-gonic/gin"func main() {r := gin.Default() // 创建一个默认的路由引擎r.GET("/pin…...
【VUE】pinia持久化存储
前言:状态持久化存储的意义在于它能够确保用户在与应用程序交互时,其操作状态、用户偏好、应用数据等关键信息在页面刷新、浏览器关闭或重新启动后依然得以保留,从而提供连贯、无缝的用户体验,避免因状态丢失导致的不便和重复操作…...
【Java基础】泛型
文章目录 泛型一、概述二、泛型的使用1、类2、方法3、接口 三、泛型通配符1、<?>2、<? extends T>3、<? super T> 四、泛型的擦除1、泛型的擦除2、泛型边界的擦除3、无法实例化泛型类型 泛型 一、概述 泛型(Generic)是一种机制&a…...
STL-vector练习题
118. 杨辉三角 思路: 杨辉三角有以下性质使我们要用到的: ● 每行数字左右对称,由 1 开始逐渐变大再变小,并最终回到 1。 ● 第 n 行(从 0 开始编号)的数字有 n1 项,前 n 行共有 2n(n1)个数。…...
Leetcode 165. 比较版本号(Medium)
给你两个 版本号字符串 version1 和 version2 ,请你比较它们。版本号由被点 . 分开的修订号组成。修订号的值 是它 转换为整数 并忽略前导零。 比较版本号时,请按 从左到右的顺序 依次比较它们的修订号。如果其中一个版本字符串的修订号较少,…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
