MFC转QT:Qt高级特性 - 事件系统(mfc读取txt文件每一行数据)
ccwgpt 2025-06-30 15:01 4 浏览 0 评论
Qt事件处理机制
Qt的事件系统是整个框架的核心基础之一,负责处理用户输入、窗口系统消息和应用内部的通信。相比MFC的消息映射系统,Qt的事件处理机制更加灵活和直观。
基本概念
事件(Event) 是Qt框架中传递应用状态变化信息的对象,从QEvent基类派生。事件包括:
- 用户输入事件:鼠标点击、键盘按键、触摸手势等
- 窗口系统事件:窗口重绘、大小改变、焦点变化等
- 应用程序事件:定时器、网络通信、自定义事件等
事件循环(Event Loop) 是Qt应用程序的核心运行机制,负责:
- 从操作系统获取事件
- 将事件分发给相应的Qt对象
- 等待下一个事件的到来
事件分发过程
Qt事件系统的工作流程:
- 用户操作或系统生成事件
- QApplication收集事件并放入事件队列
- 事件循环从队列中提取事件
- 事件传递给目标对象的event()方法
- 对象根据事件类型调用特定的事件处理函数
- 事件处理完毕,控制返回事件循环
与MFC消息循环的区别
MFC和Qt的事件处理有明显区别:
特性 | Qt事件系统 | MFC消息系统 |
基本单位 | 事件对象(QEvent子类) | 消息(MSG结构) |
传递机制 | 对象树层次传递 | 窗口过程链传递 |
处理方式 | 虚函数重写 | 消息映射宏(MESSAGE_MAP) |
参数传递 | 事件对象包含全部信息 | wParam/lParam传递有限信息 |
分发控制 | 可在任何级别接受/忽略 | 主要在目标窗口处理 |
自定义扩展 | 创建自定义事件类 | 自定义消息ID |
跨平台能力 | 完全跨平台一致 | 仅限Windows平台 |
事件处理器
Qt提供多种处理事件的方式,比MFC的消息映射更加灵活。
事件处理器函数
每种常见事件类型都有对应的虚函数处理器:
class MyWidget : public QWidget
{
Q_OBJECT
protected:
// 窗口绘制事件
void paintEvent(QPaintEvent *event) override {
QPainter painter(this);
painter.drawText(rect(), Qt::AlignCenter, "Hello Qt!");
}
// 鼠标按下事件
void mousePressEvent(QMouseEvent *event) override {
if (event->button() == Qt::LeftButton) {
qDebug() << "Left button pressed at" << event->pos();
}
}
// 按键事件
void keyPressEvent(QKeyEvent *event) override {
if (event->key() == Qt::Key_Escape) {
close();
}
}
// 调整大小事件
void resizeEvent(QResizeEvent *event) override {
qDebug() << "Resized from" << event->oldSize() << "to" << event->size();
}
// 焦点变化事件
void focusInEvent(QFocusEvent *event) override {
qDebug() << "Widget gained focus";
}
void focusOutEvent(QFocusEvent *event) override {
qDebug() << "Widget lost focus";
}
};
常见事件处理器对照表
Qt事件处理器 | MFC对应处理 | 说明 |
paintEvent() | OnPaint() | 绘制窗口内容 |
mousePressEvent() | OnLButtonDown()等 | 鼠标按下(Qt单个函数处理所有按钮) |
mouseReleaseEvent() | OnLButtonUp()等 | 鼠标释放 |
mouseMoveEvent() | OnMouseMove() | 鼠标移动 |
keyPressEvent() | OnKeyDown() | 按键按下 |
keyReleaseEvent() | OnKeyUp() | 按键释放 |
resizeEvent() | OnSize() | 窗口大小改变 |
moveEvent() | OnMove() | 窗口位置改变 |
closeEvent() | OnClose() | 窗口关闭 |
showEvent() | OnShowWindow() | 窗口显示 |
hideEvent() | OnShowWindow() | 窗口隐藏 |
focusInEvent() | OnSetFocus() | 获得焦点 |
focusOutEvent() | OnKillFocus() | 失去焦点 |
wheelEvent() | OnMouseWheel() | 鼠标滚轮 |
dragEnterEvent() | OnDragEnter() | 拖放进入 |
dropEvent() | OnDrop() | 拖放放置 |
contextMenuEvent() | OnContextMenu() | 上下文菜单 |
enterEvent() | OnMouseEnter() | 鼠标进入 |
leaveEvent() | OnMouseLeave() | 鼠标离开 |
重写event()方法
除了特定的事件处理器,还可以重写通用的event()方法处理多种事件:
class MyWidget : public QWidget
{
Q_OBJECT
protected:
bool event(QEvent *event) override {
switch (event->type()) {
case QEvent::KeyPress: {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Tab) {
// 自定义Tab键处理
customTabHandler();
return true; // 事件已处理
}
break;
}
case QEvent::ToolTip: {
QHelpEvent *helpEvent = static_cast<QHelpEvent*>(event);
QToolTip::showText(helpEvent->globalPos(),
"Custom tooltip at " + QString::number(helpEvent->pos().x()));
return true;
}
// 其他事件类型处理...
}
// 对于未处理的事件,调用基类实现
return QWidget::event(event);
}
private:
void customTabHandler() {
// 自定义Tab键处理逻辑
}
};
重写event()方法适合以下情况:
- 需要处理多种不常见事件类型
- 需要在标准事件处理前拦截事件
- 需要改变默认事件处理行为
事件过滤器
事件过滤器是Qt特有的强大机制,允许一个对象监视和处理发送给另一个对象的事件。这在MFC中没有直接对应物,是Qt事件系统的重要优势。
安装事件过滤器
class MyWindow : public QMainWindow
{
Q_OBJECT
public:
MyWindow() {
// 创建文本编辑器
textEdit = new QTextEdit(this);
setCentralWidget(textEdit);
// 安装事件过滤器
textEdit->installEventFilter(this);
}
protected:
// 事件过滤器实现
bool eventFilter(QObject *watched, QEvent *event) override {
// 确认是我们关注的对象
if (watched == textEdit) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
// 禁止输入数字
if (keyEvent->key() >= Qt::Key_0 && keyEvent->key() <= Qt::Key_9) {
// 显示消息
statusBar()->showMessage("数字输入已禁用", 2000);
return true; // 阻止事件继续传递
}
}
}
// 其他情况调用基类实现
return QMainWindow::eventFilter(watched, event);
}
private:
QTextEdit *textEdit;
};
全局事件过滤器
通过在QApplication上安装事件过滤器,可以监视和处理应用程序范围的事件:
class GlobalEventFilter : public QObject
{
Q_OBJECT
public:
GlobalEventFilter(QObject *parent = nullptr) : QObject(parent) {}
protected:
bool eventFilter(QObject *watched, QEvent *event) override {
// 监视所有鼠标事件
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
qDebug() << "全局监视到鼠标点击:"
<< "对象:" << watched->objectName()
<< "位置:" << mouseEvent->pos();
}
// 监视窗口关闭事件
if (event->type() == QEvent::Close && watched->isWidgetType()) {
QWidget *widget = static_cast<QWidget*>(watched);
qDebug() << "窗口即将关闭:" << widget->windowTitle();
// 可以记录日志或执行其他操作...
}
// 不阻止事件继续传递
return false;
}
};
// 在main函数中安装全局事件过滤器
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
GlobalEventFilter *globalFilter = new GlobalEventFilter(&app);
app.installEventFilter(globalFilter);
MainWindow w;
w.show();
return app.exec();
}
事件过滤器用途
事件过滤器特别适合以下场景:
- 修改第三方控件行为,而无需子类化
- 实现自定义输入验证,如限制特定类型输入
- 全局键盘快捷键处理或热键系统
- 调试和记录事件流
- 实现复杂鼠标手势或多步骤交互
- 为多个控件提供一致的自定义行为
自定义事件
Qt允许创建和发送自定义事件,这比MFC的自定义消息更加灵活和类型安全。
定义自定义事件类型
// 在头文件中定义事件类型
namespace MyEvents {
enum {
StatusUpdate = QEvent::User + 1,
DataChange = QEvent::User + 2,
NetworkStatus = QEvent::User + 3
};
}
// 创建自定义事件类
class StatusUpdateEvent : public QEvent
{
public:
StatusUpdateEvent(const QString &status)
: QEvent(QEvent::Type(MyEvents::StatusUpdate)),
m_status(status)
{}
QString status() const { return m_status; }
private:
QString m_status;
};
class DataChangeEvent : public QEvent
{
public:
DataChangeEvent(int dataId, const QVariant &newValue)
: QEvent(QEvent::Type(MyEvents::DataChange)),
m_dataId(dataId),
m_newValue(newValue)
{}
int dataId() const { return m_dataId; }
QVariant newValue() const { return m_newValue; }
private:
int m_dataId;
QVariant m_newValue;
};
发送和处理自定义事件
// 发送自定义事件
void DataManager::updateData(int dataId, const QVariant &value)
{
// 更新内部数据
m_data[dataId] = value;
// 创建并发送自定义事件通知所有监听器
DataChangeEvent *event = new DataChangeEvent(dataId, value);
QCoreApplication::postEvent(m_eventReceiver, event);
// 也可以直接发送事件(同步处理)
// QCoreApplication::sendEvent(m_eventReceiver, event);
}
// 处理自定义事件
bool MyWidget::event(QEvent *event)
{
if (event->type() == MyEvents::DataChange) {
DataChangeEvent *dataEvent = static_cast<DataChangeEvent*>(event);
qDebug() << "收到数据变更:"
<< "ID:" << dataEvent->dataId()
<< "新值:" << dataEvent->newValue();
// 更新UI或执行其他操作
updateUI(dataEvent->dataId(), dataEvent->newValue());
return true;
}
if (event->type() == MyEvents::StatusUpdate) {
StatusUpdateEvent *statusEvent = static_cast<StatusUpdateEvent*>(event);
statusBar()->showMessage(statusEvent->status());
return true;
}
return QWidget::event(event);
}
sendEvent vs postEvent
Qt提供两种分发事件的方法,各有用途:
方法 | 行为 | 使用场景 |
QCoreApplication::sendEvent() | 同步,直接调用目标的event()方法 | 需要立即处理,或需要返回值 |
QCoreApplication::postEvent() | 异步,将事件放入队列后返回 | 非阻塞通知,跨线程事件分发 |
// 同步发送 - 立即处理
bool success = QCoreApplication::sendEvent(receiver, event);
// 可以检查事件处理结果
// 异步投递 - 稍后处理
QCoreApplication::postEvent(receiver, event);
// 函数立即返回,事件稍后处理
与MFC消息循环的区别
事件传递路径
MFC消息传递主要基于窗口层次,而Qt基于对象层次:
MFC消息传递:
- Windows消息队列 → 应用程序消息泵
- TranslateMessage/DispatchMessage
- 窗口过程 → 子窗口过程 → 默认窗口过程
- CWnd::WindowProc → CWnd::OnWndMsg
- 消息映射宏处理特定消息
Qt事件传递:
- 平台原生事件 → Qt事件转换 → QEvent子类
- QCoreApplication::notify()
- 目标QObject::event()方法
- 特定事件处理器(如mouseEvent())
- 父对象链传递(如果未处理)
事件接受与忽略
Qt提供了接受和忽略事件的明确机制:
// 子类中处理事件
void MyWidget::mousePressEvent(QMouseEvent *event)
{
if (canHandleClick(event->pos())) {
// 处理点击
doSomething();
// 标记事件已处理(阻止传播)
event->accept();
} else {
// 让父类或父控件处理
event->ignore();
// 显式调用基类实现
QWidget::mousePressEvent(event);
}
}
这种显式接受/忽略机制比MFC的返回值模式更加清晰。
事件捕获与冒泡
Qt事件系统支持类似DOM事件的捕获和冒泡阶段:
- 捕获阶段:事件首先传递给应用程序,然后沿着父对象链向下传递到目标
- 目标阶段:事件到达目标对象
- 冒泡阶段:如果事件未被处理,沿着父对象链向上冒泡
这种机制可以通过事件过滤器和事件传播控制实现复杂的事件处理逻辑。
从MFC迁移到Qt事件系统的技巧
思维转换
- 从消息ID到事件类型
- MFC中通过消息ID(WM_XXX)识别消息
- Qt中通过QEvent子类和QEvent::Type枚举识别事件
- 从映射宏到虚函数
- MFC使用BEGIN_MESSAGE_MAP/END_MESSAGE_MAP宏
- Qt重写特定的虚函数如mousePressEvent()
- 从WPARAM/LPARAM到事件对象
- MFC通过消息参数传递信息
- Qt通过类型化的事件对象提供完整上下文
常见消息映射的转换
MFC消息处理器到Qt事件处理器的映射示例:
// MFC
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_SIZE()
ON_COMMAND(ID_FILE_OPEN, &CMyView::OnFileOpen)
END_MESSAGE_MAP()
void CMyView::OnPaint() {
CPaintDC dc(this);
// 绘制代码...
}
void CMyView::OnLButtonDown(UINT nFlags, CPoint point) {
// 处理鼠标点击...
}
void CMyView::OnSize(UINT nType, int cx, int cy) {
// 处理大小变化...
}
void CMyView::OnFileOpen() {
// 处理菜单命令...
}
// Qt等效代码
class MyView : public QWidget
{
Q_OBJECT
protected:
void paintEvent(QPaintEvent *event) override {
QPainter painter(this);
// 绘制代码...
}
void mousePressEvent(QMouseEvent *event) override {
if (event->button() == Qt::LeftButton) {
// 处理鼠标点击...
}
}
void resizeEvent(QResizeEvent *event) override {
// 处理大小变化...
}
private slots:
void onFileOpen() {
// 处理菜单动作...
}
};
// 在构造函数中连接菜单动作
MyView::MyView() {
QAction *openAction = new QAction("打开", this);
connect(openAction, &QAction::triggered, this, &MyView::onFileOpen);
}
功能等效实现
常见MFC功能在Qt事件系统中的实现方式:
MFC功能 | Qt实现方式 |
预处理消息 | 重写event()方法或使用事件过滤器 |
ON_UPDATE_COMMAND_UI | 使用QAction的setEnabled/setChecked和触发器 |
鼠标捕获 | QWidget::grabMouse() |
自定义绘制 | 重写paintEvent()并使用QPainter |
定时器消息 | 使用QTimer和信号槽 |
空闲处理 | 使用QTimer::singleShot()和0毫秒超时 |
PreTranslateMessage | 使用全局事件过滤器 |
拖放操作 | 使用dragEnterEvent/dropEvent等拖放事件 |
异步消息 | 使用postEvent()或信号槽 |
相关推荐
- Xtreme套件Xtreme Suite Pro正式发布v17.0.0
-
Codejock软件公司的Xtreme套件(XtremeSuite)包含了三种流行的组件:Xtreme命令工具栏(XtremeCommandBars)——把需要创建的具有改进对接算法的所有组件...
- Wine能不能跑Win程序?信创操作系统下运行Windows应用的条件!
-
原文链接:「链接」Hello,大家好啊,今天给大家带来一篇信创操作系统上使用Wine运行Windows应用程序的条件的文章,欢迎大家分享点赞,点个在看和关注吧!在日常使用国产信创操作系统(如统...
- VC界面开发组件Xtreme Toolkit Pro全新发布v17.0.0
-
Codejock软件公司的XtremeToolkitPro是屡获殊荣的VC界面库,是MFC开发中最全面界面控件套包,它提供了Windows开发所需要的11种主流的VisualC++MFC控件,...
- 机器视觉软件开发新人入门必看 --机器视觉软件开发学习路径
-
机器视觉是机械、运动、控制、光学、软件、算法于一体的交叉学科,对于学工科的人来说,机械、运动、控制都有一定的了解,对于软件、算法、光学不是很了解。一台设备,有一个到二个机械设计师或者结构工程师,那么这...
- 数控变频器的研究与实现(数控变频器的研究与实现思考题)
-
一般变频器具有两种控制方式:控制面板控制方式和串行通信数据控制方式。控制面板控制方式利用变频器自带控制面板进行手动操控,一般应用于非自动控制场合。在自动化程度越来越高的工业生产现场以及机电一体化的数控...
- 实用 | 分享几个非常实用的开源项目
-
前言本次分享几个实用的、值得学习使用的嵌入式相关开源项目,下面列举的这些基本上都在本公众号分享过,详细介绍及使用可查看往期笔记。protobufProtocolBuffers,是Google公司开发...
- Windows桌面应用程序常用开发框架的设计案例全面展示
-
Windows桌面应用程序是我们日常生活中不可或缺的一部分,而开发这些应用程序需要使用相应的框架。本文将全面介绍常用的Windows桌面应用程序开发框架,帮助您了解并选择适合的开发工具。一、原生的Wi...
- .NET9 FCall/QCall调用约定(.net 调用存储过程)
-
蓝字江湖评谈设为关注前言FCall/Qcall是托管与非托管之间的调用约定,双方需要一个契约,以弥合彼此的互相/单向调用。非托管调用约定先了解下非托管约定,一般有四种,分别为thiscall,std...
- BCGControlBar Pro for MFC v24.4正式发布
-
BCGControlBar(BusinessComponentsGalleryControlBar)专业版是MFC的一个扩展库,您可以用来构建类似于MicrosoftOffice2000/X...
- MFC多文档视图(mfc 多文档)
-
你可以因为现任不好而分手,但千万不要认为别人更好,永远有人更好,眼下便是更好。。。----网易云热评一、多文档视图架构程序1、特点:可以管理多个文档。(可以有多个文档类对象)2、相关类CWinA...
- MFC扩展库BCGControlBar Pro v33.5新版亮点:Ribbon Bar等全新升级
-
BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。我们的组件可以轻松地集成到您的应用程序中,并为您节省数百个开发和调试时间。BCGControlBar专业版v3...
- 山东新华电脑学院4G软件专业明星优秀作品展
-
项目实战工程师:向修艺年龄:18岁班级:4G软件1501班座右铭:付出才会有收获导师寄语:自学能力和实践能力都非常出色,并且学习认真做事责任心强,是不可多得的人才。相信将来如果能获得机会,发挥自己的...
- MFC转QT:Qt基础知识(mfc获取当前日期和时间信息)
-
1.Qt框架概述Qt的历史和版本Qt是一个跨平台的C++应用程序开发框架,由挪威公司Trolltech(现为QtCompany)于1991年创建。Qt的发展历程:1991年:Qt项目启动1995年...
- MFC转QT:Qt高级特性 - 事件系统(mfc读取txt文件每一行数据)
-
Qt事件处理机制Qt的事件系统是整个框架的核心基础之一,负责处理用户输入、窗口系统消息和应用内部的通信。相比MFC的消息映射系统,Qt的事件处理机制更加灵活和直观。基本概念事件(Event)是Qt框...
- MFC用户界面套包BCGControlBar Pro for MFC发布v25.0
-
BCGControlBar(BusinessComponentsGalleryControlBar)专业版是MFC的一个扩展库,您可以用来构建类似于MicrosoftOffice2000/X...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Xtreme套件Xtreme Suite Pro正式发布v17.0.0
- Wine能不能跑Win程序?信创操作系统下运行Windows应用的条件!
- VC界面开发组件Xtreme Toolkit Pro全新发布v17.0.0
- 机器视觉软件开发新人入门必看 --机器视觉软件开发学习路径
- 数控变频器的研究与实现(数控变频器的研究与实现思考题)
- 实用 | 分享几个非常实用的开源项目
- Windows桌面应用程序常用开发框架的设计案例全面展示
- .NET9 FCall/QCall调用约定(.net 调用存储过程)
- BCGControlBar Pro for MFC v24.4正式发布
- MFC多文档视图(mfc 多文档)
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- JAVA集合框架 (47)
- mfc框架 (52)
- grpc框架 (55)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)