Qt学习日记 Day8:事件系统

今天学了什么

今天学习Qt事件系统。

Qt事件系统

① 定义:操作系统或Qt框架生成事件对象,按规则分发给对应控件处理,实现用户交互与状态响应。

② 事件分类(按触发来源):

  • 用户操作触发:鼠标、键盘、拖放事件(人操作才产生);
  • 系统自动触发:paintEvent、resizeEvent、closeEvent、timerEvent、焦点、鼠标进出等(状态变化自动发出,无需持续操作);

③ 事件的5种处理方式:

  • 重写专属事件函数(最常用)

mousePressEvent、keyPressEvent、paintEvent等,在类内重写虚函数

  • 重写event()总入口

在分到专属函数前拦截,经典场景:捕获Tab键;

  • 局部事件过滤器

控件->installEventFilter(监视器),只监听指定控件;

必须重写eventFilter;

  • 全局事件过滤器

qApp->installEventFilter(监视器),监听整个应用所有控件;

必须重写eventFilter,开销更大

  • 重写QApplication::notify()

事件分发最顶层入口,权限最高,业务开发极少使用;

事件流经顺序(从先到后):

notify() → 全局过滤器 → 局部过滤器 → event() → 专属xxxEvent;

注:

  • 过滤器返回值:return true 拦截事件;
  • 返回父类eventFilter,事件继续分发;
  • 重写键盘事件时,焦点在子控件,主窗口keyPressEvent收不到键盘事件,使用全局过滤器解决(局部也可以,但全局更通用);

补充:

setFocusPolicy:设置控件获取键盘焦点的策略(也可解决主窗口keyPressEvent收不到键盘事件);

绘图规范:拖拽橡皮筋画线,mouseMove更新终点+update(),绘图必须写在paintEvent

Qt常用事件

鼠标事件:

  • mousePressEvent 鼠标按下

一般在这里记录起点,开启拖拽、橡皮筋绘图;

  • mouseMoveEvent 鼠标移动

默认按住鼠标才会触发;

想鼠标不按触发,在构造函数里面写 setMouseTracking();

更新坐标,调用update()触发重绘;

  • mouseReleaseEvent 鼠标松开

拖拽结束,保存最终图形,结束标记;

  • mouseDoubleClickEvent 鼠标双击

区分单击双击,注意不要和单击冲突;

键盘事件:

  • keyPressEvent 按键按下

焦点在哪,键盘事件给谁;

子控件抢焦点后主窗口收不到;

Tab默认切换焦点,需要在event()拦截;

  • keyReleaseEvent 按键松开

少用,多用于组合键检测;

绘图事件:

  • paintEvent 绘图事件

所有自定义绘图必须写在这里;

不能在mouseMove里直接new QPainter绘图;

调用update()触发,不要手动调用paintEvent;

大小、位置变化:

  • resizeEvent 控件大小改变

窗口拉伸、控件缩放时自动触发,可重新布局;

  • moveEvent 控件位置移动

控件坐标改变触发;

窗口相关:

  • closeEvent 窗口关闭

用e->ignore()阻止关闭;e->accept()允许关闭;

  • showEvent 窗口显示

窗口第一次弹出/从隐藏到显示触发;

  • hideEvent 窗口隐藏

窗口被隐藏时触发;

焦点事件:

  • focusInEvent 获取键盘焦点

控件拿到焦点,可以接收键盘输入;

  • focusOutEvent 失去键盘焦点

焦点被别的控件抢走后触发;

鼠标进出控件:

  • enterEvent 鼠标进入控件区域

鼠标一进控件就触发,不需要点击;

  • leaveEvent 鼠标离开控件区域

鼠标移出控件触发,常用于样式变化;

定时器事件:

两种定时器方案:

① 重写timerEvent(基础原生,startTimer启动)

  • timerEvent 定时器事件

基础定时器,区别QTimer;

需要startTimer开启;

② QTimer类(信号槽方式,项目更常用);

拖放事件:

Qt拖放(Drag & Drop):支持用鼠标拖拽数据,从一个控件拖动到另一个控件,实现数据传输的交互机制;

分为两个阶段:拖动发起(Drag)、放下接收(Drop);

  • dragEnterEvent

当拖拽的东西刚进入目标控件区域时触发;

必须在这里判断能不能接收该类型数据;

调用event->acceptProposedAction()允许继续拖入,否则无法放下;

  • dragMoveEvent

拖拽过程中,鼠标在目标控件内移动持续触发;

可控制鼠标样式、限定可放置区域;

  • dragLeaveEvent

拖拽的鼠标移出目标控件区域触发。

  • dropEvent

鼠标松开,完成放下的那一刻触发(核心,在这里取出拖拽的数据,完成业务处理);

发起拖拽(拖动源):一般在mousePressEvent或mouseMoveEvent中构造QDrag对象,启动拖拽。

基础使用步骤:

目标控件(接收拖拽的控件):

① 开启属性:setAcceptDrops(true); 【必须写!不写接收不到拖放事件】

② 重写4个拖放事件:dragEnterEvent、dragMoveEvent、dragLeaveEvent、dropEvent

拖拽源(被拖动的控件)在鼠标事件里创建QDrag,封装要传递的数据(QMimeData),调用

exec()启动拖拽。

注:

① 普通事件和closeEvent accept()/ignore()区别:

普通事件(鼠标、键盘等,控制事件冒泡传递)

  • ignore():事件继续向上传递,交给父控件继续处理
  • accept():事件到此处理完毕,不再继续往上传递(默认)

closeEvent(特例,专门控制窗口关闭是否放行,是特殊用法)

  • accept():同意本次关闭,继续执行窗口关闭流程
  • ignore():拒绝本次关闭,直接终止关闭,窗口不关闭

② 重写专属事件函数和重写event()使用时机:

  • 有专属事件虚函数,就重写xxxEvent;
  • 没有专属函数 / 要拦截Tab / 需要在分发前统一处理,才重写event();

③ 区分【事件】和【信号槽】:

信号槽是对象通信机制,不属于事件处理的5种方式;

事件是系统或应用状态变化的通知,触发源不同;

相关推荐
xianghongtao01161 小时前
04_ToM2Vec_解读报告
1024程序员节
夕除1 小时前
redis--IO 内核
1024程序员节
handsome_sai1 小时前
mysql索引
sql·1024程序员节
灵境(虚幻知音)1 小时前
华为超节点系统对军事体系仿真分布式计算的需求影响与技术路线变革研究
1024程序员节
Oiiouui1 小时前
针对Godot-GridGame(网格游戏)的DI注入+RefCounted数据驱动信号流架构设计的研究(全程开源)
游戏·游戏引擎·godot·1024程序员节
坤坤子吖1 小时前
C++继承:友元、静态成员、多继承与组合
开发语言·c++·笔记·学习·1024程序员节
科学熊1 小时前
OBS Studio 新手入门
1024程序员节
贵州诚鑫致达科技有限公司1 小时前
PHP两个9.2分RCE漏洞,速查版本
服务器·php·1024程序员节
漫天转悠2 小时前
Vue3白屏排查实录-Transition与多根模板
vue.js·1024程序员节