博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
QT5:事件接受与忽略.
阅读量:7239 次
发布时间:2019-06-29

本文共 5895 字,大约阅读时间需要 19 分钟。

hot3.png

让我们首先来看一个例子:

 //CustomButton.h#include 
#include 
#include 
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 
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的事件处理函数:

 #include 
#include 
#include 
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 
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()这个函数,通过代码页肯定能

看出来这个函数在QPushButton中是protected的virtual函数,而我们现在重写了该函数发现无论如果clicked()信号都无法连接到

onButtonClicked,但是没重写的时候却好好的!由此说明在QPushButton中该函数肯定发出了clicked()信号.

在上面的例子中我们在else的部分通过调用QPushButton::mousePressEvent(e),来处理该事件,却并没有发出clicked()信号.

通过调用父类的同名函数可以把QT5的事件传递看成链状的,如果当前类没有处理(accept)该信号就传递给父类由父类处理.这样使得我们不用自己去调用ignore函数,如果调用ignore,该事件就一定会被传递给父组件,可能造成我们不能遇见的后果.而父类中的该同名函数可能对该事件有所处理,可能会拦截掉该信号(比如:QPushButton),也可能会接着忽略该事件(比如QWidget).

 

QT5的事件对象有2个函数ignore()和accept(),前者告诉当前类不想处理该事件,后者告诉当前类想处理该事件.具体来说:如果一个组件的事件处理函数中事件对象调用了accept()函数,这个事件就不会继续传递个父组件了!如果调用了ignore()函数,那么就会从父组件中寻找其他的接收者!

QT5中的事件处理函数都是protected的,也就是说重写的函数必定存在着其父类中的响应的函数,然而我们并没有写该响应函数,因此调用父类中的同名函数来使当前类忽略该信号是可行的!也就是说如果我们想要当前组件忽略掉当前事件最好调用其父类中的同名函数而不是调用ignore.

如果我们在当前类的事件处理函数中直接调用事件的ignore函数,QT就会让该信号寻找其他的接收者.这样不就存在潜在危险了么!

为了避免自己去调用ingore()和accept(),QT5做了特殊的设计:事件对象一般默认都是accept的的,但是在QWidget中事件对象却是ignore的,由于QWidget是所有组件的基类,因此如果我们的当前类线接受事件就不需要调用其基类的默认实现了!如果我们的当前类想忽略该事件那就直接调用基类的同名函数就好了.

让我们接着来看例子:

 #include 
#include 
#include 
#include 
#include 
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;    std::shared_ptr
 customButtonEx;    std::shared_ptr
 customButton;    std::shared_ptr
 vBoxLayout;};
 #include "mainwindow.h"
MainWindow::MainWindow(QWidget* parent)           :QMainWindow(parent){    this->customWidget = std::shared_ptr
(new CustomWidget(this));    this->customButton = std::shared_ptr
(new CustomButton(customWidget.get()));    customButton->setText(tr("CustomButton"));    this->customButtonEx = std::shared_ptr
(new CustomButtonEx(customWidget.get()));    customButtonEx->setText(tr("CustomButtonEx"));
    this->vBoxLayout = std::shared_ptr
(new QVBoxLayout(customWidget.get()));    vBoxLayout->addWidget(customButton.get());    vBoxLayout->addWidget(customButtonEx.get());
    this->setCentralWidget(customWidget.get());}
 #include "mainwindow.h"#include 
int main(int argc, char *argv[]){    QApplication a(argc, argv);    MainWindow w;    w.show();
    return a.exec();}

151500_5TQY_2516597.png

注意上面的例子中我们对于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.

转载于:https://my.oschina.net/SHIHUAMarryMe/blog/651710

你可能感兴趣的文章
centos6.3(x64) squid透明代理服务器(详细安装步骤)
查看>>
Java&keytool生成RSA密钥
查看>>
我的友情链接
查看>>
adb 调试时出现device not found的几种解决方式
查看>>
JSON.stringify
查看>>
我的友情链接
查看>>
Eureka Server启用 https服务指北
查看>>
动画小结
查看>>
在Felix中使用Metatype Service并在OSGi中获得更新
查看>>
软件包管理 之 文件解压缩
查看>>
css优化 之logo
查看>>
ESX Common Command
查看>>
网站备份 rsync
查看>>
12306铁路售票系统核心开源中间件Geode介绍
查看>>
一维和二维最大字段和的动态规划
查看>>
web技术学习网址
查看>>
【leetcode】102. Binary Tree Level Order Traversal
查看>>
android_常用UI控件_01_TextView
查看>>
搭建只有一个路由器的拓扑
查看>>
Visual Studio Code开发Node.js
查看>>