博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PyQt5—事件处理
阅读量:3934 次
发布时间:2019-05-23

本文共 16171 字,大约阅读时间需要 53 分钟。

事件处理


一、常见事件类型和处理方法

1、事件类型

  • 常见的事件有如下:
    • 键盘事件:按键按下和松开
    • 鼠标事件:鼠标指针移动、鼠标按键按下和松开
    • 拖放事件:用鼠标进行拖放
    • 滚轮事件:鼠标滚轮滚动
    • 绘屏事件:重绘屏幕的某些部分
    • 定时事件:定时器到时
    • 焦点事件:键盘焦点移动
    • 进入和离开事件:鼠标指针移入 Widget 内,或者移出
    • 移动事件:Widget 的位置改变
    • 大小改变事件:Widget 的大小改变。
    • 显示和隐藏事件:Widget 的显示和隐藏
    • 窗口事件:窗口是否为当前窗口

2、事件处理方法

  • PyQt5 中事件处理的方法有如下五种:

(1)重写事件函数

  • 将如 mousePressEvent()、keyPressEvent()、paintEvent() 这些事件函数重写。

(2)重新实现 QObject.event()

  • 对于某些事件没有内置提供的处理函数,可以采用此方法。

(3)安装事件过滤器

  • 对 QObject 调用 installEventFilter,让 QObject 的全部事件先传到事件过滤函数 eventFilter 中,然后再这个函数中对事件进行修改,并确定哪些事件使用自定义事件处理函数,那些事件使用默认事件处理函数。

(4)在 QApplication 中安装事件过滤器

  • QApplication 的时间过滤器可以第一时间捕获 QObject 的所有事件。

(5)重新实现 QApplication 的 notify() 方法

  • notify() 函数用于分发事件,可以达到在任何事件处理器之前捕获事件。

3、示例

  • 示例代码如下:
    # -*- coding:utf-8 -*-# Time : 2019/09/16 下午 5:05 # Author : 御承扬# e-mail:2923616405@qq.com# project:  PyQt5# File : Event.py # @software: PyCharmimport sysfrom PyQt5.QtCore import (QEvent, QTimer, Qt)from PyQt5.QtWidgets import (QApplication, QMenu, QWidget)from PyQt5.QtGui import QPainter, QIconclass Widget(QWidget):    def __init__(self, parent=None):        super(Widget, self).__init__(parent)        self.setWindowIcon(QIcon("./images/Python2.ico"))        self.setWindowTitle("鼠标事件示例")        self.justDoubleClicked = False        self.key = ""        self.text = ""        self.message = ""        self.resize(400, 300)        self.move(100, 100)        self.setWindowTitle("Events")        QTimer.singleShot(0, self.giveHelp)  # 避免窗口大小重绘事件的影响,可以把参数0改变成3000(3秒),然后在运行,就可以明白这行代码的意思。    def giveHelp(self):        self.text = "请点击这里触发追踪鼠标功能"        self.update()  # 重绘事件,也就是触发paintEvent函数。    '''重新实现关闭事件'''    def closeEvent(self, event):        print("Closed")    '''重新实现上下文菜单事件'''    def contextMenuEvent(self, event):        menu = QMenu(self)        oneAction = menu.addAction("&One")        twoAction = menu.addAction("&Two")        oneAction.triggered.connect(self.one)        twoAction.triggered.connect(self.two)        if not self.message:            menu.addSeparator()            threeAction = menu.addAction("Thre&e")            threeAction.triggered.connect(self.three)        menu.exec_(event.globalPos())    '''上下文菜单槽函数'''    def one(self):        self.message = "Menu option One"        self.update()    def two(self):        self.message = "Menu option Two"        self.update()    def three(self):        self.message = "Menu option Three"        self.update()    '''重新实现绘制事件'''    def paintEvent(self, event):        text = self.text        i = text.find("\n\n")        if i >= 0:            text = text[0:i]        if self.key:  # 若触发了键盘按钮,则在文本信息中记录这个按钮信息。            text += "\n\n你按下了: {0}".format(self.key)        painter = QPainter(self)        painter.setRenderHint(QPainter.TextAntialiasing)        painter.drawText(self.rect(), Qt.AlignCenter, text)  # 绘制信息文本的内容        if self.message:  # 若消息文本存在则在底部居中绘制消息,5秒钟后清空消息文本并重绘。            painter.drawText(self.rect(), Qt.AlignBottom | Qt.AlignHCenter,                             self.message)            QTimer.singleShot(5000, self.clearMessage)            QTimer.singleShot(5000, self.update)    '''清空消息文本的槽函数'''    def clearMessage(self):        self.message = ""    '''重新实现调整窗口大小事件'''    def resizeEvent(self, event):        self.text = "调整窗口大小为: QSize({0}, {1})".format(            event.size().width(), event.size().height())        self.update()    '''重新实现鼠标释放事件'''    def mouseReleaseEvent(self, event):        # 若鼠标释放为双击释放,则不跟踪鼠标移动        # 若鼠标释放为单击释放,则需要改变跟踪功能的状态,如果开启跟踪功能的话就跟踪,不开启跟踪功能就不跟踪        if self.justDoubleClicked:            self.justDoubleClicked = False        else:            self.setMouseTracking(not self.hasMouseTracking())  # 单击鼠标            if self.hasMouseTracking():                self.text = "开启鼠标跟踪功能.\n" + \                            "请移动一下鼠标!\n" + \                            "单击鼠标可以关闭这个功能"            else:                self.text = "关闭鼠标跟踪功能.\n" + \                            "单击鼠标可以开启这个功能"            self.update()    '''重新实现鼠标移动事件'''    def mouseMoveEvent(self, event):        if not self.justDoubleClicked:            globalPos = self.mapToGlobal(event.pos())  # 窗口坐标转换为屏幕坐标            self.text = """鼠标位置:            窗口坐标为:QPoint({0}, {1})             屏幕坐标为:QPoint({2}, {3}) """.format(event.pos().x(), event.pos().y(), globalPos.x(), globalPos.y())            self.update()    '''重新实现鼠标双击事件'''    def mouseDoubleClickEvent(self, event):        self.justDoubleClicked = True        self.text = "你双击了鼠标"        self.update()    '''重新实现键盘按下事件'''    def keyPressEvent(self, event):        self.key = ""        if event.key() == Qt.Key_Home:            self.key = "Home"        elif event.key() == Qt.Key_End:            self.key = "End"        elif event.key() == Qt.Key_PageUp:            if event.modifiers() & Qt.ControlModifier:                self.key = "Ctrl+PageUp"            else:                self.key = "PageUp"        elif event.key() == Qt.Key_PageDown:            if event.modifiers() & Qt.ControlModifier:                self.key = "Ctrl+PageDown"            else:                self.key = "PageDown"        elif Qt.Key_A <= event.key() <= Qt.Key_Z:            if event.modifiers() & Qt.ShiftModifier:                self.key = "Shift+"            self.key += event.text()        if self.key:            self.key = self.key            self.update()        else:            QWidget.keyPressEvent(self, event)    '''重新实现其他事件,适用于PyQt没有提供该事件的处理函数的情况,Tab键由于涉及焦点切换,不会传递给keyPressEvent,因此,需要在这里重新定义。'''    def event(self, event):        if (event.type() == QEvent.KeyPress and                event.key() == Qt.Key_Tab):            self.key = "在event()中捕获Tab键"            self.update()            return True        return QWidget.event(self, event)if __name__ == "__main__":    app = QApplication(sys.argv)    form = Widget()    form.show()    app.exec_()
  • 效果如下:
    在这里插入图片描述
  • 使用事件过滤器的案例代码入下:
    # -*- coding:utf-8 -*-# Time : 2019/09/16 下午 7:16 # Author : 御承扬# e-mail:2923616405@qq.com# project:  PyQt5# File : Event02.py # @software: PyCharmfrom PyQt5.QtGui import *from PyQt5.QtWidgets import *from PyQt5.QtCore import *import sysclass EventFilter(QDialog):    def __init__(self, parent=None):        super(EventFilter, self).__init__(parent)        self.setWindowTitle("事件过滤器")        self.setWindowIcon(QIcon("./images/Python2.ico"))        self.label1 = QLabel("请点击")        self.label2 = QLabel("请点击")        self.label3 = QLabel("请点击")        self.LabelState = QLabel("test")        self.image1 = QImage("images/cartoon1.ico")        self.image2 = QImage("images/cartoon2.ico")        self.image3 = QImage("images/cartoon3.ico")        self.width = 600        self.height = 300        self.resize(self.width, self.height)        self.label1.installEventFilter(self)        self.label2.installEventFilter(self)        self.label3.installEventFilter(self)        mainLayout = QGridLayout(self)        mainLayout.addWidget(self.label1, 500, 0)        mainLayout.addWidget(self.label2, 500, 1)        mainLayout.addWidget(self.label3, 500, 2)        mainLayout.addWidget(self.LabelState, 600, 1)        self.setLayout(mainLayout)    def eventFilter(self, watched, event):        # 只对 label1 的点击事件进行过滤,重写其行为,其他事件忽略        if watched == self.label1:            if event.type() == QEvent.MouseButtonPress:                mouseEvent = QMouseEvent(event)                if mouseEvent.buttons() == Qt.LeftButton:                    self.LabelState.setText("按下鼠标左键")                elif mouseEvent.button() == Qt.MidButton:                    self.LabelState.setText("按下鼠标中键")                elif mouseEvent.buttons() == Qt.RightButton:                    self.LabelState.setText("按下了鼠标右键")                '''装换图片大小'''                transform = QTransform()                transform.scale(0.5, 0.5)                tmp = self.image1.transformed(transform)                self.label1.setPixmap(QPixmap.fromImage(tmp))            if event.type() == QEvent.MouseButtonRelease:                self.LabelState.setText("释放鼠标键")                self.label1.setPixmap(QPixmap.fromImage(self.image2))        elif watched == self.label3:            if event.type() == QEvent.MouseButtonPress:                mouseEvent = QMouseEvent(event)                if mouseEvent.buttons() == Qt.LeftButton:                    self.LabelState.setText("按下鼠标左键")                elif mouseEvent.button() == Qt.MidButton:                    self.LabelState.setText("按下鼠标中键")                elif mouseEvent.buttons() == Qt.RightButton:                    self.LabelState.setText("按下了鼠标右键")                '''装换图片大小'''                transform = QTransform()                transform.scale(0.5, 0.5)                tmp = self.image2.transformed(transform)                self.label3.setPixmap(QPixmap.fromImage(tmp))            if event.type() == QEvent.MouseButtonRelease:                self.LabelState.setText("释放鼠标键")                self.label3.setPixmap(QPixmap.fromImage(self.image3))        return QDialog.eventFilter(self, watched, event)if __name__ == "__main__":    app = QApplication(sys.argv)    dialog = EventFilter()    dialog.show()    sys.exit(app.exec_())
  • 运行效果如下:
    在这里插入图片描述

二、窗口数据传递

  • 一个应用往往有一个以上的窗口,窗口本身以及窗口之间往往需要进行数据传递。
  • 对于多窗口的窗口之间的数据传递,一种是主窗口获取子窗口中控件的属性;另一种通过信号与槽机制,具体就是子窗口发射信号,主窗口的槽函数接收信号。

1、同个窗口的不同控件数据传递

  • 在典型应用中,一个窗口控件的变化往往会引起另一个窗口控件的变化,这种操作可以利用信号与槽机制实现,示例代码如下:
    # -*- coding:utf-8 -*-# Time : 2019/09/16 下午 8:21 # Author : 御承扬# e-mail:2923616405@qq.com# project:  PyQt5# File : SignalSlot07.py # @software: PyCharmfrom PyQt5.QtGui import *from PyQt5.QtWidgets import *from PyQt5.QtCore import *import sysclass WinForm(QWidget):    def __init__(self):        super(WinForm, self).__init__()        self.initUI()    def initUI(self):        self.setWindowIcon(QIcon("./images/Python2.ico"))        self.setWindowTitle("信号与槽:连接滑块 LCD")        self.setGeometry(300, 300, 350, 150)        lcd = QLCDNumber(self)        slider = QSlider(Qt.Horizontal, self)        vBox = QVBoxLayout()        vBox.addWidget(lcd)        vBox.addWidget(slider)        self.setLayout(vBox)        slider.valueChanged.connect(lcd.display)if __name__ == "__main__":    app = QApplication(sys.argv)    win = WinForm()    win.show()    sys.exit(app.exec_())
  • 效果如下:
    在这里插入图片描述

2、多窗口传递数据:属性

  • 一般是主窗口调用一个子窗口,子窗口关闭时将数据传输给主窗口。
  • 主窗口代码如下:
    # -*- coding:utf-8 -*-# Time : 2019/09/16 下午 9:01 # Author : 御承扬# e-mail:2923616405@qq.com# project:  PyQt5# File : CAllDialogMainWin.py # @software: PyCharmfrom 信号与槽.DateDialog import DateDialogfrom PyQt5.QtGui import *from PyQt5.QtWidgets import *from PyQt5.QtCore import *import sysclass MainWin(QWidget):    def __init__(self, parent=None):        super(MainWin, self).__init__(parent)        self.resize(400, 90)        self.setWindowIcon(QIcon("./images/Python2.ico"))        self.setWindowTitle("窗口传递数据")        self.lineEdit = QLineEdit(self)        self.button1 = QPushButton("弹出对话框1")        self.button1.clicked.connect(self.onButton1Click)        self.button2 = QPushButton('弹出对话框2')        self.button2.clicked.connect(self.onButton2Click)        gridLayout = QGridLayout()        gridLayout.addWidget(self.lineEdit)        gridLayout.addWidget(self.button1)        gridLayout.addWidget(self.button2)        self.setLayout(gridLayout)    def onButton1Click(self):        dialog = DateDialog(self)        result = dialog.exec_()        date = dialog.dateTime()        self.lineEdit.setText(date.date().toString())        print('\n 日期对话框的返回值')        print('date=%s' % str(date.date()))        print('time=%s' % str(date.time()))        print('result=%s' % result)        dialog.destroy()    def onButton2Click(self):        date, time, result = DateDialog.getDateTime()        self.lineEdit.setText(date.toString())        print('\n 日期对话框的返回值')        print('date=%s' % str(date))        print('time=%s' % str(date))        print('result=%s' % result)if __name__ == "__main__":    app = QApplication(sys.argv)    form = MainWin()    form.show()    sys.exit(app.exec_())
  • 子窗口代码如下:
    # -*- coding:utf-8 -*-# Time : 2019/09/16 下午 8:50 # Author : 御承扬# e-mail:2923616405@qq.com# project:  PyQt5# File : DateDialog.py # @software: PyCharmfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import *class DateDialog(QDialog):    def __init__(self, parent=None):        super(DateDialog, self).__init__(parent)        self.setWindowTitle('DateDialog')        self.setWindowIcon(QIcon("./images/Python2.ico"))        self.resize(100, 100)        layout = QVBoxLayout(self)        self.datetime = QDateTimeEdit(self)        self.datetime.resize(150, 20)        self.datetime.setCalendarPopup(True)        self.datetime.setDateTime(QDateTime.currentDateTime())        buttons = QDialogButtonBox(            QDialogButtonBox.Ok | QDialogButtonBox.Cancel,            Qt.Horizontal, self)        buttons.accepted.connect(self.accept)        buttons.rejected.connect(self.reject)        layout.addWidget(buttons)    def dateTime(self):        return self.datetime.dateTime()    @staticmethod    def getDateTime(parent=None):        dialog = DateDialog(parent)        result = dialog.exec_()        date = dialog.dateTime()        return (date.date(), date.time(), result == QDialog.Accepted)
  • 运行效果:
    在这里插入图片描述

3、多窗口数据传递:信号与槽

  • 这种模式下,一般是子窗口发射信号,主窗口的槽函数捕捉信号,然后获取信号中携带的数据;信号分为 PyQt5 的内置信号和自定义信号。
  • 示例代码如下:
    # -*- coding:utf-8 -*-# Time : 2019/09/20 下午 8:37 # Author : 御承扬# e-mail:2923616405@qq.com# project:  PyQt5# File : DateDialog02.py # @software: PyCharmfrom PyQt5.QtGui import *from PyQt5.QtWidgets import *from PyQt5.QtCore import *class DateDialog(QDialog):    Signal_OneParameter = pyqtSignal(str)    def __init__(self, parent=None):        super(DateDialog, self).__init__(parent)        self.setWindowIcon(QIcon("./images/Python2.ico"))        self.setWindowTitle('Child Dialog: Submit Signal')        layout = QVBoxLayout(self)        self.label = QLabel(self)        self.label.setText('前者发射内置信号\n后者发射自定义信号')        self.datetime_inner = QDateTimeEdit(self)        self.datetime_inner.setCalendarPopup(True)        self.datetime_inner.setDateTime(QDateTime.currentDateTime())        self.datetime_emit = QDateTimeEdit(self)        self.datetime_emit.setCalendarPopup(True)        self.datetime_emit.setDateTime(QDateTime.currentDateTime())        layout.addWidget(self.label)        layout.addWidget(self.datetime_inner)        layout.addWidget(self.datetime_emit)        buttons = QDialogButtonBox(            QDialogButtonBox.Ok | QDialogButtonBox.Cancel,            Qt.Horizontal, self)        buttons.accepted.connect(self.accept)        buttons.rejected.connect(self.reject)        layout.addWidget(buttons)        self.datetime_emit.dateTimeChanged.connect(self.emit_signal)    def emit_signal(self):        date_str = self.datetime_emit.dateTime().toString()        self.Signal_OneParameter.emit(date_str)
    # -*- coding:utf-8 -*-# Time : 2019/09/20 下午 8:56 # Author : 御承扬# e-mail:2923616405@qq.com# project:  PyQt5# File : CallDialogMainWin2.py # @software: PyCharmfrom 信号与槽.DateDialog02 import DateDialogfrom PyQt5.QtGui import *from PyQt5.QtWidgets import *from PyQt5.QtCore import *import sysclass WinForm(QWidget):    def __init__(self, parent=None):        super(WinForm, self).__init__(parent)        self.resize(400, 90)        self.setWindowTitle('信号与槽传递参数示例')        self.setWindowIcon(QIcon("./images/Python2.ico"))        self.open_btn = QPushButton('获取时间')        self.lineEdit_inner = QLineEdit(self)        self.lineEdit_emit = QLineEdit(self)        self.open_btn.clicked.connect(self.openDialog)        self.lineEdit_inner.setText('接收子窗口内置信号的时间')        self.lineEdit_emit.setText('接收子窗口自定义信号的时间')        grid = QGridLayout()        grid.addWidget(self.lineEdit_inner)        grid.addWidget(self.lineEdit_emit)        grid.addWidget(self.open_btn)        self.setLayout(grid)    def openDialog(self):        dialog = DateDialog(self)        dialog.datetime_inner.dateChanged.connect(self.deal_inner_slot)        dialog.Signal_OneParameter.connect(self.deal_emit_slot)        dialog.show()    def deal_inner_slot(self, date):        self.lineEdit_inner.setText(date.toString())    def deal_emit_slot(self, dateStr):        self.lineEdit_emit.setText(dateStr)if __name__ == "__main__":    app = QApplication(sys.argv)    form = WinForm()    form.show()    sys.exit(app.exec_())
  • 效果如下:
    在这里插入图片描述
    在这里插入图片描述

转载地址:http://qtqgn.baihongyu.com/

你可能感兴趣的文章
color vector using in plotting example points and lines between corresponding vertices
查看>>
laplacian,degree,adjacency and oriented incidence matrix, differential and laplacian coordinates
查看>>
mex 里面调用matlab函数
查看>>
CUDA里面GRID, BLOCK 边界检测
查看>>
matlab中cuda编程中分配grid和block dimension的时候的注意事项
查看>>
GPU CUDA and MEX Programming
查看>>
arrayfun用法
查看>>
矩阵积分
查看>>
laplacian matrix
查看>>
cotangent matrix or laplacian mesh operator
查看>>
Minimizing quadratic energies with constant constraints
查看>>
Python-第三方库requests详解
查看>>
暴力破解黄巴登录网站
查看>>
python多线程
查看>>
read selection
查看>>
optimization on macOS
查看>>
Template-Based 3D Model Fitting Using Dual-Domain Relaxation
查看>>
install libfreenect2 on ubuntu 16.04
查看>>
how to use automake to build files
查看>>
using matlab drawing line graph for latex
查看>>