多线程场景下,使用QEventLoop使界面不卡顿的同时过滤用户输入

背景描述

有耗时的操作需要放到子线程中处理,但是此过程中不允许界面执行其他操作,不能使用阻塞界面的模态对话框实现。
可以通过QEventLoop在子线程执行的同时开启一个事件循环,使UI界面不卡顿,能够正常响应。但是这种不卡顿只是鼠标滑动时UI可以流畅的变化,界面没有变成卡顿状态,此时不会执行鼠标点击或者键盘输入等用户输入的事件,否则会影响子线程中正在执行的操作。

QEventLoop说明

1.exec函数

int QEventLoop::exec(QEventLoop::ProcessEventsFlags flags = AllEvents)Enters the main event loop and waits until exit() is called. 
进入主事件循环并等待,直到exit()被调用。If flags are specified, only events of the types allowed by the flags will be processed.
如果指定了标志,则只处理标志允许的类型的事件。
It is necessary to call this function to start event handling. 
必须调用此函数来启动事件处理。
The main event loop receives events from the window system and dispatches these to the application widgets.
主事件循环从窗口系统接收事件,并将这些事件分发给应用程序小部件。
Generally speaking, no user interaction can take place before calling exec(). 
一般来说,在调用exec()之前不能进行任何用户交互。
As a special case, modal widgets like QMessageBox can be used before calling exec(), because modal widgets use their own local event loop.
作为一种特殊情况,像QMessageBox这样的模态小部件可以在调用exec()之前使用,因为模态小部件使用它们自己的本地事件循环。
参数描述
QEventLoop::AllEvents所有事件。注意,对DeferredDelete事件进行了特殊处理。参见QObject::deleteLater()了解更多细节。
QEventLoop::ExcludeUserInputEvents不处理用户输入事件,如ButtonPress和KeyPress。但是请注意,事件不会被丢弃;它们将在下一次不带excludeuserinputtevents标志的processEvents()被调用时传递。
QEventLoop::ExcludeSocketNotifiers不处理套接字通知事件。请注意,事件不会被丢弃;它们将在下一次不带ExcludeSocketNotifiers标志的processEvents()被调用时传递。
QEventLoop::WaitForMoreEvents如果没有挂起的事件可用,则等待事件。

通过exec函数开始事件循环,此函数默认参数是处理所有事件,使用其它参数也不会丢弃用户输入事件,如果在时间循环期间用户点击了按钮,在事件循环结束后就会执行点击按钮的操作,所以此时还无法做到过滤用户输入,需要添加额外处理。

使用事件过滤器过滤用户输入

  1. 给应用程序对象的全局指针qApp安装事件过滤器
  2. 使用eventloop来监听应用程序的所有事件,重写eventloop的eventFilter函数从而实现过滤某些输入事件的效果
  3. 退出事件循环后,回收eventloop对象,移除事件过滤器

eventFilter函数说明

virtual bool eventFilter(QObject *watched, QEvent *event);

  • 如果返回true,表示事件过滤,不会发送到对象本身
  • 如果返回false,表示事件未过滤,会通过event()方法将事件分发到对象。
  • 返回给基类进行处理,例:return QObject::eventFilter(obj, event)。

代码实现

继承QEventLoop类,重写exec,eventFilter,deleteLater函数

// 头文件
#include <QEventLoop>class CCustomEventLoop : public QEventLoop
{Q_OBJECTpublic:CCustomEventLoop(QObject* parent = nullptr);~CCustomEventLoop();int exec(ProcessEventsFlags flags = AllEvents);void deleteLater();virtual bool eventFilter(QObject*, QEvent* event);private:bool m_bUiThread = false;
};
// 源文件
#include "customeventloop.h"#include <QCoreApplication>
#include <QEvent>
#include <QThread>CCustomEventLoop::CCustomEventLoop(QObject* parent) : QEventLoop(parent)
{
}CCustomEventLoop::~CCustomEventLoop()
{
}int CCustomEventLoop::exec(ProcessEventsFlags flags)
{//判断当前线程是否为UI线程,此时才需要安装事件过滤器if (qApp->thread() == QThread::currentThread()) {// 给qApp安装事件过滤器,eventloop对象监听应用程序的所有事件qApp->installEventFilter(this);m_bUiThread = true;}return QEventLoop::exec(flags);
}void CCustomEventLoop::deleteLater()
{if (m_bUiThread){// 回收eventloop对象时移除qApp的事件过滤器qApp->removeEventFilter(this);}return QEventLoop::deleteLater();
}bool CCustomEventLoop::eventFilter(QObject* , QEvent* event)
{// 过滤用户输入事件:鼠标、键盘、快捷键if (event->type() == QEvent::MouseButtonPress ||event->type() == QEvent::MouseButtonRelease ||event->type() == QEvent::MouseButtonDblClick ||event->type() == QEvent::KeyPress ||event->type() == QEvent::KeyRelease ||event->type() == QEvent::Shortcut ||event->type() == QEvent::ShortcutOverride ||event->type() == QEvent::FocusIn ||event->type() == QEvent::FocusOut ||event->type() == QEvent::Wheel){return true;}return false;
}

使用方法

CCustomEventLoop *eventLoop = new CCustomEventLoop();
QtConcurrent::run([&]()mutable{// 1. 执行耗时操作...// 2. 执行完耗时操作后退出事件循环eventLoop->exit();
});
eventLoop->exec(); // 程序会在此处阻塞,直到执行exit()才会继续执行。UI不会卡顿。
eventLoop->deleteLater();
eventLoop = nullptr;
// 继续执行其他操作...

参考

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

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

相关文章

【Python进阶】继承进阶和私有权限

目录 一、继承进阶 1、方法重写 2、调用父类方法 3、多层继承 二、私有权限 1、私有属性 2、私有方法 面向对象基础&#xff1a;小白也能看懂的Python基础教程&#xff08;8&#xff09;-CSDN博客 一、继承进阶 1、方法重写 当父类的同名方法达不到子类的要求&#x…

阿里云上kubesphere安装配置 - 使用阿里云负载均衡

教程参考 https://www.kubesphere.io/zh/docs/v3.3/installing-on-linux/public-cloud/install-kubesphere-on-ali-ecs/ 环境配置 关闭防火墙关闭selinux关闭swap分区时间同步hosts解析内核参数设置检查DNS安装ipvs安装依赖组件安装、设置docker每台机器都需要操作 #安装工具…

crossJoin笛卡尔积

crossJoin笛卡尔积 在Spark中&#xff0c;crossJoin方法用于执行两个数据集之间的笛卡尔积操作。具体来说&#xff0c;如果有两个数据集&#xff08;DataFrame或Dataset&#xff09;&#xff0c;调用crossJoin方法将会生成一个新的数据集&#xff0c;其中包含两个原始数据集中所…

Monaco 中添加 CodeLens

CodeLens 会在指定代码行上添加一行可点击的文字&#xff0c;点击时可以触发定义的命令&#xff0c;效果如下&#xff1a; 通过调用 API 注册 LensProvider&#xff0c;点击时触发 Command&#xff0c;首先要注册命令&#xff0c;通过 editor.addCommand () 方法进行注册。三个…

7月9日学习打卡-回文链表,交叉链表

大家好呀&#xff0c;本博客目的在于记录暑假学习打卡&#xff0c;后续会整理成一个专栏&#xff0c;主要打算在暑假学习完数据结构&#xff0c;因此会发一些相关的数据结构实现的博客和一些刷的题&#xff0c;个人学习使用&#xff0c;也希望大家多多支持&#xff0c;有不足之…

python使用tkinter添加下载进度UI

添加进度组件 def download(): # 创建下载进度框progress_window tk.Toplevel()progress_window.title("下载进度")progress_label tk.Label(progress_window, text"正在下载视频文件...")progress_label.pack(pady10)progress_bar ttk.Progre…

【微信小程序开发实战项目】——个人中心页面的制作

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

canvas高清绘制与retina屏

一、retina屏 视网膜显示屏&#xff08;英语&#xff1a;Retina Display&#xff09;是一种由苹果公司设计和委托制造的现实屏幕&#xff0c;具备足够高像素密度而使得人体肉眼无法分辨其中单独像素点的液晶屏幕。 比如&#xff0c;初期Retina屏幕的分辨率为640960&#xff0…

在 PostgreSQL 里如何处理数据的版本跟踪和回滚?

文章目录 一、事务二、保存点三、使用版本控制扩展四、审计表和触发器五、使用时间戳列六、比较和还原数据七、考虑数据备份和恢复八、结论 在数据库管理中&#xff0c;数据的版本跟踪和回滚是非常重要的功能&#xff0c;有助于在数据操作出现错误或需要回滚到特定状态时进行有…

HINet: Half Instance Normalization Network for Image Restoration

论文&#xff1a;HINet: Half Instance Normalization Network for Image Restoration Abstract&#xff1a; 在本文中&#xff0c;我们探讨了实例归一化在低级视觉任务中的作用。 具体来说&#xff0c;我们提出了一个新颖的块&#xff1a;半实例归一化块&#xff08;HIN 块&…

洛谷 数学进制 7.9

P1100 高低位交换 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码一 #include<bits/stdc.h> using namespace std; typedef long long ll; #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)const ll N1e510; char a[N];int main() {IOS;ll a;int b[32]…

十分钟且一次性带你学懂泛型编程思想(模板化思想)

引言 在编程的世界里&#xff0c;泛型编程思想&#xff08;模板化思想&#xff09;是一种极具魅力的编程范式。它允许我们编写出具有高度通用性和可重用性的代码&#xff0c;极大地提高了开发效率和代码质量。无论你是初学者还是有一定经验的开发者&#xff0c;掌握泛型编程思想…

GNU/Linux - 什么是loopback设备

在计算机科学中&#xff0c;特别是在类Unix操作系统中&#xff0c;环回设备&#xff08;loopback device&#xff09;是一种虚拟设备&#xff0c;它将一个文件映射为块设备。这使得可以像访问物理磁盘或分区一样访问一个文件。环回设备通常用于挂载磁盘镜像、操作文件系统镜像以…

【单链表】05 有一个带头结点的单链表L,设计一个算法使其元素递增有序。

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux算法题上机准备 &#x1f618;欢迎 ❤️关注 &#x1f44d;点赞 &#x1f64c;收藏 ✍️留言 题目 有一个带头结点的单链表L,设计一个算法使其元素递增有序。 算法思路 解决办法有很多&…

代码随想录训练营第三十三天 509斐波那契数列 70爬楼梯 746使用最小花费爬楼梯

第一题&#xff1a; 原题链接&#xff1a;509. 斐波那契数 - 力扣&#xff08;LeetCode&#xff09; 本题很简单&#xff0c; 递推公式&#xff1a;dp[i] dp[i - 1] dp[i - 2]; 初始化dp[0] 0; dp[1] 1; 顺序遍历即可 代码如下&#xff1a; class Solution { public…

商品分页,商品模糊查询

一、商品分页 引入分页 定义分页主件的参数 在请求url上拼接参数 定义改变当前页码后触发的事件&#xff0c;把当前页码的值给到分页表单&#xff0c;重新查询 二、商品查询&#xff08;以商品的名称查询name为例&#xff09; 引入elementplus的from表单组件 定义一个FormData…

实现在列表框内及列表框间实现数据拖动:在工作表界面窗体的加载

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…

three-platformize 微信小程序 uniapp 使用截图功能

最近需要将3d场景进行截图&#xff0c;但是网上的各种各样&#xff0c;看的我一团乱麻&#xff0c;因此在解决完后就将这些简单的分享一下&#xff1b; 原理&#xff1a;将3维场景的那个canvas中的像素提取出来&#xff0c;找一个空的canvas二维画布放上去&#xff0c;然后用二…

jitsi 使用JWT验证用户身份

前言 Jitsi Meet是一个很棒的会议系统,但是默认他运行所有人创建会议,这样在某种程度上,我们会觉得他不安全,下面我们就来介绍下使用JWT来验证用户身份 方案 卸载旧的lua依赖性sudo apt-get purge lua5.1 liblua5.1-0 liblua5.1-dev luarocks添加ubuntu的依赖源,有则不需…

运维锅总详解设计模式

本首先简介23种设计模式&#xff0c;然后用Go语言实现这23种设计模式进行举例分析。希望对您理解这些设计模式有所帮助&#xff01; 一、设计模式简介 设计模式是软件设计中用于解决常见设计问题的一套最佳实践。它们不是代码片段&#xff0c;而是解决特定问题的通用方案。设…