PyQt5 註冊 EventFilter 以監聽元件的預設內建事件

上一篇提到提到了幾個元件綁定 Event 的方法,但那僅限與該 Object 提供給你用的事件,許多內建事件無法透過那些方法來監聽,例如 keyPressEvnetmouseButtonPress 等,就算有相應的事件可以用(例如 textChangedclicked),通常也只能「後」處理而且也不一定完全對應(例如 textChanged 就無法偵測到 Ctrl、Alt 那些修飾按鍵)。如果硬要監聽該 Event 的話可能會這樣做:

self.b1.mouseButtonPress = self.myBtnClicked

然後你就發現原本註冊好的事件沒反應了,這個作法的缺點就是會覆蓋掉原本該事件的預設行為,而這預設行為通常也是大家對 GUI 期望的行為。又例如在文字列裡按鍵盤會有文字會跑出來,硬把 keyPressEvnet 改成自定義功能的話變成你要自己實作那些消失的功能。

有沒有一個方法可以讓我們單純監聽某事件,甚至還能控制該事件的觸發與否呢?

EventFilter

有,就是本篇要介紹的 EventFilter(事件過濾)。此內建 Method 就是在提供我們一條路可以單純只監聽事件而不影響其原生功能,該做的事情只要條件允許還是會做,另一方面只要我們想要也可以隨時取消該事件的觸發。

例如我想要監聽文字框 lEquation,註冊的方法如下:

class Main(QMainWindow, ui.Ui_MainWindow):
    def __init__(self):
        # ...
        self.lEquation.installEventFilter(self)

    def eventFilter(self, obj, event):
        print(obj, event.type())
        return False # will not be filtered out (ie. event will be processed)

就這麼簡單,請預設 return False,否則所有事件都會被過濾掉,連 Paint(繪圖事件)都不例外於是就看不到元件了。

傳入的參數:

  • obj 可以讓你知道是誰被觸發了事件,同時註冊多個元件時才不會搞混
  • event 就是該事件的完整訊息

那個 installEventFilter 的參數傳入的物件參數是一個類似漏斗的功能,雖然範例將之設定為自己但其實不限定。PyQt 會去 call 該漏斗物件的 evenrFilter 以達到事件過濾的功能,只要確保有實作此 Method 即可。

Reference