一、事件处理基本流程

在Qt中,所有从QObject派生的类都能处理事件。事件处理的核心流程如下:

  1. 事件入口函数

    bool QObject::event(QEvent *e)
    
    • 参数e包含事件信息,通过e->type()获取事件类型

    • 返回值true表示事件已被处理,false表示未处理

  2. 事件响应控制

    e->accept();  // 接受事件,阻止传播
    e->ignore();  // 忽略事件,继续向父组件传播
  3. 事件传播机制

二、QWidget常用事件处理函数

QWidget预定义了针对特定事件类型的虚函数(均可重写):

事件类型

处理函数

参数类型

鼠标移动

mouseMoveEvent()QMouseEvent*

鼠标点击

mousePressEvent()QMouseEvent*

鼠标释放

mouseReleaseEvent()QMouseEvent*

键盘按下

keyPressEvent()QKeyEvent*

绘制事件

paintEvent()QPaintEvent*

窗口大小变化

resizeEvent()QResizeEvent*

焦点变化

focusInEvent()QFocusEvent*

三、代码示例:自定义窗口事件处理

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>// 自定义窗口类
class MyWindow : public QWidget {
public:MyWindow(QWidget *parent = nullptr) : QWidget(parent) {setWindowTitle("Qt事件处理示例");resize(400, 300);}protected:// 1. 绘制事件 - 绘制背景void paintEvent(QPaintEvent *event) override {QPainter painter(this);// 绘制渐变背景QLinearGradient gradient(0, 0, width(), height());gradient.setColorAt(0, Qt::cyan);gradient.setColorAt(1, Qt::blue);painter.fillRect(rect(), gradient);// 绘制文本painter.setPen(Qt::white);painter.setFont(QFont("Arial", 24));painter.drawText(rect(), Qt::AlignCenter, "点击窗口查看事件日志");}// 2. 鼠标点击事件void mousePressEvent(QMouseEvent *event) override {QString button;switch(event->button()) {case Qt::LeftButton: button = "左键"; break;case Qt::RightButton: button = "右键"; break;case Qt::MiddleButton: button = "中键"; break;default: button = "未知按键";}qDebug() << "鼠标点击: " << button << " 位置: (" << event->x() << "," << event->y() << ")";// 接受事件,阻止传播event->accept();}// 3. 键盘事件void keyPressEvent(QKeyEvent *event) override {qDebug() << "按键按下: " << event->text()<< " 键码: " << event->key();// ESC键关闭窗口if(event->key() == Qt::Key_Escape) {close();}}// 4. 窗口大小变化事件void resizeEvent(QResizeEvent *event) override {qDebug() << "窗口大小变化: " << event->oldSize() << " -> " << event->size();}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);MyWindow window;window.show();return app.exec();
}

四、关键机制解析

  • 事件处理优先级
// 事件分发伪代码
bool QWidget::event(QEvent *e) {switch(e->type()) {case QEvent::MouseButtonPress:mousePressEvent(static_cast<QMouseEvent*>(e));return true;case QEvent::Paint:paintEvent(static_cast<QPaintEvent*>(e));return true;// ...其他事件类型default:return QObject::event(e);}
}
  • 事件传播控制
void MyWidget::mousePressEvent(QMouseEvent *e) {if(shouldHandle(e)) {// 自定义处理逻辑e->accept();  // 事件终止传播} else {e->ignore();  // 事件传递给父组件}
}
  • 自定义事件处理建议
    • 优先重写特定事件处理函数(如mouseMoveEvent
    • 需要处理特殊事件类型时重写event()函数
    • 在事件处理函数中避免耗时操作

五、运行效果说明

  1. 窗口显示渐变背景和居中文本

  2. 鼠标点击输出日志:
    鼠标点击: 左键 位置: (120,80)
    鼠标点击: 右键 位置: (200,150)
    
  3. 键盘按键显示字符和键码

  4. 调整窗口大小时输出尺寸变化

  5. 按ESC键关闭窗口

最佳实践:对于需要精细控制事件流的场景(如游戏开发),可在event()函数中进行统一事件分发,结合event->type()dynamic_cast实现多类型事件处理。

六、事件的接受与忽略

//!!! Qt5
// ---------- custombutton.h ----------
classCustomButton:publicQPushButton{Q_OBJECT
public:
CustomButton(QWidget *parent =0);
private:
voidonButtonCliecked();
};// ---------- custombutton.cpp ----------
CustomButton::CustomButton(QWidget *parent):QPushButton(parent){
connect(this,&CustomButton::clicked,this,&CustomButton::onButtonCliecked);
}voidCustomButton::onButtonCliecked(){
qDebug()<<"You clicked this!";
}// ---------- main.cpp ----------
intmain(int argc,char*argv[]){QApplication a(argc, argv);CustomButton btn;btn.setText("This is a Button!");btn.show();
return a.exec();
}

这段代码的运行结果是:点击按钮,会在控制台打印出"You clicked this!"字符串。

重写事件函数

下面我们向CustomButton类添加一个事件函数:

// CustomButton ...
protected:
voidmousePressEvent(QMouseEvent *event);
...// ---------- custombutton.cpp ----------
...
voidCustomButton::mousePressEvent(QMouseEvent *event)
{if(event->button()== Qt::LeftButton){qDebug()<<"left";}else{QPushButton::mousePressEvent(event);}
}

重写mousePressEvent()函数后:

  1. 当鼠标按下的是左键,打印"left"字符串

  2. 否则调用父类的同名函数

  3. 此时"You clicked this!"字符串不再出现

重要注意事项

  1. 事件传递机制

    • 当重写事件回调函数时,必须注意是否需要调用父类的同名函数

    • 如果完全覆盖父类函数,可能导致原有功能失效(如clicked()信号不会发出)

  2. accept()和ignore()函数

    • accept():告诉Qt这个类想要处理这个事件

    • ignore():告诉Qt这个类不想要处理这个事件

    • 可以使用isAccepted()查询事件是否已被接收

  3. 默认行为

    • 事件对象默认是accept的

    • QWidget的默认实现是调用ignore()

    • 不调用父类实现等同于接受事件

    • 调用父类实现等同于忽略事件

事件传播示例

classCustomButton:publicQPushButton{Q_OBJECT
public:CustomButton(QWidget *parent):QPushButton(parent){}
protected:voidmousePressEvent(QMouseEvent *event){qDebug()<<"CustomButton";}
};classCustomButtonEx:publicCustomButton{Q_OBJECT
public:CustomButtonEx(QWidget *parent):CustomButton(parent){}
protected:voidmousePressEvent(QMouseEvent *event){qDebug()<<"CustomButtonEx";}
};classCustomWidget:publicQWidget{Q_OBJECT
public:CustomWidget(QWidget *parent):QWidget(parent){}
protected:voidmousePressEvent(QMouseEvent *event){qDebug()<<"CustomWidget";}
};classMainWindow:publicQMainWindow{Q_OBJECT
public:
MainWindow(QWidget *parent =0):QMainWindow(parent){CustomWidget *widget =newCustomWidget(this);CustomButton *cbex =newCustomButton(widget);cbex->setText(tr("CustomButton"));CustomButtonEx *cb =newCustomButtonEx(widget);cb->setText(tr("CustomButtonEx"));QVBoxLayout *widgetLayout =newQVBoxLayout(widget);widgetLayout->addWidget(cbex);widgetLayout->addWidget(cb);this->setCentralWidget(widget);
}
protected:voidmousePressEvent(QMouseEvent *event){qDebug()<<"MainWindow";}
};

测试结果:

  1. 默认情况下输出"CustomButtonEx"
  2. 添加event->ignore()后输出"CustomButtonEx CustomWidget"
  3. 在CustomWidget中添加QWidget::mousePressEvent(event)后输出"CustomButtonEx CustomWidget MainWindow"

特殊应用场景:窗口关闭事件

//!!! Qt5
...
textEdit =newQTextEdit(this);
setCentralWidget(textEdit);
connect(textEdit,&QTextEdit::textChanged,[=](){this->setWindowModified(true);});
setWindowTitle("TextPad [*]");
...voidMainWindow::closeEvent(QCloseEvent *event){if(isWindowModified()){bool exit =QMessageBox::question(this,tr("Quit"),tr("Are you sure to quit this application?"),QMessageBox::Yes | QMessageBox::No,QMessageBox::No)== QMessageBox::Yes;if(exit){event->accept();}else{event->ignore();}}else{event->accept();}
}

关键点:

  1. setWindowTitle()使用"[]"语法表示修改状态
  2. 重写closeEvent()处理关闭事件
  3. accept()会关闭窗口,ignore()会阻止关闭

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/93901.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/93901.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/93901.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zynq中级开发七项必修课-第三课:S_AXI_GP0 主动访问 PS 地址空间

Zynq中级开发七项必修课-第三课&#xff1a;S_AXI_GP0 主动访问 PS 地址空间 目标1.0 编写 AXI-Lite Master&#xff1a;按键计数 → 写入 PS 内存1.1 PL 触发中断 → PS 响应并串口打印按键计数值BD图axi_lite_master.v // // AXI4-Lite Simple Master (single-shot, non-pip…

CVPR | 2025 | MAP:通过掩码自回归预训练释放混合 Mamba - Transformer 视觉骨干网络的潜力

文章目录CVPR | 2025 | MAP&#xff1a;通过掩码自回归预训练释放混合 Mamba - Transformer 视觉骨干网络的潜力创新点初步研究初步结论方法确定一个混合网络方法掩码机制掩码比例MAP的transformer解码器重建目标实验ImageNet-1k 上的 2D 分类CVPR | 2025 | MAP&#xff1a;通过…

Spring Boot + Spring AI 最小可运行 Demo

一. 项目依赖&#xff08;pom.xml&#xff09;<project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0https://maven.apache.org/xsd/mav…

AI重塑校园教育:中小学AI智慧课堂定制方案+AI作业批改减负,告别一刀切学生进步快

家长们&#xff0c;你有没有听过孩子抱怨上学的烦恼&#xff1f;课堂上老师讲的内容&#xff0c;有的同学觉得太简单 “吃不饱”&#xff0c;有的却跟不上 “听不懂”&#xff1b;放学后作业堆成山&#xff0c;老师要熬夜批改到半夜&#xff0c;错题反馈要等第二天才能拿到&…

旧物循环,交易新生——旧物回收二手交易小程序,引领绿色消费新风尚

在资源日益紧张、环境污染问题日益突出的今天&#xff0c;绿色消费已经成为时代发展的必然趋势。旧物回收二手交易小程序&#xff0c;作为绿色消费的重要载体&#xff0c;正以其独特的优势和魅力&#xff0c;引领着一场关于旧物循环、交易新生的绿色革命。一、旧物循环&#xf…

刷机维修进阶教程-----如何清除云账号 修复wifi 指南针 相机 指纹等刷机故障

在刷机、系统升级或降级过程中,是否遇到过以下问题:WiFi无法开启、相机无响应、指南针或陀螺仪失灵 指纹等故障?另外,云账号是否仍会保留,即使通过9008模式刷机也无法彻底清除?那么这篇博文都可以找到答案。 通过博文了解💝💝💝 1💝💝💝----云账号信息分区如…

AI翻唱实战:用[灵龙AI API]玩转AI翻唱 – 第6篇

历史文章 [灵龙AI API] 申请访问令牌 - 第1篇 [灵龙AI API] AI生成视频API&#xff1a;文生视频 – 第2篇 图生视频实战&#xff1a;用[灵龙AI API]玩转AI生成视频 – 第2篇&#xff0c;从静图到大片 单图特效实战&#xff1a;用[灵龙AI API]玩转AI生成视频 – 第3篇&#…

大模型0基础开发入门与实践:第11章 进阶:LangChain与外部工具调用

第11章 进阶&#xff1a;LangChain与外部工具调用 1. 引言 在上一章&#xff0c;我们成功地创造了我们的第一个“生命”——一个可以对话的机器人。我们为它的诞生而兴奋&#xff0c;但很快我们就会发现它的局限性。它就像一个被囚禁在玻璃房中的天才大脑&#xff0c;拥有渊博…

SQL 日期处理:深入解析与高效实践

SQL 日期处理&#xff1a;深入解析与高效实践 引言 在数据库管理中&#xff0c;日期和时间数据的处理是不可或缺的一部分。SQL&#xff08;结构化查询语言&#xff09;提供了丰富的日期和时间函数&#xff0c;使得对日期的处理变得既灵活又高效。本文将深入探讨SQL日期处理的相…

源代码部署 LAMP 架构

源代码部署 LAMP 架构 &#xff08;Linux Apache MySQL PHP&#xff09; 一、LAMP 架构概述 LAMP 是一套经典的开源 Web 服务架构&#xff0c;通过源代码安装可实现高度定制化&#xff0c;适用于对软件版本、功能模块有特定需求的场景。本指南基于 CentOS 7 系统&#xf…

GO环境变量中GO111MODULE到底是干啥的?

查看GO111MODULE变量GO111MODULE的作用GO111MODULE的案例演示 一&#xff0c;查看GO111MODULE变量 ]# go env GO111MODULE 或者 ]# go env | grep GO111MODULE二&#xff0c;GO111MODULE的作用 auto : 自动判断机制 当项目位于 $GOPATH/src 目录外且包含 go.mod 文件时&…

在线培训机构如何降低培训视频被盗录的风险

每一节精心录制的培训视频&#xff0c;都凝聚着讲师的心血与机构的巨大投入。然而&#xff0c;只需一个简单的录屏软件&#xff0c;这一切都可能被轻易窃取。一旦被盗取&#xff0c;不但会损失经济利益&#xff0c;还可能会影响机构的声誉。那么&#xff0c;在线培训机构如何降…

Docker:安装配置

目录一、卸载旧版本二、配置Docker的yum库三、安装Docker3.1 在线安装方式3.2 离线安装方式四、配置阿里云镜像加速【选配】五、Docker服务相关命令六、导出和导入镜像官网 一、卸载旧版本 首先如果系统中已经存在旧版本的Docker&#xff0c;则先卸载&#xff1a; yum remov…

RabbitMQ:SpringAMQP 入门案例

目录一、概述二、基础配置三、生产者四、消费者一、概述 这是一篇Java集成RabbitMQ的入门案例&#xff0c;在这里我们做一个小案例&#xff0c;来体会一下RabbitMQ的魅力。 首先我们要做的就是创建一个生产者一个消费者&#xff1a; 生产者直接向RabbitMQ的队列&#xff08;Q…

Ubuntu 下面安装搜狗输入法debug记录

目录0. 整体安装流程1. 在键盘输入法系统中&#xff0c;没有“fcitx”选项解决方法0. 整体安装流程 详细的Ubuntu搜狗输入法安装指南请参考官方教程&#xff1a;Ubuntu搜狗输入法安装指南 1. 在键盘输入法系统中&#xff0c;没有“fcitx”选项 即使是安装完 fcitx&#xff0…

Jenkins+GitLab在CentOS7上的自动化部署方案

最近在安装jenkins实现微服务的自动发布&#xff0c;记录配置过程以免再次踩坑。 Centos7环境准备 jenkins、gitlab配置&#xff0c;全程使用ftpuser普通用户操作 &#xff08;1&#xff09;安装好jdk并配置好环境变量 安装路径/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.…

打开或者安装Navicat时出现Missing required library libcurl.dll,126报错解决方法(libmysql_e.dll等)

提示 Missing required library libcurl.dll 出现原因是由于Navicat安装目录下libcurl.dll可能不能用了&#xff0c;下载该文件放到Navicat安装目录下即可。下载地址&#xff1a;libcurl.dll — download free for Windows 下载解压包里只有个libcurl.dll 提示 Missing requir…

基于SpringBoot的流浪动物领养管理系统【2026最新】

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

Qt实现TabWidget通过addTab函数添加的页,页内控件自适应窗口大小

前言&#xff1a;因为项目的要求&#xff0c;需要把几个不同类型功能的界面集成在同一个窗口中&#xff0c;方便用户不切换窗口&#xff0c;也能快捷的操作不同类型的功能。我首先想到的是通过选项卡方式&#xff0c;让几个类别的功能界面通过不同选项卡进行切换&#xff0c;这…

代码随想录算法训练营27天 | ​​56. 合并区间、738.单调递增的数字、968.监控二叉树(提高)

题目链接&#xff1a;56. 合并区间、738.单调递增的数字、968.监控二叉树 文章链接&#xff1a;代码随想录 贪心算法 1. 合并区间 &#xff08;待更新...&#xff09; class Solution { private:static bool cmp(const vector<int>& a, const vector<int>&…