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

这篇具有很好参考价值的文章主要介绍了【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.MouseButtonRelease
            self.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']=data
        record['currMouse']=data
        record['lastPress']=data
        self.__record=record
    def timerEvent(self,event):
        record=self.__record
        press=self.__press
        tId=event.timerId()
        cId=self.__timerID
        self.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=interval
    def Set_LongPressInterval(self,interval):#设置长按时间间隔(ms)
        self.__longPressInterval=interval
    def Set_AntiJitter(self,val):#设置防抖值
        self.__antiJitter=val if val>0 else 0

    def Get_Position(self):#返回鼠标坐标。是屏幕坐标(global),需要使用QWidget.mapFromGlobal(QPoint)自行转换为控件相对坐标
        return self.__record['currMouse'].pos
    def Get_PressButtonStatus(self):#返回当前鼠标的键(左中右)以及按下状态(单击/双击/抬起)
        return self.__record['currMouse'].btn,self.__record['currMouse'].pressStatus
    def Get_MoveDelta(self,total=True,strict=True):#返回鼠标移动量(仅鼠标按下时有效),为QPoint对象
        press=self.__press
        record=self.__record
        data_curr=record['currMouse']
        if(data_curr.pressStatus!=press[0]):#说明鼠标按下
            if(not strict or self.__move):#严格模式下,仅判定发生移动时计算移动量
                p1=record['currMouse'].pos
                if(total):
                    p2=record['lastPress'].pos
                else:
                    p2=record['lastMouse'].pos
                return QPoint(p1.x()-p2.x(),p1.y()-p2.y())
        return QPoint(0,0)
    def Get_HasMoved(self):#判断是否发生移动(毕竟用Get_MoveDelta来判断移动的发生是有点麻烦,还不如多一个函数
        return self.__move

    def Opt_Update(self,event):#更新状态
        press=self.__press
        record=self.__record
        data_curr=self.__Data(event)
        if(event.type()==press[1] or event.type()==press[2]):#单/双击
            self.__move=False
            data_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_curr
            record['lastMouse']=data_curr
            record['currMouse']=data_curr
            self.__timerID=self.startTimer(self.__longPressInterval)
        else:#移动/抬起
            data_curr.btn=event.buttons()
            data_curr.pressStatus=record['lastMouse'].pressStatus
            if(event.type()==press[0]):#抬起
                if(data_curr.btn==Qt.NoButton):#确保无按键按下时设置为Release
                    data_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=True
                        record['currMouse'].pos=record['lastPress'].pos
            record['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=None
    def __init__(self,*arg):
        super().__init__(*arg)
        ms=XJ_MouseStatus()
        ms.longClick.connect(lambda:print("<LongClick!>"))
        self.__mouseStatus=ms
    def __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.__mouseStatus
        pos=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())

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




本文发布于CSDN,未经个人允许不得私自转载:https://blog.csdn.net/weixin_44733774/article/details/134349820文章来源地址https://www.toymoban.com/news/detail-787214.html

到了这里,关于【PyQt】(自制类)处理鼠标点击逻辑的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • [pyqt5]关于在pyqt5界面上鼠标位置问题

    先上代码,主要看鼠标移动事件里面代码 通过运行代码可以发现: 上面这2行就是相当于屏幕左上角坐标了

    2024年02月15日
    浏览(39)
  • Pyqt通过鼠标滚轮进行缩放界面

    大多数视图类和一部分控件应该都有wheelEvent()函数 首先定义变量,这里为了缩小和放大的比例相同,缩小倍数为1除以放大倍数。 重写wheelEvent函数。 这里的event对象是个QWheelEvent事件对象。  event.angleDelta()返回一个Qpoint对象,代表滚动的数值。单位是8分之一度。转一下一

    2024年02月12日
    浏览(48)
  • 【PyQt学习篇 · ⑤】:QWidget - 鼠标操作

    在PyQt中,QWidget类提供了设置鼠标形状的功能。可以使用 setCursor() 方法来更改QWidget及其子类的鼠标形状。该方法接受一个Qt.CursorShape参数,该参数定义了不同的鼠标形状选项。 以下是一些常用的鼠标形状选项及其对应的Qt.CursorShape常量: Qt.ArrowCursor:标准箭头指针。 Qt.UpArr

    2024年02月08日
    浏览(42)
  • [pyqt5]触发ctrl+鼠标滚轮事件

    有时候我们需要按住Ctrl+鼠标滚轮实现图像放大或者缩小,因此需要这个事件,具体看代码

    2024年02月13日
    浏览(47)
  • PyQt5实现多文件调用以及UI和逻辑分离

    UI   ui_untitled.py 逻辑代码页 目录 一、PyCharm+PyQt5的环境配置 二、使用Qt Designer将界面显示与业务逻辑分离 三、PyQt5工程中的多文件开发 转自原文链接 作为一个使用C++开发QT五年的“老”程序猿,总觉得使用C++开发GUI,是一个很费时费力或者说没有“钱”途的事情,因为现在

    2024年02月12日
    浏览(48)
  • python pyqt5 如何点击按钮,打开文件夹选择目录

    您可以使用PyQt5的QFileDialog类来实现打开文件夹选择目录的功能。下面是一个示例代码,演示了如何创建一个窗口,包含一个按钮,点击按钮后弹出文件夹选择对话框并返回所选目录的路径: import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QFileDialog class MainWindow(Q

    2024年02月10日
    浏览(61)
  • 香,一套逻辑轻松且智能解决PyQt中控件数值验证的问题

    在 PyQt 开发中,时常需要对控件的值进行校验,如需要校验 QCheckBox 是否被选中, QLabel 是否校验值是否为空等等。在复杂的业务场景下,这类控件如果数量很多,逐个校验就显得麻烦,需要一一获得控件名称,再调用对应的方法来判断是否被选中、是否为空等。而且开发过程

    2023年04月15日
    浏览(39)
  • PyQt5 Qt Designer使用(界面显示与业务逻辑分离模式)

    Qt Designer运行界面: MainWinSignalSlog02.ui Ui_MainWinSignalSlog02.py CallMainWinSignalSlog02.py

    2024年02月15日
    浏览(37)
  • pyqt5 QMainWindow、Dialog点击关闭弹出是否确定关闭

    1.在QMainWindow()中,重写closeEvent函数实现窗口关闭事件。 2.在Dialog()中,重写closeEvent函数实现窗口关闭事件。  以上述两种情况做演示,其他情况同上。 注意:    在main()方法中可以看到:我们最终显示的是QMainWindow()类创建的窗口对象,如果想要实现关闭窗口触发弹窗提示

    2024年02月15日
    浏览(53)
  • OpenCV-PyQT项目实战(8)项目案例03:鼠标定位

    欢迎关注『OpenCV-PyQT项目实战 @ Youcans』系列,持续更新中 OpenCV-PyQT项目实战(1)安装与环境配置 OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战(3)信号与槽机制 OpenCV-PyQT项目实战(4)OpenCV 与PyQt的图像转换 OpenCV-PyQT项目实战(5)项目案例01:图像模糊

    2024年02月10日
    浏览(49)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包