PYQT5-事件处理机制

PYQT5-事件处理机制

PyQt中提供了两种针对事件处理的机制:一种是信号和槽,另一种则是事件;事件处理在PyQt中是比较底层的,这里的事件常见如下类型:

键盘事件、鼠标事件、拖放事件、滚轮事件、定时事件、焦点事件、进入和离开事件(光标移入控件或者移出),移动事件(窗口位置变化),

显示和隐藏事件,窗口事件(窗口是否为当前窗口)、以及常见的Qt事件:Socket事件、剪贴板事件、文字改变事件,布局改变事件;

PyQt提供了5中事件处理和过滤方法,弱到强,其中前两者常用;

(1)重写事件具体的函数(例如:mousePressEvent()/keyPressEvent()…)

(2)重新实现QObject.event()一般用在PyQt没有提供该事件的处理函数的情况下,即添加一个新的事件;

(3)通过事件过滤器

对QObject调用installEventFilter,则相当于为QObject安装了一个事件过滤器;对于QObject的全部事件来说,他们会先传递到事件过滤函数eventFilter中;

在函数中我们可以放弃或者修改某些事件,如果该过滤事件比较多,则会降低性能;

(4)在QApplication中设置事件过滤器

这种方式比前者更强大,QApplication的事件过滤器会捕获所有QObject的事件,且第一个获得事件,即在任意一个事件过滤器之前捕获;

(5)重写QApplication中notify()方法;

使用notify方法来分发事件;想在任意事件处理器之前捕获事件,则唯一方法就是从写notify方法;

1、鼠标按键事件

    def mousePressEvent(self, event):
        print("鼠标按下触发事件")
    def mouseReleaseEvent (self, event):
        print("鼠标松开触发事件")
    def mouseDoubleClickEvent(self, event):
        print('鼠标双击触发事件')

参数event

方法描叙
x()和y()返回相对于控件空间的鼠标坐标值
pos()返回相对于控件空间的QPoint对象
localPos()返回相对于控件空间的QPointF对象
globalX() 和 globalY()返回相对于屏幕的x,y 坐标值
globalPos()返回相对于屏幕的QPoint对象
windowPos()回相对于窗口的QPointF对象
screenPos()返回相对于屏幕的QPointF对象
button()0 - 没有按下鼠标键
timestamp()返回事件发生的时间

2、鼠标指针

    def mouseMoveEvent(self, event):
        print("鼠标移动事件")

默认情况下只有按下鼠标键移动才会触发该事件,设置普通移动也触发该事件setMouseTracking(True);

    def enterEvent (self, event):
        print('鼠标进入控件')
    def leaveEvent(self, QEvent):
        print('鼠标离开控件')

3、滚动鼠标

    def wheelEvent(self, event):
        print("鼠标滚轮滚动事件")

4、键盘事件

    def keyPressEvent(self, QKeyEvent):
        print("键盘按下事件")
        if QKeyEvent.key() == Qt.Key_F5:
            print('按下F5')
    def keyReleaseEvent(self, QKeyEvent):
        print("键盘松开事件")
        if QKeyEvent.key() == Qt.Key_F6:
            print("松开F6")
    #长按会连续触发

5、焦点事件

        #设置焦点
        self.ui.setFocusPolicy(QtCore.Qt.ClickFocus)
    def focusInEvent(self, QFocusEvent):
        print("在焦点")
    def focusOutEvent(self, QFocusEvent):
        print("不在焦点")

如果窗口内有其它控件,可以将其它控件设置为NoFocus。

6、示例

重写具体事件和event函数;

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys

class Win(QWidget):
    def __init__(self,parent=None):

        super(Win, self).__init__(parent)
        self.message=""
        self.btn1=QPushButton("点击1",self)
        self.btn1.move(20,40)
        self.btn1.clicked.connect(lambda :self.btnFn(1))#点击按钮,执行btnFn方法

        self.btn2 = QPushButton("点击2", self)
        self.btn2.move(140,40)
        self.btn2.clicked.connect(lambda: self.btnFn(2))  # 点击按钮,执行btnFn方法
    def btnFn(self,flag):
        if flag==1:
            print("点击了第一个按钮")
        else:
            print("点击了第二个按钮")


    #上面之前的实例,下面从写按键事件方法
    ###第一种方式
    def keyPressEvent(self, QKeyEvent):#重写按键事件
        if QKeyEvent.key()==Qt.Key_A:#按A建
           self.btn1.click()
        if  QKeyEvent.key()==Qt.Key_Tab:
            print("TABTAB")

    def closeEvent(self, QCloseEvent):#重写关闭窗口事件
        print("重写关闭窗口事件closeEvent")

    def contextMenuEvent(self, even):#重写上下文菜单事件
        menu=QMenu(self)
        oneAction=menu.addAction("One")
        oneAction.triggered.connect(self.one)

        menu.addSeparator()#菜单添加分割线
        twoAction=menu.addAction("Two")
        twoAction.triggered.connect(self.two)

        menu.exec_(even.globalPos())#事件触发在任意位置

    def one(self):
        print("one")
        self.message="Menu option One"
        self.update()
    def two(self):
        print("two")
        self.message="Menu option Two"
        self.update()

    def paintEvent(self, event):#重写绘制事件
        painter=QPainter(self)
        painter.setRenderHint(QPainter.TextAntialiasing)
        painter.drawText(self.rect(),Qt.AlignCenter,self.message)
        QTimer.singleShot(15000,self.clearMessage)#清空数据
        QTimer.singleShot(15000,self.update)#更新当前组件

    def clearMessage(self):
        self.message=""

    def resizeEvent(self, event):#更新窗体大小事件
        self.message="窗口大小调整为:QSize({0},{1})".format(event.size().width(),event.size().height())
        self.update()

    ###第二种方式,一般适用于PyQt没有提供事件处理函数情况,需要自定义事件,例如:
        #Tab按键不会传递给keyPressEvent;
       #第二种方式则是重写event函数,所有针对窗口的事件都会传递给event函数,event会根据事件的类型,讲事件分配给不同函数处理;

    def event(self,event):
        #?????下面捕获不到tab按键的事件,if判断始终未false,不知道为何,待解决;???
        if ( event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab ):
            print("Tab")
            self.message="在event()中捕获Tab按键触发的事件"
            self.update()
            return True
        return QWidget.event(self,event)


if __name__=='__main__':

    app=QApplication(sys.argv)
    win = Win()
    win.show()
    sys.exit(app.exec_())

事件过滤器;单击按钮获取左键或者右键单击事件;

from PyQt5.QtWidgets import  *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys

class Win(QWidget):
    def __init__(self,parent=None):
        super(Win, self).__init__(parent)
        self.resize(400,400)

        self.btn=QPushButton("按钮",self)
        self.btn.move(50,50)
        self.btn.setMinimumWidth(220)

        self.image=QImage("./image/7.ico")
        self.label=QLabel('图片',self)
        self.label.setMinimumWidth(600 )
        self.label.setMinimumHeight(400)
        self.label.move(100,150)
        self.label.setPixmap(QPixmap(self.image))

        #对按钮添加事件过滤器
        self.btn.installEventFilter(self)

    def  eventFilter(self,obj, event):
         if obj==self.btn:
             if event.type()==QEvent.MouseButtonPress:
                mouseEvent=QMouseEvent(event)
                if mouseEvent.buttons()==Qt.LeftButton:
                   self.btn.setText("按鼠标左键缩小图片")
                   transform=QTransform()
                   transform.scale(0.5,0.5)#设置缩放多少倍
                   self.label.setPixmap(QPixmap.fromImage(self.image.transformed(transform)))#将label中图片设置缩放效果
                if mouseEvent.buttons()==Qt.RightButton:
                    self.btn.setText("按鼠标右键放大图片")
                    transform = QTransform()
                    transform.scale(1.5, 1.5)#设置缩放多少倍
                    self.label.setPixmap(QPixmap.fromImage(self.image.transformed(transform)))
         return QWidget.eventFilter(self,obj,event)
    
if __name__=='__main__':

    app=QApplication(sys.argv)
    win = Win()
    win.show()
    sys.exit(app.exec_())

在QApplication中安装事件监听,修改如下代码。

if __name__=='__main__':

    app=QApplication(sys.argv)
    win = Win()
    app.installEventFilter(win)  #安装事件过滤器,将前面代码中按钮的installEventFilter注释掉即可
    win.show()
    sys.exit(app.exec_())


评论回复