I wrote a class that I think is pretty good to simplify the mouse information in mousePressEvent
, mouseMoveEvent
and mouseReleaseEvent
.
The functions include the following:
Current mouse status
, including left/middle/right mouse button and click/double-click/liftMouse anti-shake
(only when the mouse has moved beyond a certain level), the sensitivity can be set;Mouse long press
(triggered when the mouse is long pressed and no movement occurs), the duration can be set;Mouse double-click
(the time interval between two clicks is small enough to be judged as a double-click), the duration can be set;Mouse offset
is only valid when the mouse is pressed. It can return the total offset since the click or the relative offset from the last mouse event.
Supplement:
This self-made class will cause ambiguity when pressing multiple keys, that is, it cannot handle difficult operations, such as right-clicking and dragging and then left-clicking to cause chaos. Originally, I wanted to rewrite the code to fill this flaw, but when I think about it, it’s a bit strange. Under what circumstances is this weird operation needed?
Homemade class 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 and mouseReleaseEvent are specially provided. Only handles single keys (multi-key behavior please control in external code) longClick=pyqtSignal()#Triggered when the mouse remains in place and long pressed __antiJitter=5# Anti-shake, when the Manhattan distance between the mouse click position and the current mouse position does not exceed this value, the mouse will still be regarded as motionless. __doubleClickInterval=500#Double-click interval (ms) __longPressInterval=500#Long press interval (ms) __record={<!-- --> 'lastPress':None,#Information when last pressed 'lastMouse':None,#Last mouse information 'currMouse':None,#Current mouse information } __press=[QMouseEvent.MouseButtonRelease,QMouseEvent.MouseButtonPress,QMouseEvent.MouseButtonDblClick]#For laziness __move=False# Used to determine whether to long press __timerID=0#The corresponding timer when the mouse is pressed class __Data: pos=None#mouse position btn=None#Mouse buttons (left, middle, right) pressStatus=None#The mouse is currently pressed (single double click/lift) timeStamp=None#Mouse event time moment def __init__(self,event): self.pos=event.globalPos()#pos is not used here to prevent violent death 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#Small defense to avoid triggering double-click behavior when clicking at the start 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):#Current timer if(not self.__move and record['currMouse'].pressStatus!=press[0]):#No movement occurs, the mouse is not lifted, and the long press signal is triggered self.longClick.emit() def Set_DoubleClickInterval(self,interval):#Set the double-click interval (ms) self.__doubleClickInterval=interval def Set_LongPressInterval(self,interval):#Set the long press interval (ms) self.__longPressInterval=interval def Set_AntiJitter(self,val):#Set anti-shake value self.__antiJitter=val if val>0 else 0 def Get_Position(self):#Return the mouse coordinates. It is the screen coordinate (global), and you need to use QWidget.mapFromGlobal(QPoint) to convert it to the relative coordinate of the control. return self.__record['currMouse'].pos def Get_PressButtonStatus(self):#Return the current mouse button (left, middle, right) and pressed status (click/double-click/lift) return self.__record['currMouse'].btn,self.__record['currMouse'].pressStatus def Get_MoveDelta(self,total=True,strict=True):#Return the mouse movement amount (valid only when the mouse is pressed), which is a QPoint object press=self.__press record=self.__record data_curr=record['currMouse'] if(data_curr.pressStatus!=press[0]):#Indicates that the mouse is pressed if(not strict or self.__move):#In strict mode, the movement amount is only calculated when movement occurs. 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): #Determine whether movement has occurred (after all, it is a bit troublesome to use Get_MoveDelta to determine the occurrence of movement. It is better to have one more function return self.__move def Opt_Update(self,event):#Update status press=self.__press record=self.__record data_curr=self.__Data(event) if(event.type()==press[1] or event.type()==press[2]):#Single/double click self.__move=False data_old=record['lastPress'] data_curr.pressStatus=press[1] if(data_old.btn==data_curr.btn):# Press the same key if(data_curr.timeStamp-data_old.timeStamp<self.__doubleClickInterval):#Within the time interval if(data_old.pressStatus!=press[2]):#No double-click data_curr.pressStatus=press[2]#Double click record['lastPress']=data_curr record['lastMouse']=data_curr record['currMouse']=data_curr self.__timerID=self.startTimer(self.__longPressInterval) else:#Move/Lift data_curr.btn=event.buttons() data_curr.pressStatus=record['lastMouse'].pressStatus if(event.type()==press[0]):#Lift up if(data_curr.btn==Qt.NoButton):#Ensure that it is set to Release when no button is pressed data_curr.pressStatus=press[0] data_curr.btn=event.button() else:#Move(QMouseEvent.MouseMove) if(data_curr.pressStatus!=press[0] and not self.__move):#Determine whether dragging has occurred 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
Test code and running results:
Some enumerations related to the mouse:
- Click
QMouseEvent.MouseButtonPress
- Double-click
QMouseEvent.MouseButtonDblClick
- Lift
QMouseEvent.MouseButtonRelease
- Left button
Qt.LeftButton
- Middle button
Qt.MidButton
- Right click
Qt.RightButton
#Main.py importsys 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 & amp;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())
This article was published on CSDN and may not be reproduced without personal permission: https://blog.csdn.net/weixin_44733774/article/details/134349820