当前位置: 首页 > news >正文

【PyQt】(自制类)处理鼠标点击逻辑

写了个自认为还算不错的类,用于简化mousePressEventmouseMoveEventmouseReleaseEvent中的鼠标信息。

功能有以下几点:
  • 鼠标当前状态,包括鼠标左/中/右键和单击/双击/抬起
  • 鼠标防抖(仅超出一定程度时才判断鼠标发生了移动),灵敏度可设置;
  • 鼠标长按(在鼠标长按并且未发生移动时触发),时长可设置;
  • 鼠标双击(两次点击的时间间隔足够小时判断为双击),时长可设置;
  • 鼠标偏移量,仅鼠标按下时有效,可返回自点击时的总偏移量,也可返回与上次鼠标事件之间的相对偏移量
补充:

这个自制类在多键按下时会产生歧义,也就是没法处理有如刁难一般的操作,像是右键拖拽然后左键来添乱之类的。本来是想再重新写份代码以填补这个缺陷的,但想想就有点怪,什么场合下才需要满足这种怪异的操作。




自制类XJ_MouseStatus

#XJ_MouseStatus.py
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import QPoint,Qt,QObject
from PyQt5.QtGui import QMouseEvent__all__=['XJ_MouseStatus']
class XJ_MouseStatus(QObject):#mousePressEvent、mouseMoveEvent和mouseReleaseEvent特供。只处理单键(多键行为请在外部代码控制)longClick=pyqtSignal()#鼠标原地不动长按时触发__antiJitter=5#防抖,当鼠标点击位置与鼠标当前位置的曼哈顿距离不超过该值时仍将鼠标视为不动状态__doubleClickInterval=500#双击间隔(ms)__longPressInterval=500#长按间隔(ms)__record={'lastPress':None,#上一次按下时的信息'lastMouse':None,#上一次的鼠标信息'currMouse':None,#当前鼠标信息}__press=[QMouseEvent.MouseButtonRelease,QMouseEvent.MouseButtonPress,QMouseEvent.MouseButtonDblClick]#偷懒用的__move=False#用于判断是否长按__timerID=0#鼠标按下时对应的定时器class __Data:pos=None#鼠标位置btn=None#鼠标按键(左中右)pressStatus=None#鼠标当前按下状态(单双击/抬起)timeStamp=None#鼠标事件时间刻def __init__(self,event):self.pos=event.globalPos()#这里不用pos是为了防暴毙self.btn=event.button()self.pressStatus=event.MouseButtonReleaseself.timeStamp=event.timestamp()def __init__(self,*arg):super().__init__(*arg)record=self.__record.copy()fakeEvent=QMouseEvent(QMouseEvent.MouseButtonRelease,QPoint(0,0),Qt.NoButton,Qt.NoButton,Qt.NoModifier)data=self.__Data(fakeEvent)data.timeStamp-=self.__doubleClickInterval#小防,避免开局单击时触发双击行为record['lastMouse']=datarecord['currMouse']=datarecord['lastPress']=dataself.__record=recorddef timerEvent(self,event):record=self.__recordpress=self.__presstId=event.timerId()cId=self.__timerIDself.killTimer(event.timerId())if(cId==tId):#当前定时器if(not self.__move and record['currMouse'].pressStatus!=press[0]):#未发生移动,未抬起鼠标,触发长按信号self.longClick.emit()def Set_DoubleClickInterval(self,interval):#设置双击时间间隔(ms)self.__doubleClickInterval=intervaldef Set_LongPressInterval(self,interval):#设置长按时间间隔(ms)self.__longPressInterval=intervaldef Set_AntiJitter(self,val):#设置防抖值self.__antiJitter=val if val>0 else 0def Get_Position(self):#返回鼠标坐标。是屏幕坐标(global),需要使用QWidget.mapFromGlobal(QPoint)自行转换为控件相对坐标return self.__record['currMouse'].posdef Get_PressButtonStatus(self):#返回当前鼠标的键(左中右)以及按下状态(单击/双击/抬起)return self.__record['currMouse'].btn,self.__record['currMouse'].pressStatusdef Get_MoveDelta(self,total=True,strict=True):#返回鼠标移动量(仅鼠标按下时有效),为QPoint对象press=self.__pressrecord=self.__recorddata_curr=record['currMouse']if(data_curr.pressStatus!=press[0]):#说明鼠标按下if(not strict or self.__move):#严格模式下,仅判定发生移动时计算移动量p1=record['currMouse'].posif(total):p2=record['lastPress'].poselse:p2=record['lastMouse'].posreturn QPoint(p1.x()-p2.x(),p1.y()-p2.y())return QPoint(0,0)def Get_HasMoved(self):#判断是否发生移动(毕竟用Get_MoveDelta来判断移动的发生是有点麻烦,还不如多一个函数return self.__movedef Opt_Update(self,event):#更新状态press=self.__pressrecord=self.__recorddata_curr=self.__Data(event)if(event.type()==press[1] or event.type()==press[2]):#单/双击self.__move=Falsedata_old=record['lastPress']data_curr.pressStatus=press[1]if(data_old.btn==data_curr.btn):#同键位按下if(data_curr.timeStamp-data_old.timeStamp<self.__doubleClickInterval):#在时间间隔内if(data_old.pressStatus!=press[2]):#没有双击过data_curr.pressStatus=press[2]#双击record['lastPress']=data_currrecord['lastMouse']=data_currrecord['currMouse']=data_currself.__timerID=self.startTimer(self.__longPressInterval)else:#移动/抬起data_curr.btn=event.buttons()data_curr.pressStatus=record['lastMouse'].pressStatusif(event.type()==press[0]):#抬起if(data_curr.btn==Qt.NoButton):#确保无按键按下时设置为Releasedata_curr.pressStatus=press[0]data_curr.btn=event.button()else:#移动(QMouseEvent.MouseMove)if(data_curr.pressStatus!=press[0] and not self.__move):#判断有无发生拖拽delta=self.Get_MoveDelta(strict=False)if(abs(delta.x())+abs(delta.y())>self.__antiJitter):self.__move=Truerecord['currMouse'].pos=record['lastPress'].posrecord['lastMouse']=record['currMouse']record['currMouse']=data_curr



测试代码与运行结果:

与鼠标相关的部分枚举量:
  • 单击QMouseEvent.MouseButtonPress
  • 双击QMouseEvent.MouseButtonDblClick
  • 抬起QMouseEvent.MouseButtonRelease
  • 左键Qt.LeftButton
  • 中键Qt.MidButton
  • 右键Qt.RightButton
#Main.py
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from XJ_MouseStatus import *class Test(QWidget):__mouseStatus=Nonedef __init__(self,*arg):super().__init__(*arg)ms=XJ_MouseStatus()ms.longClick.connect(lambda:print("<LongClick!>"))self.__mouseStatus=msdef __EasyPrint(self):press={QMouseEvent.MouseButtonRelease:"Release",QMouseEvent.MouseButtonPress:"Press",QMouseEvent.MouseButtonDblClick:"DblClick",}button={Qt.LeftButton:'Left',Qt.MidButton:'Middle',Qt.RightButton:'Right',}tPoint=lambda point:(point.x(),point.y())tBtn=lambda btn:[button[key] for key in button if key&btn]tBtnStatus=lambda status:(tBtn(status[0]),press[status[1]])ms=self.__mouseStatuspos=tPoint(self.mapFromGlobal(ms.Get_Position()))moveDelta=tPoint(ms.Get_MoveDelta())btnStatus=tBtnStatus(ms.Get_PressButtonStatus())print(f'pos{pos},\tdelta{moveDelta},\t{btnStatus[0]}-{btnStatus[1]}')if(btnStatus[1]=='Release'):print()def mousePressEvent(self,event):self.__mouseStatus.Opt_Update(event)self.__EasyPrint()def mouseMoveEvent(self,event):self.__mouseStatus.Opt_Update(event)self.__EasyPrint()def mouseReleaseEvent(self,event):self.__mouseStatus.Opt_Update(event)self.__EasyPrint()if __name__=='__main__':app = QApplication(sys.argv)t=Test()t.show()sys.exit(app.exec())

运行结果




本文发布于CSDN,未经个人允许不得私自转载:https://blog.csdn.net/weixin_44733774/article/details/134349820

相关文章:

【PyQt】(自制类)处理鼠标点击逻辑

写了个自认为还算不错的类&#xff0c;用于简化mousePressEvent、mouseMoveEvent和mouseReleaseEvent中的鼠标信息。 功能有以下几点&#xff1a; 鼠标当前状态&#xff0c;包括鼠标左/中/右键和单击/双击/抬起鼠标防抖(仅超出一定程度时才判断鼠标发生了移动)&#xff0c;灵…...

JAVA IDEA 下载

超简单步骤一&#xff1a; IntelliJ IDEA 官方下载链接 点击以上链接进入下图&#xff0c;点击下载 继续点下载&#xff0c;然后等待下载完后打开安装包即可 步骤二&#xff1a; 打开下好的安装包&#xff0c;点击Browse...我们把它下载到自己喜欢的地方&#xff08;主要是别占…...

DevOps简介

DevOps简介 1、DevOps的起源2、什么是DevOps3、DevOps的发展现状4、DevOps与虚拟化、容器 1、DevOps的起源 上个世纪40年代&#xff0c;世界上第一台计算机诞生。计算机离不开程序&#xff08;Program&#xff09;驱动&#xff0c;而负责编写程序的人&#xff0c;被称为程序员&…...

体验前所未有的显示器管理体验:BetterDisplay Pro Mac

在现代的数字化时代&#xff0c;显示器是我们日常生活和工作中不可或缺的一部分。从笔记本电脑到台式机&#xff0c;从平板电脑到手机&#xff0c;几乎所有的电子设备都配备了显示器。然而&#xff0c;对于专业人士和从事设计行业的人来说&#xff0c;仅仅依靠系统自带的显示器…...

python用pyinstaller打包exe,去掉黑窗口

使用Python编写程序将Python脚本打包成可执行文件&#xff08;EXE&#xff09;,但是会有一个命令框产生&#xff0c;很烦&#xff0c;所以&#xff0c;去掉这个框 1&#xff0c;安装pyinstaller pip install pyinstaller2&#xff0c;打包产生cmd命令框 pyinstaller --onefi…...

如何关闭Windows Defender(亲测可行!!非常简单)

一、背景 Windows Defender&#xff08;简称WD&#xff09;真的太讨厌了&#xff0c;经常给你报你下载的文件是病毒&#xff0c;且不说真的是不是病毒&#xff0c;它都不询问直接删。 另外聚资料显示WD还会不合时宜地执行扫描导致系统变慢&#xff08;不会在合适的、空闲的时…...

【objectarx.net】创建多重引线

创建多重引线...

【objectarx.net】创建组,列出所有组,查找实体所在的组

创建组,列出所有组...

Llama2通过llama.cpp模型量化 WindowsLinux本地部署

Llama2通过llama.cpp模型量化 Windows&Linux本地部署 什么是LLaMA 1 and 2 LLaMA&#xff0c;它是一组基础语言模型&#xff0c;参数范围从7B到65B。在数万亿的tokens上训练的模型&#xff0c;并表明可以专门使用公开可用的数据集来训练最先进的模型&#xff0c;而无需求…...

Coding面试题之手写线程池

原理图 JDK线程池原理 实现代码 1.线程类&#xff08;PoolThread&#xff09; 这个类用于执行任务队列中的任务。 public class PoolThread extends Thread {private final Queue<Runnable> taskQueue;private boolean isStopped false;private long lastTaskTime …...

【objectarx.net】删除零长度曲线和获取零长度曲线的数量

删除零长度曲线和获取零长度曲线的数量...

Win11专业版安装Docker Desktop,并支持映射主机的gpu

一、Windows环境下安装 Docker 必须满足: 1. 64位Windows 11 Pro(专业版和企业版都可以) 2. Microsoft Hyper-V,Hyper-V是微软的虚拟机,在win11上是自带的,我们只需要启动就可以了 二、下载Docker Desktop安装包 方式一:进入官网下载 https://docs.docker.com/desktop…...

Mac代码文本编辑器Sublime Text 4

Sublime Text 4 for Mac拥有快速响应的功能&#xff0c;可以快速加载文件和执行命令&#xff0c;并提供多种语言支持&#xff0c;包括C 、Java、Python、HTML、CSS等。此外&#xff0c;该编辑器还支持LaTeX、Markdown、JSON、XML等技术领域。 Sublime Text 4 for Mac的插件丰富…...

MATLAB中plot函数用法

目录 语法 说明 向量和矩阵数据 表数据 其他选项 示例 创建线图 绘制多个线条 根据矩阵创建线图 指定线型 指定线型、颜色和标记 在特定的数据点显示标记 指定线宽、标记大小和标记颜色 添加标题和轴标签 绘制持续时间并指定刻度格式 基于表绘制坐标 在一个轴…...

win10 安装vscode

1 Download Visual Studio Code - Mac, Linux, Windows 2 this user installer is not meant to be run as an administrator . if ou would like to install vs code for all users i this sys download the system installer instead form are u want to con 提示的意思是&a…...

MATLAB中Arrow 属性说明

目录 颜色和样式 位置 Arrow 属性是箭头的外观和行为。 Arrow 属性控制 Arrow 对象的外观和行为。通过更改属性值&#xff0c;可以修改箭头的特定方面。使用圆点表示法查询和设置属性。 ar annotation("arrow"); c ar.Color; ar.Color "red"; 颜色和…...

MYSQL 慢查询和慢查询日志

在数据库管理中&#xff0c;慢查询是指执行时间较长的 SQL 查询语句。这类查询可能导致系统性能下降&#xff0c;影响用户体验。为了帮助识别和解决这些性能问题&#xff0c;数据库管理系统通常提供了慢查询日志&#xff0c;用于记录执行时间超过一定阈值的查询。本文将深入探讨…...

Longhorn跨AZ实现存储高可用

Longhorn跨AZ实现存储高可用 longhorn基础组件功能及其作用这里就不做介绍了 方案一 Longhorn跨AZ的高可用的就是一个PVC的replicas 均匀打散的不同的AZ区域之间&#xff0c;这样当某个AZ挂掉后&#xff0c;engine会立即使用另外一个数据副本&#xff0c;并重建这个副本&…...

maven 私有仓库配置

1.整体库信息 2.配置阿里云库 &#xff08;可以配置多个库&#xff0c;再引用代理库&#xff09; 3.建立自己的 发布&#xff0c;快照库 4.建立自由的公共库- 引用所有需要的库 5.maven setting 中配置 用户名密码 <server><id>mv-releases</id><usernam…...

TypeScript: 判断两个数组的内容是否相等

一、直接遍历 // 1.直接遍历 const arr1: any[] ["apple", "banana", NaN]; const arr2: any[] ["apple", NaN, "banana"];function fn1(arr1: any[], arr2: any[]) {// Array.some(): 有一项不满足&#xff0c;返回falseif (arr1.…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...