Qt 事件管理

參考:Events and signals in PyQt5

所有的應(yīng)用都是事件驅(qū)動(dòng)的。事件大部分都是由用戶的行為產(chǎn)生的,當(dāng)然也有其他的事件產(chǎn)生方式,比如網(wǎng)絡(luò)的連接,窗口管理器或者定時(shí)器等。調(diào)用應(yīng)用的 exec_() 方法時(shí),應(yīng)用會(huì)進(jìn)入主循環(huán),主循環(huán)會(huì)監(jiān)聽和分發(fā)事件。

在事件模型中,有三個(gè)角色:

  • 事件源(event source):發(fā)生了狀態(tài)改變的對(duì)象,用于生成事件。
  • 事件對(duì)象(event object):將狀態(tài)更改封裝在事件源中。
  • 事件目標(biāo)(event target):即要通知的對(duì)象。事件源對(duì)象將處理事件的任務(wù)委托給事件目標(biāo)。

1 事件和信號(hào)及槽的區(qū)別

信號(hào)與槽可以說是對(duì)事件處理機(jī)制的高級(jí)封裝,如果說事件是用來創(chuàng)建窗口控件的,那么信號(hào)與槽就是用來對(duì)這個(gè)窗口控件進(jìn)行使用的。比如一個(gè)按鈕,當(dāng)我們使用這個(gè)按鈕時(shí),只關(guān)心 clicked 信號(hào),至于這個(gè)按鈕如何接收并處理鼠標(biāo)點(diǎn)擊事件,然后再發(fā)射這個(gè)信號(hào),則不用關(guān)心。但是如果要重載一個(gè)按鈕,這時(shí)就要關(guān)心這個(gè)問題了。比如可以改變它的行為:在鼠標(biāo)按鍵按下時(shí)觸發(fā) clicked 信號(hào),而不是在釋放時(shí)。

PyQt5/PySide2 是對(duì) Qt 的封裝,Qt 程序是事件驅(qū)動(dòng)的,它的每個(gè)動(dòng)作都由幕后某個(gè)事件所觸發(fā)。Qt 事件的類型有很多,常見的 Qt 事件如下:

  • 鍵盤事件:按鍵按下和松開。
  • 鼠標(biāo)事件:鼠標(biāo)指針移動(dòng)、鼠標(biāo)按鍵按下和松開。
  • 拖放事件:用鼠標(biāo)進(jìn)行拖放。
  • 滾輪事件:鼠標(biāo)滾輪滾動(dòng)。
  • 繪屏事件:重繪屏幕的某些部分。
  • 定時(shí)事件:定時(shí)器到時(shí)。
  • 焦點(diǎn)事件:鍵盤焦點(diǎn)移動(dòng)。
  • 進(jìn)入和離開事件:鼠標(biāo)指針移入 Widget 內(nèi),或者移出。
  • 移動(dòng)事件:Widget 的位置改變。
  • 大小改變事件:Widget 的大小改變。
  • 顯示和隱藏事件:Widget 顯示和隱藏。
  • 窗口事件:窗口是否為當(dāng)前窗口。

還有一些常見的 Qt 事件,比如 Socket 事件、剪貼板事件、字體改變事件、布局改變事件等。

下面看一個(gè) LCD 的例子:

from xinet import QtWidgets, QtCore, QtGui, Signal
from xinet.run_qt import run


class LCDNumber(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.initUI()
        lcd = QtWidgets.QLCDNumber(self)
        sld = QtWidgets.QSlider(QtCore.Qt.Horizontal)  # 橫向滑塊
        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(lcd)
        vbox.addWidget(sld)
        self.setLayout(vbox)
        sld.valueChanged.connect(lcd.display)

    def initUI(self):
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal and slot')


if __name__ == "__main__":
    run(LCDNumber)

效果:

其中 sld.valueChanged 是滑塊的值改變的信號(hào),lcd.display 是 LCD 數(shù)字的槽函數(shù)。即 sld 發(fā)送被改變的值給 lcd 并顯示出來。

2 使用事件處理的方法

PyQt5/PySide2 提供了如下 5 種事件處理和過濾方法(由弱到強(qiáng)),其中只有前兩種方法使用最頻繁。

  1. 重新實(shí)現(xiàn)事件函數(shù):比如 mousePressEvent()keyPressEvent()paintEvent()。這是最常規(guī)的事件處理方法。
  2. 重新實(shí)現(xiàn) QObject.event():一般用在 PyQt5/PySide2 沒有提供該事件的處理函數(shù)的情況下,即增加新事件時(shí)。
  3. 安裝事件過濾器 :如果對(duì) QObject 調(diào)用 installEventFilter,則相當(dāng)于為這個(gè) QObject 安裝了一個(gè)事件過濾器,對(duì)于 QObject 的全部事件來說,它們都會(huì)先傳遞到事件過濾函數(shù) eventFilter 中,在這個(gè)函數(shù)中我們可以拋棄或者修改這些事件,比如可以對(duì)自己感興趣的事件使用自定義的事件處理機(jī)制,對(duì)其他事件使用默認(rèn)的事件處理機(jī)制。由于這種方法會(huì)對(duì)調(diào)用 installEventFilter 的所有 QObject 的事件進(jìn)行過濾,因此如果要過濾的事件比較多,則會(huì)降低程序的性能。
  4. QApplication 中安裝事件過濾器 :這種方法比上一種方法更強(qiáng)大:QApplication 的事件過濾器將捕獲所有 QObject 的所有事件,而且第一個(gè)獲得該事件。也就是說,在將事件發(fā)送給其他任何一個(gè)事件過濾器之前(就是在第三種方法之前),都會(huì)先發(fā)送給 QApplication 的事件過濾器。
  5. 重新實(shí)現(xiàn) QApplicationnotify() 方法 :使用 notify()來分發(fā)事件。要想在任何事件處理器之前捕獲事件,唯一的方法就是重新實(shí)現(xiàn) QApplicationnotify()。在實(shí)踐中,在調(diào)試時(shí)才會(huì)使用這種方法。

3 重新實(shí)現(xiàn)事件函數(shù)

重載 keyPressEvent 函數(shù),實(shí)現(xiàn)按下 Esc 鍵程序就會(huì)退出:

from xinet import QtWidgets, QtCore, QtGui, Signal
from xinet.run_qt import run


class EscWin(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.initUI()
        
    def initUI(self):
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Event handler')

    def keyPressEvent(self, e):
        if e.key() == QtCore.Qt.Key_Escape:
            self.close()


if __name__ == "__main__":
    run(EscWin)

4 事件對(duì)象

事件對(duì)象是用來描述一系列的事件自身屬性的對(duì)象。

這個(gè)示例中,我們在一個(gè)組件里顯示鼠標(biāo)的 X 和 Y 坐標(biāo)。

from xinet import QtWidgets, QtCore, QtGui, Signal
from xinet.run_qt import run


class Window(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.initUI()

    def initUI(self):
        grid = QtWidgets.QGridLayout()
        x = 0
        y = 0
        self.text = f'x: {x},  y: {y}'
        self.label = QtWidgets.QLabel(self.text, self)
        grid.addWidget(self.label, 0, 0, QtCore.Qt.AlignTop)
        # 事件追蹤默認(rèn)沒有開啟,當(dāng)開啟后才會(huì)追蹤鼠標(biāo)的點(diǎn)擊事件
        self.setMouseTracking(True)
        self.setLayout(grid)
        self.setGeometry(300, 300, 450, 300)
        self.setWindowTitle('Event object')

    def mouseMoveEvent(self, e):
        x = e.x()
        y = e.y()
        text = f'x: {x},  y: {y}'
        self.label.setText(text)


if __name__ == "__main__":
    run(Window)

效果:

5 事件發(fā)送

有時(shí)候我們會(huì)想知道是哪個(gè)組件發(fā)出了一個(gè)信號(hào),sender() 方法能搞定這件事。

from xinet import QtWidgets, QtCore, QtGui, Signal
from xinet.run_qt import run


class Window(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.init_Ui()

    def init_Ui(self):
        btn1 = QtWidgets.QPushButton("Button 1", self)
        btn1.move(30, 50)
        btn2 = QtWidgets.QPushButton("Button 2", self)
        btn2.move(150, 50)

        btn1.clicked.connect(self.buttonClicked)
        btn2.clicked.connect(self.buttonClicked)

        self.statusBar()
        self.setGeometry(300, 300, 450, 350)
        self.setWindowTitle('Event sender')

    def buttonClicked(self):
        sender = self.sender()
        self.statusBar().showMessage(sender.text() + ' was pressed')


if __name__ == "__main__":
    run(Window)

這個(gè)例子里有兩個(gè)按鈕,buttonClicked() 方法決定了是哪個(gè)按鈕能調(diào)用 sender() 方法。我們用調(diào)用 sender() 方法的方式?jīng)Q定了事件源。狀態(tài)欄顯示了被點(diǎn)擊的按鈕。

程序展示:

如果在信號(hào)激活的插槽中調(diào)用,則PySide2.QtCore.QObject.sender()返回指向發(fā)送信號(hào)的對(duì)象的指針;否則返回None。指針僅在執(zhí)行從該對(duì)象的線程上下文調(diào)用此函數(shù)的插槽期間有效。

如果發(fā)送方被銷毀或插槽與發(fā)送方的信號(hào)斷開連接,則此函數(shù)返回的指針將變?yōu)闊o效。

警告:此功能違反了模塊化的面向?qū)ο笤瓌t。但是,當(dāng)多個(gè)信號(hào)連接到單個(gè)插槽時(shí),訪問發(fā)送者可能會(huì)很有用。

警告:如上所述,當(dāng)通過DirectConnection從不同于該對(duì)象線程的線程中調(diào)用插槽時(shí),此函數(shù)的返回值無效。不要在這種情況下使用此功能。

6 發(fā)送自定義信號(hào)

QObject 實(shí)例能發(fā)送事件信號(hào)。下面的例子是發(fā)送自定義的信號(hào)。

from xinet import QtWidgets, QtCore, QtGui, Signal
from xinet.run_qt import run


class Communicate(QtCore.QObject):
    closeApp = Signal()


class Window(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.init_Ui()

    def init_Ui(self):
        self.c = Communicate()
        self.c.closeApp.connect(self.close)
        self.setGeometry(300, 300, 450, 350)
        self.setWindowTitle('Emit signal')

    def mousePressEvent(self, event):
        self.c.closeApp.emit()


if __name__ == "__main__":
    run(Window)

創(chuàng)建了一個(gè)叫 closeApp 的信號(hào),這個(gè)信號(hào)會(huì)在鼠標(biāo)按下的時(shí)候觸發(fā),事件與 QMainWindow 的 槽函數(shù) close 綁定 。

點(diǎn)擊窗口的時(shí)候,發(fā)送 closeApp 信號(hào),程序終止。

7 經(jīng)典案例

from xinet import QtWidgets, QtCore, QtGui, Signal
from xinet.run_qt import run

QPainter = QtGui.QPainter
QMenu = QtWidgets.QMenu
QEvent, QTimer, Qt = QtCore.QEvent, QtCore.QTimer, QtCore.Qt


class Window(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.init_Ui()
        # 避免窗口大小重繪事件的影響,可以把參數(shù)0改變成3000(3秒),然后在運(yùn)行,就可以明白這行代碼的意思。
        QTimer.singleShot(0, self.give_help)
        self.justDoubleClicked = False
        self.key = ""
        self.text = ""
        self.message = ""

    def init_Ui(self):
        self.resize(400, 300)
        self.move(100, 100)
        self.setWindowTitle("Events")

    def give_help(self):
        self.text = "請點(diǎn)擊這里觸發(fā)追蹤鼠標(biāo)功能"
        self.update()  # 重繪事件,也就是觸發(fā)paintEvent函數(shù)。

    def closeEvent(self, event):
        '''重新實(shí)現(xiàn)關(guān)閉事件'''
        print("Closed")

    def one(self):
        '''上下文菜單槽函數(shù)'''
        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 contextMenuEvent(self, event):
        '''重新實(shí)現(xiàn)上下文菜單事件'''
        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 clearMessage(self):
        '''清空消息文本的槽函數(shù)'''
        self.message = ""

    def paintEvent(self, event):
        '''重新實(shí)現(xiàn)繪制事件'''
        text = self.text
        i = text.find("\n\n")
        if i >= 0:
            text = text[0:i]
        if self.key:  # 若觸發(fā)了鍵盤按鈕,則在文本信息中記錄這個(gè)按鈕信息。
            text += "\n\n你按下了: {0}".format(self.key)
        painter = QPainter(self)
        painter.setRenderHint(QPainter.TextAntialiasing)
        painter.drawText(self.rect(), Qt.AlignCenter, text)  # 繪制信息文本的內(nèi)容
        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 resizeEvent(self, event):
        '''重新實(shí)現(xiàn)調(diào)整窗口大小事件'''
        self.text = "調(diào)整窗口大小為: QSize({0}, {1})".format(
            event.size().width(), event.size().height())
        self.update()

    def mouseReleaseEvent(self, event):
        '''重新實(shí)現(xiàn)鼠標(biāo)釋放事件'''
        # 若鼠標(biāo)釋放為雙擊釋放,則不跟蹤鼠標(biāo)移動(dòng)
        # 若鼠標(biāo)釋放為單擊釋放,則需要改變跟蹤功能的狀態(tài),如果開啟跟蹤功能的話就跟蹤,不開啟跟蹤功能就不跟蹤
        if self.justDoubleClicked:
            self.justDoubleClicked = False
        else:
            self.setMouseTracking(not self.hasMouseTracking())  # 單擊鼠標(biāo)
            if self.hasMouseTracking():
                self.text = "開啟鼠標(biāo)跟蹤功能.\n" + \
                            "請移動(dòng)一下鼠標(biāo)!\n" + \
                            "單擊鼠標(biāo)可以關(guān)閉這個(gè)功能"
            else:
                self.text = "關(guān)閉鼠標(biāo)跟蹤功能.\n" + \
                            "單擊鼠標(biāo)可以開啟這個(gè)功能"
            self.update()

    def mouseMoveEvent(self, event):
        '''重新實(shí)現(xiàn)鼠標(biāo)移動(dòng)事件'''
        if not self.justDoubleClicked:
            globalPos = self.mapToGlobal(event.pos())  # 窗口坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo)
            self.text = """鼠標(biāo)位置:
            窗口坐標(biāo)為:QPoint({0}, {1}) 
            屏幕坐標(biāo)為:QPoint({2}, {3}) """.format(event.pos().x(), event.pos().y(), globalPos.x(), globalPos.y())
            self.update()

    def mouseDoubleClickEvent(self, event):
        '''重新實(shí)現(xiàn)鼠標(biāo)雙擊事件'''
        self.justDoubleClicked = True
        self.text = "你雙擊了鼠標(biāo)"
        self.update()

    def keyPressEvent(self, event):
        '''重新實(shí)現(xiàn)鍵盤按下事件'''
        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:
            super().keyPressEvent(event)

    def event(self, event):
        '''重新實(shí)現(xiàn)其他事件,適用于PyQt沒有提供該事件的處理函數(shù)的情況,
           Tab鍵由于涉及焦點(diǎn)切換,不會(huì)傳遞給keyPressEvent,因此,需要在這里重新定義。
        '''
        if (event.type() == QEvent.KeyPress and
                event.key() == Qt.Key_Tab):
            self.key = "在event()中捕獲Tab鍵"
            self.update()
            return True
        return super().event(event)


if __name__ == "__main__":
    run(Window)

update() 函數(shù)的作用是更新窗口。由于在窗口更新過程中會(huì)觸發(fā)一次 paintEvent 函數(shù)(paintEvent 是窗口基類 QWidget 的內(nèi)部函數(shù)),因此在本例中 update 函數(shù)的作用等同于 paintEvent 函數(shù)。

對(duì)于上下文菜單事件,主要影響 message 變量的結(jié)果,paintEvent 負(fù)責(zé)把這個(gè)變量在窗口底部輸出。

繪制事件是代碼的核心事件,它的主要作用是時(shí)刻跟蹤 textmessage 這兩個(gè)變量的信息,并把 text 的內(nèi)容繪制到窗口的中部,把 message 的內(nèi)容繪制到窗口的底部(保持 5 秒后就會(huì)被清空)。

8 安裝事件過濾器

from xinet import QtWidgets, QtCore, QtGui, Signal
from xinet.run_qt import run

QPainter = QtGui.QPainter
QMenu = QtWidgets.QMenu
QLabel = QtWidgets.QLabel
QImage = QtGui.QImage
QEvent, QTimer, Qt = QtCore.QEvent, QtCore.QTimer, QtCore.Qt


class EventFilter(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("事件過濾器")

        self.label1 = QLabel("請點(diǎn)擊")
        self.label2 = QLabel("請點(diǎn)擊")
        self.label3 = QLabel("請點(diǎn)擊")
        self.LabelState = QLabel("test")

        self.image1 = QImage("images/cartoon1.ico")
        self.image2 = QImage("images/cartoon1.ico")
        self.image3 = QImage("images/cartoon1.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 = QtWidgets.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):
        if watched == self.label1:  # 只對(duì)label1的點(diǎn)擊事件進(jìn)行過濾,重寫其行為,其他的事件會(huì)被忽略
            if event.type() == QEvent.MouseButtonPress:  # 這里對(duì)鼠標(biāo)按下事件進(jìn)行過濾,重寫其行為
                mouseEvent = QtGui.QMouseEvent(event)
                if mouseEvent.buttons() == Qt.LeftButton:
                    self.LabelState.setText("按下鼠標(biāo)左鍵")
                elif mouseEvent.buttons() == Qt.MidButton:
                    self.LabelState.setText("按下鼠標(biāo)中間鍵")
                elif mouseEvent.buttons() == Qt.RightButton:
                    self.LabelState.setText("按下鼠標(biāo)右鍵")

                '''轉(zhuǎn)換圖片大小'''
                transform = QtCore.QTransform()
                transform.scale(0.5, 0.5)
                tmp = self.image1.transformed(transform)
                self.label1.setPixmap(QPixmap.fromImage(tmp))
            if event.type() == QEvent.MouseButtonRelease:  # 這里對(duì)鼠標(biāo)釋放事件進(jìn)行過濾,重寫其行為
                self.LabelState.setText("釋放鼠標(biāo)按鈕")
                self.label1.setPixmap(QtGui.QPixmap.fromImage(self.image1))
        return super().eventFilter(watched, event)  # 其他情況會(huì)返回系統(tǒng)默認(rèn)的事件處理方法。

if __name__ == "__main__":
    run(EventFilter)

效果:

對(duì)于使用事件過濾器,關(guān)鍵是要做好兩步。
對(duì)要過濾的控件設(shè)置 installEventFilter,這些控件的所有事件都會(huì)被 eventFilter 函數(shù)接收并處理。

installEventFilter的使用方法如下:

self.label1.installEventFilter(self) 
self.label2.installEventFilter(self) 
self.label3.installEventFilter(self)

在 QApplication 中安裝事件過濾器)的使用也非常簡單,與第三種事件處理方法相比,只需要簡單地修改兩處代碼即可。

屏蔽三個(gè) label 標(biāo)簽控件的 installEventFilter 代碼:

# self.label1.installEventFilter(self) 
# self.label2.installEventFilter(self) 
# self.label3.installEventFilter(self) 

對(duì)于在 QApplication 中安裝 installEventFilter,下面代碼的意思是 dialog 的所有事件都要經(jīng)過 eventFilter 函數(shù)處理,而不僅僅是三個(gè)標(biāo)簽控件的事件。

if __name__=='__main__': 
    app=QApplication(sys.argv) 
    dialog=EventFilter() 
    app.installEventFilter(dialog) 
    dialog.show() 
    app.exec_() 

完整代碼:

# -*- coding: utf-8 -*-
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys


class EventFilter(QDialog):
    def __init__(self, parent=None):
        super(EventFilter, self).__init__(parent)
        self.setWindowTitle("事件過濾器")

        self.label1 = QLabel("請點(diǎn)擊")
        self.label2 = QLabel("請點(diǎn)擊")
        self.label3 = QLabel("請點(diǎn)擊")
        self.LabelState = QLabel("test")

        self.image1 = QImage("images/cartoon1.ico")
        self.image2 = QImage("images/cartoon1.ico")
        self.image3 = QImage("images/cartoon1.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):
        print(type(watched))
        if watched == self.label1:  # 只對(duì)label1的點(diǎn)擊事件進(jìn)行過濾,重寫其行為,其他的事件會(huì)被忽略
            if event.type() == QEvent.MouseButtonPress:  # 這里對(duì)鼠標(biāo)按下事件進(jìn)行過濾,重寫其行為
                mouseEvent = QMouseEvent(event)
                if mouseEvent.buttons() == Qt.LeftButton:
                    self.LabelState.setText("按下鼠標(biāo)左鍵")
                elif mouseEvent.buttons() == Qt.MidButton:
                    self.LabelState.setText("按下鼠標(biāo)中間鍵")
                elif mouseEvent.buttons() == Qt.RightButton:
                    self.LabelState.setText("按下鼠標(biāo)右鍵")

                '''轉(zhuǎn)換圖片大小'''
                transform = QTransform()
                transform.scale(0.5, 0.5)
                tmp = self.image1.transformed(transform)
                self.label1.setPixmap(QPixmap.fromImage(tmp))
            if event.type() == QEvent.MouseButtonRelease:  # 這里對(duì)鼠標(biāo)釋放事件進(jìn)行過濾,重寫其行為
                self.LabelState.setText("釋放鼠標(biāo)按鈕")
                self.label1.setPixmap(QPixmap.fromImage(self.image1))
        return QDialog.eventFilter(self, watched, event)  # 其他情況會(huì)返回系統(tǒng)默認(rèn)的事件處理方法。


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = EventFilter()
    app.installEventFilter(dialog)
    dialog.show()
    sys.exit(app.exec_())

可見。第四種事件處理方法確實(shí)過濾了所有事件,而不像第三種方法那樣只過濾三個(gè)標(biāo)簽控件的事件。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。