當點擊?QLabel
?時,正常情況下并不會直接觸發?MyWidget
?的?mousePressEvent
?函數,原因在于事件的傳遞機制和事件過濾器的存在。下面詳細分析這個過程:
事件傳遞機制
在 Qt 里,事件的傳遞是從子控件往父控件冒泡的。不過,在事件到達目標控件(也就是子控件)的事件處理函數之前,會先經過事件過濾器。
結合代碼分析
事件過濾器部分
cpp
bool eventFilter(QObject *watched, QEvent *event) override {if (watched->objectName() == "childLabel" && event->type() == QEvent::MouseButtonPress) {QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);qDebug() << "[事件過濾器] 子控件被點擊,全局坐標:" << mouseEvent->globalPos();return true; // 攔截事件,不再傳遞到子控件的mousePressEvent}return QWidget::eventFilter(watched, event);
}
當點擊?QLabel
?時,事件會先被傳遞到?MyWidget
?的?eventFilter
?函數。在這個函數中,會檢查被監視的對象是否為?childLabel
?且事件類型是否為鼠標點擊事件。要是條件滿足,就會輸出點擊的全局坐標信息,并且返回?true
。返回?true
?意味著事件被攔截,不會再傳遞到?QLabel
?的?mousePressEvent
?函數,更不會繼續冒泡到?MyWidget
?的?mousePressEvent
?函數。
mousePressEvent
?函數
cpp
void mousePressEvent(QMouseEvent *event) override {if (event->button() == Qt::LeftButton) {qDebug() << "[對象處理] 左鍵點擊位置:" << event->pos();event->accept();} else {QWidget::mousePressEvent(event);}
}
這個函數是?MyWidget
?的鼠標點擊事件處理函數。只有當點擊的是?MyWidget
?本身(而非其子控件?QLabel
),或者事件過濾器沒有攔截事件且事件冒泡到?MyWidget
?時,這個函數才會被觸發。
觸發?MyWidget
?的?mousePressEvent
?函數的情況
- 點擊?
MyWidget
?非子控件區域:若點擊的是?MyWidget
?中不包含?QLabel
?的區域,事件會直接觸發?MyWidget
?的?mousePressEvent
?函數。 - 事件過濾器不攔截事件:若在?
eventFilter
?函數中,對于點擊?QLabel
?的事件返回?false
,那么事件會繼續傳遞到?QLabel
?的?mousePressEvent
?函數(前提是?QLabel
?重寫了該函數),若?QLabel
?沒有處理該事件,事件就會冒泡到?MyWidget
?的?mousePressEvent
?函數。
總結
點擊?QLabel
?時,由于事件過濾器攔截了事件,所以不會觸發?MyWidget
?的?mousePressEvent
?函數。若要觸發該函數,要么點擊?MyWidget
?的非子控件區域,要么讓事件過濾器不攔截事件。
編輯
分享
除了鼠標點擊事件,還有哪些常見的事件類型?
如何在事件過濾器中判斷事件的具體類型?
如何在父控件中處理子控件的事件?