讓咱們首先來看一個例子:ide
//CustomButton.h #include <QWidget> #include <QPushButton> #include <QDebug>
class CustomButton : public QPushButton { Q_OBJECT
public: CustomButton(QWidget* parent = nullptr); ~CustomButton()=default;
protected: inline void onButtonClicked() { qDebug()<<"You click this!"; } };
CustomButton::CustomButton(QWidget* parent) :QPushButton(parent) { connect(this, &CustomButton::clicked, this, &CustomButton::onButtonClicked); }
//mian.cpp #include <QApplication>
int main(int argc, char *argv[]) { QApplication a(argc, argv); CustomButton customButton; customButton.setText(QString("This is a CustomButton")); customButton.show();
return a.exec(); }
很顯然這個例子在咱們點擊該按鈕的時候會在控制檯顯示:"You click this".函數
根據上面的例子咱們經過繼承QPushButton重寫了一個protected的事件處理函數:this
#include <QWidget> #include <QPushButton> #include <QDebug>
class CustomButton : public QPushButton { Q_OBJECT
public: CustomButton(QWidget* parent = nullptr); ~CustomButton()=default;
private: inline void onButtonClicked() { qDebug()<<"You click this!"; }
protected: virtual void mousePressEvent(QMouseEvent* e)override; };
#include <QMouseEvent>
CustomButton::CustomButton(QWidget* parent) :QPushButton(parent) { connect(this, &CustomButton::clicked, this, &CustomButton::onButtonClicked); }
void CustomButton::mousePressEvent(QMouseEvent* e) { if(e->button() == Qt::LeftButton){ qDebug()<<"you clicked left-key"; //emit clicked(); //注意這裏.
}else{ QPushButton::mousePressEvent(e); } }
運行發現居然顯示:"you clicked left-key"!!!!!!!!!!!!!!!設計
那麼爲何呢???咱們來仔細看一下代碼與上個例子不一樣之處在於咱們重寫了mousePressEvent()這個函數,經過代碼頁確定能code
看出來這個函數在QPushButton中是protected的virtual函數,而咱們如今重寫了該函數發現不管若是clicked()信號都沒法鏈接到對象
onButtonClicked,可是沒重寫的時候卻好好的!由此說明在QPushButton中該函數確定發出了clicked()信號.繼承
在上面的例子中咱們在else的部分經過調用QPushButton::mousePressEvent(e),來處理該事件,卻並無發出clicked()信號.事件
經過調用父類的同名函數能夠把QT5的事件傳遞當作鏈狀的,若是當前類沒有處理(accept)該信號就傳遞給父類由父類處理.這樣使得咱們不用本身去調用ignore函數,若是調用ignore,該事件就必定會被傳遞給父組件,可能形成咱們不能碰見的後果.而父類中的該同名函數可能對該事件有所處理,可能會攔截掉該信號(好比:QPushButton),也可能會接着忽略該事件(好比QWidget).get
QT5的事件對象有2個函數ignore()和accept(),前者告訴當前類不想處理該事件,後者告訴當前類想處理該事件.具體來講:若是一個組件的事件處理函數中事件對象調用了accept()函數,這個事件就不會繼續傳遞個父組件了!若是調用了ignore()函數,那麼就會從父組件中尋找其餘的接收者!it
QT5中的事件處理函數都是protected的,也就是說重寫的函數一定存在着其父類中的響應的函數,然而咱們並無寫該響應函數,所以調用父類中的同名函數來使當前類忽略該信號是可行的!也就是說若是咱們想要當前組件忽略掉當前事件最好調用其父類中的同名函數而不是調用ignore.
若是咱們在當前類的事件處理函數中直接調用事件的ignore函數,QT就會讓該信號尋找其餘的接收者.這樣不就存在潛在危險了麼!
爲了不本身去調用ingore()和accept(),QT5作了特殊的設計:事件對象通常默認都是accept的的,可是在QWidget中事件對象倒是ignore的,因爲QWidget是全部組件的基類,所以若是咱們的當前類線接受事件就不須要調用其基類的默認實現了!若是咱們的當前類想忽略該事件那就直接調用基類的同名函數就行了.
讓咱們接着來看例子:
#include <QMainWindow> #include <QPushButton> #include <QVBoxLayout> #include <QDebug> #include <memory>
class CustomButton : public QPushButton { Q_OBJECT
public: CustomButton(QWidget* parent=nullptr):QPushButton(parent){} virtual ~CustomButton()=default;
protected: virtual void mousePressEvent(QMouseEvent* ev)override { qDebug()<<"CustomButton!"; } };
class CustomButtonEx : public CustomButton { Q_OBJECT
public: CustomButtonEx(QWidget* parent=nullptr):CustomButton(parent){} ~CustomButtonEx()=default;
protected: virtual void mousePressEvent(QMouseEvent* ev) override { qDebug()<<"CustomButtonEx!"; } };
class CustomWidget : public QWidget { Q_OBJECT
public: CustomWidget(QWidget* parent=nullptr):QWidget(parent){} ~CustomWidget()=default;
protected: virtual void mousePressEvent(QMouseEvent* ev)override { qDebug()<<"CustomWidget!"; } };
class MainWindow : public QMainWindow { Q_OBJECT
public: MainWindow(QWidget* parent = nullptr); ~MainWindow()=default;
protected: virtual void mousePressEvent(QMouseEvent* ev)override { qDebug()<<"MainWindow!"; }
private: std::shared_ptr<CustomWidget> customWidget; std::shared_ptr<CustomButtonEx> customButtonEx; std::shared_ptr<CustomButton> customButton; std::shared_ptr<QVBoxLayout> vBoxLayout; };
#include "mainwindow.h"
MainWindow::MainWindow(QWidget* parent) :QMainWindow(parent) { this->customWidget = std::shared_ptr<CustomWidget>(new CustomWidget(this)); this->customButton = std::shared_ptr<CustomButton>(new CustomButton(customWidget.get())); customButton->setText(tr("CustomButton")); this->customButtonEx = std::shared_ptr<CustomButtonEx>(new CustomButtonEx(customWidget.get())); customButtonEx->setText(tr("CustomButtonEx"));
this->vBoxLayout = std::shared_ptr<QVBoxLayout>(new QVBoxLayout(customWidget.get())); vBoxLayout->addWidget(customButton.get()); vBoxLayout->addWidget(customButtonEx.get());
this->setCentralWidget(customWidget.get()); }
#include "mainwindow.h" #include <QApplication>
int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show();
return a.exec(); }
注意上面的例子中咱們對於mousePressEvent(QMouseEvent* ev)的實現咱們並無對ev進行任何操做.可是在咱們點擊相應的組件的時候好比CustomWidget, CustomButton,CustomButtonEx的時候這些組件仍然可以精準的接受到信號.由此能夠看出除了QWdiget以外的全部事件處理函數中的事件對象默認都是accept的。
那麼咱們來改一下CustomButtonEx中的mousePressEvent函數吧!
virtual void mousePressEvent(QMouseEvent* ev) override { ev->ignore(); qDebug()<<"CustomButtonEx!"; }
輸出結果是:
CustomButtonEx!
CustomWidget!
是的你沒看錯傳遞給了其父組件!由此能夠看出來ignore只是代表當前組件不想響應該事件,而不是說該事件就被扼殺了!
咱們能夠看出來因爲CustomButtonEx不想響應所以該事件被傳遞給了父組件,由此能夠看出事件的傳遞是在父-子組件之間的,
而不是父-子繼承之間的.
咱們接着修改CustomWidget中的mousePressEvent的實現(上面的修改也不要變啊):
virtual void mousePressEvent(QMouseEvent* ev)override { qDebug()<<"CustomWidget!"; this->QWidget::mousePressEvent(ev); }
輸出結果是:
CustomButtonEx!
CustomWidget!
MainWindow!
咱們在程序中點擊了CustomButtonEx這個按鈕,這個按鈕中的mousePressEvent選擇忽略,因而事件被傳遞給了CustomWidget,而在CustomWidget中咱們調用它的基類中的mousePressEvent接受該事件,又因爲CustomWidget的基類是
QWidget,而QWidget的mousePressEvent函數中的事件對象默認設置爲ignore因此該事件又被傳遞給了MainWindow.