文档章节

QT5:事件接受与忽略.

SHIHUAMarryMe
 SHIHUAMarryMe
发布于 2016/04/02 10:06
字数 1518
阅读 189
收藏 2

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

 //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的事件处理函数:

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

看出来这个函数在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 <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.

© 著作权归作者所有

下一篇: QT5: QFileDialog
SHIHUAMarryMe
粉丝 13
博文 162
码字总数 138435
作品 0
武汉
程序员
私信 提问
用Qt实现一个简单的shell (Qt5+V8)

在CSDN论坛看到有网友问用Qt如何实现一个类似shell的东西。 同时呢,前两天V8已经成为Qt5的基础模块了,刚好,可以做个简单的javascript的shell试试看(只支持单行输入)。 于是,便有了本文...

晨曦之光
2012/05/08
1K
0
【Qt笔记】事件的接受与忽略

上一章我们介绍了有关事件的相关内容。我们曾经提到,事件可以依情况接受和忽略。现在,我们就来了解下有关事件的更多的知识。 首先来看一段代码: 这是一段简单的代码,经过我们前面一段时间...

大道无名
2016/07/30
29
0
QT5: 事件过滤.

虽然可以用event拦截事件,但是有的时候我们的应用中用到了很多的组件,或者我们自己实现了一个组件继承了很多其他的组件,我们要想通过event拦截事件,就变得很困难了,必须重写所有的event...

SHIHUAMarryMe
2016/04/04
49
0
为Qt添加libevent的高性能事件循环--qt_eventdispatcher_libevent

qteventdispatcherlibevent 是基于 Libevent 的 Qt 事件调度器 特点 非常快速 支持Qt4和Qt5 不需要Qt的私有头文件 通过Qt4 和 Qt5 的事件调度,事件循环,定时器和socket通知测试...

渡世白玉
2014/03/07
1K
0
为Qt添加libev的高性能事件循环--qt_eventdispatcher_libev

qteventdispatcherlibev 是基于 libev 的 Qt 事件调度器。 特点 非常快速 支持 Qt4 和 Qt5 不需要 Qt 的私有头文件 通过了 Qt4 和 Qt5 的事件调度,事件循环,定时器和 socket 通知测试...

渡世白玉
2014/03/07
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

可见性有序性,Happens-before来搞定

写在前面 上一篇文章并发 Bug 之源有三,请睁大眼睛看清它们 谈到了可见性/原子性/有序性三个问题,这些问题通常违背我们的直觉和思考模式,也就导致了很多并发 Bug 为了解决 CPU,内存,IO ...

tan日拱一兵
20分钟前
2
0
网络七层模型与TCP/UDP

为了使全球范围内不同的计算机厂家能够相互之间能够比较协调的进行通信,这个时候就有必要建立一种全球范围内的通用协议,以规范各个厂家之间的通信接口,这就是网络七层模型的由来。本文首先...

爱宝贝丶
23分钟前
2
0
Jenkins World 贡献者峰会及专家答疑展位

本文首发于:Jenkins 中文社区 原文链接 作者:Marky Jackson 译者:shunw Jenkins World 贡献者峰会及专家答疑展位 本文为 Jenkins World 贡献者峰会活动期间的记录 Jenkins 15周岁啦!Jen...

Jenkins中文社区
41分钟前
8
0
杂谈:面向微服务的体系结构评审中需要问的三个问题

面向微服务的体系结构如今风靡全球。这是因为更快的部署节奏和更低的成本是面向微服务的体系结构的基本承诺。 然而,对于大多数试水的公司来说,开发活动更多的是将现有的单块应用程序转换为...

liululee
56分钟前
7
0
OSChina 周二乱弹 —— 我等饭呢,你是不是来错食堂了?

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @ 自行车丢了:给主编推荐首歌 《クリスマスの夜》- 岡村孝子 手机党少年们想听歌,请使劲儿戳(这里) @烽火燎原 :国庆快来,我需要长假! ...

小小编辑
今天
625
11

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部