Qt事件传递及相关的性能问题

这篇具有很好参考价值的文章主要介绍了Qt事件传递及相关的性能问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在使用Qt时,我们都知道能通过mousePressEvent,eventFilter等虚函数的重写来处理事件,那么当我们向一个界面发送事件,控件和它的父控件之间的事件传递过程是什么样的呢?
本文将以下图所示界面为例,结合源码介绍Qt事件传递的过程。
父到子的关系依次为:
MyWindow->MyButton->MyEdit。
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化

在启动程序后,用鼠标点击一下MyEdit,下面是事件传递的过程。

第一步、QCoreApplication(qApp)处理事件

过程

qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
这里最后接收点击事件的是最上层的控件,也就是本例中的MyEdit。

相关源码

源码按执行顺序来排列。
qwindowsysteminterface.cpp->QWindowSystemInterface::sendWindowSystemEvents
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
qapplication->QApplicationPrivate::notify_helper
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
qwidgetwindow->QWidgetWindow::handleMouseEvent
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
childAt的过程:
1、遍历MyWindow的子控件,找到包含了点击坐标的MyButton。
2、遍历MyButton的子控件,找到包含了点击坐标的MyEdit。
3、遍历MyEdit的子控件,没找到子控件,返回MyEdit。

第二步、控件处理事件

过程

qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
流程看起来有点复杂,用文字来表示就是以下几点:
1、每个控件处理事件时会先执行qApp安装的事件过滤器,即qApp->installEventFilter安装的。然后执行自己安装的事件过滤器,即this->installEventFilter安装的,最后才是事件处理,如mousePressEvent等。
2、控件在处理事件时可以用setAccepted来设置事件是否被吸收,如果setAccepted(true),那么这个事件不会被传递到父控件中去。
3、事件处理是从子控件开始依次传递到各级父控件的。
4、事件过滤器返回true和e->setAccepted(true)都可以阻断事件往父控件传递,但在事件过滤器中设置e->setAccepted并不能阻止当前控件的事件处理。

相关源码

qapplication->QApplication::notify
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
qapplication->QApplicationPrivate::notify_helper
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化

总结

Qt的事件传递大致就上述说的两步,因为要介绍里面的一些细节,所以看起没那么直观,这里写一个示意的代码来说明整个流程。
现有appFilter(obj, e)和widgetFilter(obj, e)事件过滤器,分别被qApp和各个控件安装。

void handle(systemEvent)
{
    e = toEvent(systemEvent); //转换为QEvent

    /* qApp的事件过滤 */
    if (appFilter(systemEvent.qApp, e) == true)
        return;

    w = qApp.m_widget.childAt(e.pos());  //获取MyEdit

    while (w)
    {
        /* 事件过滤 */
        if (appFilter(w, e) == true)
            break;
        if (widgetFilter(w, e) == true)
            break;

        w.event(e); //事件处理

        /* 判断事件是否被接收 */
        if (e.isAccept())
            break;

        w = w.parentWidget();
    }
}

相关的性能问题

从上面给出的例子可以看到,我们点击一个控件时,会有两个步骤。
1、Qt会先从窗口找到MyWindow,再从MyWindow找到MyButton,再从MyButton找到MyEdit。
2、找到MyEdit后,会执行MyEdit的事件过滤,事件处理,然后依次对MyButton和MyWindow做同样的操作。
这两个步骤带来了一些性能的问题。
1、找MyEdit的过程是递归的,带来了函数栈的开销。
2、如果MyEdit的父控件确实需要处理点击事件,那么多次调用事件过滤,事件处理是有必要的,但是如果传递的是绘图事件呢?当一个子控件接收到绘图事件,这个事件也会被传递给它的父控件们,而想要提升UI的性能,减少不必要的刷新是一个方向。

我们做一个测试,在MyWindow中做以下修改。
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
放置多个QFrame控件嵌套在一起。
创建一个MyButton控件,分别对比它作为frame_14和窗口的子控件时执行update的耗时。

update本质上是发送绘图事件来重回控件。

界面中的按钮绑定槽。

void MyWindow::on_pushButton_clicked()
{
    QElapsedTimer timer;
    timer.start();

    for (int i = 0; i < 1000000; ++i)
        button->update();

    qDebug() << "cost time: " << timer.elapsed() << "ms";
}

测试结果:
作为窗口子控件时:
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
作为frame_14的子控件时:
qt事件在窗口传递的顺序,Qt笔记,qt,ui,开发语言,事件传递,性能优化
可以看出差别是很大的。
所以我们在设计UI架构时,应避免出现层次过多的情况。文章来源地址https://www.toymoban.com/news/detail-819560.html

到了这里,关于Qt事件传递及相关的性能问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 1.2.1 Qt中事件是如何进行传递——实例篇(下)

    1.2.1 Qt中事件是如何进行传递 1.2.2 Qt中的事件过滤器(eventFilter) 1.2.3 如何自己模拟发送事件消息 上一篇中我们讲解了Qt中的事件,通过流程图给大家展示了事件的传递过程,今天就通过代码来给大家实操一下,验证流程图的走向。 EventTestWgt.h EventTestWgt.cpp 图一:事件传递流

    2024年02月13日
    浏览(33)
  • Qt获取鼠标移动事件,窗口内任意位置按下鼠标左键拖动窗口

    重写窗口的两个事件函数mousePressEvent和mouseMoveEvent即可: 在mousePressEvent 中,按下鼠标左键时,记录窗口坐标,其中窗口坐标的计算是由鼠标事件获取到鼠标在整个屏幕中的坐标(ev-globalpos()),然后再使用pos()获取到鼠标在窗口内的相对位置,两者之差就是窗口在整个屏幕上

    2024年02月12日
    浏览(42)
  • Qt窗口设置无边框不能移动,鼠标穿透后不能响应点击事件

      最近在做一个迷你小工具,准备干点不可描述的事情,想要短小强悍,始终在最顶层显示,同时不要自带的关闭按钮和边框,百度一下,发现是需要设置如下两个属性:   那么问题来了,这样的话一运行窗体就在正中间,而且无法拖动,就像这样   哪怕对于我这种

    2024年02月10日
    浏览(47)
  • 【Qt UI相关】Qt中如何控制 窗口的最大化、最小化和关闭按钮?一文带你掌握用法

    窗口的最大化、最小化和关闭按钮通常是由操作系统的窗口管理器控制的,而不是由应用程序控制的。这些按钮的行为(例如点击最大化按钮会将窗口的大小调整为屏幕的大小)是由窗口管理器实现的,应用程序通常不能改变这些行为。 在 Qt 中,你可以通过 QWidget::setWindow

    2024年02月11日
    浏览(31)
  • 【Qt学习笔记】☞窗口插入图片

    零基础Qt实现简易音视频播放器(包括可能出现的问题+解决方法)-QT文档类资源-CSDN文库         上边链接是利用Qt实现的简易音视频播放器,在主窗口开始页面使用汉字描述播放器名称,为了更美观的展示播放器主页面,可以在播放器的开始页面插入图片。 Qt中没有Image组件

    2024年02月06日
    浏览(29)
  • Qt 自定义窗口的标题栏,重写鼠标事件实现,关闭隐藏,最大化/最小化,重写窗口事件函数,实现鼠标选中边框拉大拉小,双击标题栏切换窗口最大化和最小化

    Qt 自定义窗口的标题栏,重写鼠标事件实现,关闭隐藏,最大化/最小化,重写窗口事件函数,实现鼠标选中边框拉大拉小,双击标题栏切换窗口最大化和最小化 1、main.cpp 2、widget.h 3、widget.cpp 4、效果展示 5、完成

    2024年02月16日
    浏览(47)
  • qt解决信号和槽连接时传递额外参数的问题

    QSignalMapper 是 Qt 框架中的一个类,用于解决信号和槽连接时传递额外参数的问题。当一个信号被触发时,QSignalMapper 可以将该信号与一个特定的参数关联起来,并将信号与对应的槽函数进行连接。 下面是关于 QSignalMapper 的一些详细解释: 1.作用: QSignalMapper 类的主要作用是在一

    2024年02月07日
    浏览(29)
  • Qt知识笔记(八)—— 鼠标和事件

    默认情况下,触发事件需要点击一下,才能触发。可设置为自动触发: setMouseTracking(true); 鼠标事件有单机,双击,释放,移动,滑轮 单机:void mousePressEvent(QMouseEvent *event); 双击:void mouseDoubleClickEvent(QMouseEvent *event); 释放:void mouseReleaseEvent(QMouseEvent *event); 移动:void mouseMove

    2024年02月16日
    浏览(51)
  • 06-5_Qt 5.9 C++开发指南_Splash 与登录窗口(MouseEvent鼠标事件;注册表;加密)

    一般的大型应用程序在启动时会显示一个启动画面,即 Splash 窗口。Splash 窗口是一个无边对话框,一般显示一个图片,展示软件的信息。Splash 窗口显示时,程序在后台做一些比较耗时的启动准备工作,Splash 窗口显示一段时间后自动关闭,然后软件的主窗口显示出来。Qt有一个

    2024年02月13日
    浏览(36)
  • Qt透明窗口鼠标穿透问题及解决办法

    最近写了个项目,需要播放视频并在视频上做标记框去完成一些功能 因为视频播放使用了 VLC-qt 的库,封装好的窗口控件 没办法直接在该视频窗口上绘图(也许可以?) 出于不想动别人写好的库的想法,想着在视频窗口上加一个透明蒙版-即一个透明窗口,在透明窗口上进行

    2024年02月04日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包