PyQt5事件處理


事件介紹

事件的處理機制非常的復雜,屬於PyQt底層的事,不必我們關心,學會使用就行。如果說事件是用來創建窗口,那么信號與槽就是用來對這個控件進行處理。事件屬於低級的處理方式,信號與槽是高級的處理方式,一般信號與槽處理不了的問題,再使用事件處理。信號與槽功能強大使用簡單但是不能解決所有的問題,事件使用麻煩但是可以處理全部的問題。事件的處理主要是重載類方法,信號與槽的處理主要是綁定、發送以及處理。

事件

  1. 重寫mousePressEvent,keyPressEvent,paintEvent等方法,最常用(控件級)

  2. 重寫QObject.event方法,一般在PyQt沒有提供該事件的處理方法時使用(控件級)

  3. 安裝事件過濾器:如果對QObject調用installEventFilter,相當於對這個QObject對象添加了一個過濾器。對於QObject的全部事件來說,都會先經過過濾器的處理,在過濾器里面就可以進行我們自己的處理,比如修改丟棄等,慎用,因為會處理所有的事件,會降低效率(控件級)

  4. 在QApplication中安裝事件過濾器:比QObject的過濾器更強大,對所有的QObject的所有事件進行過濾,且第一時間捕獲。事件的過濾先經過QApplication的處理再進過QObject的處理,必須慎用(應用級)

  5. 重寫QApplication的notify方法,要想在任何事件被處理之前捕獲事件,唯一的方法就是重寫QApplication的notify方法,一般只在調試中使用(應用級)

 事件處理流程(紫色部分是應用級處理,綠色部分是對象級處理)

例子

import sys

from PyQt5.QtCore import QEvent
from PyQt5.QtWidgets import QApplication, QWidget

class MyWidget(QWidget):
    def __init__(self):
        super(MyWidget, self).__init__()

    def mousePressEvent(self, mouseEvent):
        print('MyWidget.mousePressEvent')
        return QWidget.mousePressEvent(self, mouseEvent)

    def event(self, event):
        if event.type() == QEvent.MouseButtonPress:
            print('MyWidget.event')
        return QWidget.event(self, event)

    def eventFilter(self, object, event):
        if event.type() == QEvent.MouseButtonPress:
            print('MyWidget.eventFilter')
        return QWidget.eventFilter(self, object, event)

class MyQApplication(QApplication):
    def __init__(self, param):
        super(MyQApplication, self).__init__(param)

    def notify(self, object, event):
        if event.type() == QEvent.MouseButtonPress:
            print('MyQApplication.notify')
        return QApplication.notify(self, object, event)

    def eventFilter(self, object, event):
        if event.type() == QEvent.MouseButtonPress:
            print('MyQApplication.eventFilter')
        return QApplication.eventFilter(self, object, event)

if __name__ == '__main__':
    app = MyQApplication(sys.argv)
    app.installEventFilter(app)
    w = MyWidget()
    w.installEventFilter(w)
    w.resize(500, 300)
    w.move(300, 300)
    w.setWindowTitle('Simple')
    w.show()
    sys.exit(app.exec_())

信號與槽

信號與槽是PyQt的核心機制,也是對象與對象之間的通信方法。信號與槽函數的對應方式是多對多,且信號可以連接信號。除了控件默認的信號外,可以自己定義和實現信號。

信號定義:

mySignal = pyqtSignal([param])

連接信號到槽:

mySignal.connect(handlerFunc)

發送信號:

mySignal.emit([param])

斷開信號與槽:

mySignal.disconnect(handlerFunc)

例子:自定義信號並實現與槽的鏈接

import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton

class MyWidget(QWidget):
    mySignal = pyqtSignal()

    def __init__(self):
        super(MyWidget, self).__init__()
        button = QPushButton(self)
        button.setText('點我')
        button.clicked.connect(self.buttonClicked)
        self.mySignal.connect(self.mySignalHandler)

    def buttonClicked(self):
        print('button clicked emit and handler')
        self.mySignal.emit()

    def mySignalHandler(self):
        print('my signal emit and handler')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWidget()
    w.resize(500, 300)
    w.move(300, 300)
    w.setWindowTitle('Simple')
    w.show()
    sys.exit(app.exec_())

信號與槽高級玩法

信號重載

import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton

class MyWidget(QWidget):
    # 無參數信號
    mySignal_no_aram = pyqtSignal()
    # 帶一個整型參數信號
    mySignal_int = pyqtSignal(int)
    # 帶一個整型或字符串信號
    mySignal_int_or_str = pyqtSignal([int], [str])
    # 帶兩個參數,int和srt 或 str和str
    mySignal_two_param = pyqtSignal([int, str], [str, str])

    def mySignal_no_aram_handler(self):
        print('mySignal_no_aram_handler')

    def mySignal_int_handler(self):
        print('mySignal_int_handler')

    def mySignal_int_or_str_int_handler(self):
        print('mySignal_int_or_str_int_handler')

    def mySignal_int_or_str_str_handler(self):
        print('mySignal_int_or_str_str_handler')

    def mySignal_two_param_int_str_handler(self):
        print('mySignal_two_param_int_str_handler')

    def mySignal_two_param_str_str_handler(self):
        print('mySignal_two_param_str_str_handler')

    def __init__(self):
        super(MyWidget, self).__init__()
        button = QPushButton(self)
        button.setText('點我')
        button.clicked.connect(self.onClicked)

        # 綁定信號到槽函數
        self.mySignal_no_aram.connect(self.mySignal_no_aram_handler)
        self.mySignal_int.connect(self.mySignal_int_handler)
        self.mySignal_int_or_str[int].connect(self.mySignal_int_or_str_int_handler)
        self.mySignal_int_or_str[str].connect(self.mySignal_int_or_str_str_handler)
        self.mySignal_two_param[int, str].connect(self.mySignal_two_param_int_str_handler)
        self.mySignal_two_param[str, str].connect(self.mySignal_two_param_str_str_handler)

    def onClicked(self):
        # 發送信號
        self.mySignal_no_aram.emit()
        self.mySignal_int.emit(1)
        self.mySignal_int_or_str[int].emit(2)
        self.mySignal_int_or_str[str].emit('abc')
        self.mySignal_two_param[int, str].emit(3, 'def')
        self.mySignal_two_param[str, str].emit('abc', 'def')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWidget()
    w.resize(500, 300)
    w.move(300, 300)
    w.setWindowTitle('Simple')
    w.show()
    sys.exit(app.exec_())

使用自定義參數

import sys
from functools import partial
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton

class MyWidget(QWidget):
    def __init__(self):
        super(MyWidget, self).__init__()
        button1 = QPushButton(self)
        button1.setText('button1')
        button1.move(10, 10)
        button2 = QPushButton(self)
        button2.setText('button2')
        button2.move(10, 50)

        # button1.clicked.connect(lambda: self.onClicked(button1))
        # button2.clicked.connect(lambda: self.onClicked(button2))
        # 等價
        button1.clicked.connect(partial(self.onClicked, button1))
        button2.clicked.connect(partial(self.onClicked, button2))

    def onClicked(self, btn):
        print("%s" % btn.text())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWidget()
    w.resize(500, 300)
    w.move(300, 300)
    w.setWindowTitle('Simple')
    w.show()
    sys.exit(app.exec_())

使用裝飾器定義信號與槽

import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton

class MyWidget(QWidget):
    def __init__(self):
        super(MyWidget, self).__init__()
        button = QPushButton(self)
        button.setText('點擊')
        
        # 設置發送者名稱
        button.setObjectName('button')
        # 實現綁定
        QtCore.QMetaObject.connectSlotsByName(self)

    # 槽函數命名規則:on_發送者名稱_發射信號名稱(self, param)
    @QtCore.pyqtSlot()
    def on_button_clicked(self):
        print('you clicked button')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWidget()
    w.resize(500, 300)
    w.move(300, 300)
    w.setWindowTitle('Simple')
    w.show()
    sys.exit(app.exec_())

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM