让咱们首先来看一个例子: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.