---
# System prepended metadata

title: Pyside QDialog & EventFilter
tags: [Python]

---

Pyside QDialog & EventFilter
===

###### tags: `Python`

### 緣起
1. 按下Mainwindow的button創建一個dialog，並傳signal給dialog
:::danger
關閉dialog時不會將自己砍掉，所以關掉後再次點擊會傳出兩個signal給兩個同名的人
:::
2. 偵測滑鼠點擊Dialog的位置和元件，以做不同動作
:::danger
卻發現label和frame沒有default的clicked signal可以用
:::


### 解法
1. 偵測dialog關閉事件，若發生就把自己砍掉
    ```python
    '''直接寫在dialog的class裡'''
    def closeEvent(self, event):
        self.deleteLater()
        print("X is clicked")
    ```
    
2. 需要對dialog要偵測的元件註冊EventFilter
    ```python
    '''都寫在dialog class裡'''
    for w in self.findChildren(QtWidgets.QWidget)+[self]:
        w.installEventFilter(self)
        self.i = 0
    def eventFilter(self, obj, event):
        if event.type() == QtCore.QEvent.MouseButtonPress:
            if event.buttons() & QtCore.Qt.LeftButton:
                ...
        return super(RegAnalyzer, self).eventFilter(obj, event)
    ```
**坑**
* mainwindow 開啟Dialog有兩種call法 - show()和exec()
  show()開啟後，主執行緒還是在mainwindow這邊；
  exec()執行後則無法操控mainwindow，只能控制dialog
* 網上找到的註冊eventfilter方法都是先宣告dialog，然後直接在main function對其做註冊(如下)
```python
class MouseDetector(QtCore.QObject):
    i = 0
    def eventFilter(self, watched: QtCore.QObject, event: QtCore.QEvent) -> bool:
        if event.type() == event.MouseButtonPress:
            self.i += 1
            print(f"{self.i}: Mouse Pressed")
            print('mouse pressed', watched.objectName())
        return super().eventFilter(watched, event)

app = dialog()
mouseFilter = MouseDetector()
app.installEventFilter(mouseFilter)
```
* 但這個方法對show()或exec()生成的視窗無效，因此必須把事件寫在dialog裡面，如"解法2"所提。