当前位置: 首页 > 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.…...

Rails 7中的表单验证与错误处理

在Ruby on Rails开发中,表单验证是确保用户输入符合预期的重要机制。尤其在用户注册这样的场景中,如何优雅地处理错误信息并显示给用户,是一个不容忽视的细节。本文将结合实际代码示例,探讨在Rails 7中如何实现表单验证和错误处理。 问题背景 一位开发者在使用Rails 7开发…...

CowPi嵌入式教学平台:内存映射I/O与轮询中断实践

1. CowPi 硬件教学平台概述CowPi 是一个专为嵌入式系统底层教学设计的硬件实验套件&#xff0c;其核心目标是系统性地训练学生掌握三大基础硬件交互范式&#xff1a;内存映射 I/O&#xff08;Memory-Mapped I/O&#xff09;、轮询&#xff08;Polling&#xff09;和中断&#x…...

The Algorithms - PHP单元测试完全指南:如何为算法编写高质量测试用例

The Algorithms - PHP单元测试完全指南&#xff1a;如何为算法编写高质量测试用例 【免费下载链接】PHP All Algorithms implemented in PHP 项目地址: https://gitcode.com/gh_mirrors/php1/PHP 在软件开发中&#xff0c;单元测试是确保代码质量和稳定性的关键环节。对…...

Cesium与Vue.js融合构建:智慧管网三维可视化平台的架构演进与实践

1. 从零开始的智慧管网三维可视化平台架构设计 第一次接触智慧管网项目时&#xff0c;我被地下管线数据的复杂性震惊了。传统二维GIS系统就像用平面地图导航迷宫&#xff0c;而我们需要的是能透视地下五米的"X光眼"。这就是为什么选择Cesium作为核心引擎——它不仅能…...

保姆级 uPyPi 教程|从 到 :MicroPython 驱动包一键安装 + 分享全攻略诮

这个代码的核心功能是&#xff1a;基于输入词的长度动态选择反义词示例&#xff0c;并调用大模型生成反义词&#xff0c;体现了 “动态少样本提示&#xff08;Dynamic Few-Shot Prompting&#xff09;” 与 “上下文长度感知的示例选择” 的能力。 from langchain.prompts impo…...

别再死记命令了!通过一个Packet Tracer静态路由实验,彻底搞懂‘下一跳’和‘出接口’的区别

别再死记命令了&#xff01;通过Packet Tracer实验彻底搞懂静态路由的“下一跳”与“出接口” 刚接触网络配置时&#xff0c;很多人会陷入一个误区&#xff1a;把静态路由的配置命令当作魔法咒语来记忆。直到某天&#xff0c;当网络拓扑发生变化&#xff0c;或者需要在不同场景…...

别再一关了之!手把手教你用setenforce命令调试SELinux权限问题(附安卓init流程解析)

SELinux调试实战&#xff1a;从权限拒绝到策略优化的完整指南 遇到SELinux权限问题时&#xff0c;很多开发者第一反应是直接关闭它——这就像因为门锁太复杂而直接把大门拆掉。本文将带你深入理解SELinux的工作机制&#xff0c;并掌握一套系统化的调试方法&#xff0c;让你既能…...

为什么要做 GeoPipeAgent底

指令替换 项目需求&#xff1a;将加法指令替换为减法 项目目录如下 /MyProject ├── CMakeLists.txt # CMake 配置文件 ├── build/ #构建目录 │ └── test.c #测试编译代码 └── mypass2.cpp # pass 项目代码 一&#xff0c;测试代码示例 test.c // test.c #includ…...

别再让扩展坞‘抢电’了!手把手教你用LDR6282 APP智能分配USB-C功率

别再让扩展坞“抢电”了&#xff01;LDR6282芯片智能功率分配全攻略 每次连接扩展坞时&#xff0c;笔记本电量不增反减&#xff1f;外接硬盘频繁断开&#xff1f;这些困扰专业用户的“功率焦虑”问题&#xff0c;根源在于传统扩展坞的固定功率分配机制。本文将深度解析基于LDR…...

深度学习实战:用多尺度训练提升图像识别准确率(附TensorFlow代码)

深度学习实战&#xff1a;用多尺度训练提升图像识别准确率&#xff08;附TensorFlow代码&#xff09; 当你在街头用手机拍摄远处模糊的路牌时&#xff0c;是否好奇过AI如何识别不同尺寸的物体&#xff1f;这正是多尺度训练技术要解决的核心问题。在医疗影像分析中&#xff0c;从…...