Qt事件系统

第三章Qt事件系统

文章目录

1.事件系统

在Qt中,事件是派生抽象QEvent类的对象,它表示应用程序内发生的事情,或应用程序需要知道的外部活动的结果。事件可以由QObject子类的任何实例接收和处理。

Qt程序需要在main函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始Qt的事件循环。执行后,程序将进入事件循环来监听应用程序的事件,当事件发生时,Qt将创建一个事件对象。

事件是如何传递的

通过
QCoreApplication::sendEvent()
发送事件 用户触发事件 操作系统接收 将事件分发给对应的应用程序 应用程序事件过滤器处理
nativeEventFilter() 通过
QCoreApplication::postEvent()
发送事件 事件队列 事件分发给对应控件
QApplication::notify() 控件事件过滤处理
QObject::eventFilter() 将事件进行分发
QObject::event() 控件处理
例如mousePressEvent() 忽略该事件 控件的父级处理

事件类型

c 复制代码
#include <QWidget>
#include <QMouseEvent>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
protected:
    //鼠标事件
    void mouseDoubleClickEvent(QMouseEvent *)override;
    void mousePressEvent(QMouseEvent *)override;
    void mouseReleaseEvent(QMouseEvent *)override;
    void mouseMoveEvent(QMouseEvent *)override;

    //按键事件
    void keyPressEvent(QKeyEvent *)override;
    void keyReleaseEvent(QKeyEvent * )override;

    //窗口事件
    void closeEvent(QCloseEvent *) override;
    void hideEvent(QHideEvent *)override;
    void resizeEvent(QResizeEvent *)override;

    //焦点事件
    void focusInEvent(QFocusEvent*)override;
    void focusOutEvent(QFocusEvent*)override ;

    void contextMenuEvent(QContextMenuEvent*)override;

    //程序状态改变事件
    void changeEvent(QEvent*)override;

    //定时器事件
    void timerEvent(QTimerEvent*)override;
};

事件处理

c 复制代码
#include "Widget.h"
#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    this->setMouseTracking(false);//启用鼠标追踪
    this->setFocus();
    new QPushButton("按钮",this);
    this->startTimer(10);//10毫秒
}

Widget::~Widget() {}

void Widget::mouseDoubleClickEvent(QMouseEvent *)
{
    qInfo()<<"鼠标双击";
}

void Widget::mousePressEvent(QMouseEvent *)
{
    qInfo()<<"鼠标按下";
}

void Widget::mouseReleaseEvent(QMouseEvent *)
{
    qInfo()<<"鼠标释放";
}

void Widget::mouseMoveEvent(QMouseEvent *)
{
    static int16_t i=0;
    qInfo()<<"鼠标移动"<<i++;
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    qInfo()<<event->text()<<"按键已按下";
}

void Widget::keyReleaseEvent(QKeyEvent *event)
{
    auto k=event->key();
    qInfo()<<k<<"按键已弹起";
}

void Widget::closeEvent(QCloseEvent *)
{
    qInfo()<<"窗口关闭";
}

void Widget::hideEvent(QHideEvent *)
{
    qInfo()<<"窗口隐藏";
}

void Widget::resizeEvent(QResizeEvent *)
{
    qInfo()<<"窗口大小改变";
}

void Widget::focusInEvent(QFocusEvent *)
{
    qInfo("有焦点");
}

void Widget::focusOutEvent(QFocusEvent *)
{
    qInfo("失去焦点");
}

void Widget::contextMenuEvent(QContextMenuEvent *)
{
    qInfo()<<"收到信号,弹出菜单";
}

void Widget::changeEvent(QEvent *e)
{
    if(e->type()==QEvent::WindowStateChange)
        qInfo()<<"发生改变";
}

void Widget::timerEvent(QTimerEvent *)
{
    static qint32 x=0,y = 0;
    this->move(x++%600+500,y++%800);
}
c 复制代码
 bool event(QEvent *event) override;
 
bool Widget::event(QEvent *event)
{
    if(event->type()==QEvent::Type::MouseButtonPress)
        return true;//屏蔽了MouseButtonPress事件
    return QWidget::event(event);	//把事件交给父类处理
}

发送事件

  • 自定义事件
c 复制代码
#include <QWidget>
#include <QMouseEvent>
#include <QEvent>

class MyCustomEvent:public QEvent
{
public:
    MyCustomEvent():QEvent(QEvent::Type::User)
    {
        info = "自定义事件";
    }
    QString getMessage()
    {
        return info;
    }
private:
    QString info;
};

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
protected:
    //鼠标事件
    void mousePressEvent(QMouseEvent *)override;

    //自定义事件
    void customEvent(QEvent *event)override;

};

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    resize(640,480);
}


void Widget::mousePressEvent(QMouseEvent *)
{
    qInfo()<<"鼠标按下";
    MyCustomEvent* ce = new MyCustomEvent;
    qApp->sendEvent(this,ce);
}

void Widget::customEvent(QEvent *event)
{
    if(event->type()==QEvent::User)
    {
        auto ce = dynamic_cast<MyCustomEvent*>(event);
        if(!ce)
            return;
        qInfo()<<ce->getMessage();
    }
}
  • sendEvent和postEvent的区别

sendEvent 事件发送后,事件不会被删除,是分配在栈上的

postEvent 事件必须在堆上分配,事件发布后会被删除,事件按优先级降序排列。

2.事件传播机制

事件接受和忽略

QEvent()有accept()和ignore()函数

accept,本组处理该事件,不会被传递

ignore,不处理,交给父处理

事件分发

事件过滤

用事件过滤器实现鼠标拖动无边框窗口案例

c 复制代码
#include <QWidget>
#include <QMouseEvent>
#include <QEvent>
#include <QPushButton>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
protected:


    //事件过滤处理器
    bool eventFilter(QObject *watched, QEvent *event)override;
private:
    QPoint pressPos;

#include "Widget.h"
#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    resize(640,480);
    setWindowFlag(Qt::FramelessWindowHint);//设置无边框
    installEventFilter(this);//在对象上安装事件过滤器,如果不装,过滤器重写无效
}

Widget::~Widget() {}




bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if(watched==this)
    {
        if(event->type()==QEvent::MouseButtonPress)
        {
            auto me=dynamic_cast<QMouseEvent*>(event);
            pressPos = me->pos();
            return true;
        }
        else if(event->type()==QEvent::MouseMove)
        {
            auto me=dynamic_cast<QMouseEvent*>(event);
            move(me->globalPosition().toPoint()-pressPos);
            //globalPosition是鼠标在全局的位置,pressPos是鼠标相对于窗口左上角的位置,两者一减,就是窗口左上角在全局的位置
        }
        else
            return false;
    }
    else
        return QObject::eventFilter(watched,event);
}

};

3.事件和信号的区别

事件 信号
与QObject的关系 由具体对象进行处理 由具体对象主动产生
对程序的影响 改写事件处理函数可能导致程序行为发生改变 信号是否存在对应的槽函数不会改变程序的行为
两者的联系 一般而言,信号在具体的事件处理函数中产生

信号和事件是两个不同层面的东西,发出者不同,作用不同。

相关推荐
明月看潮生1 分钟前
青少年编程与数学 02-004 Go语言Web编程 20课题、单元测试
开发语言·青少年编程·单元测试·编程与数学·goweb
大G哥11 分钟前
java提高正则处理效率
java·开发语言
VBA633721 分钟前
VBA技术资料MF243:利用第三方软件复制PDF数据到EXCEL
开发语言
轩辰~23 分钟前
网络协议入门
linux·服务器·开发语言·网络·arm开发·c++·网络协议
小_太_阳32 分钟前
Scala_【1】概述
开发语言·后端·scala·intellij-idea
向宇it33 分钟前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
古希腊掌管学习的神1 小时前
[LeetCode-Python版]相向双指针——611. 有效三角形的个数
开发语言·python·leetcode
赵钰老师1 小时前
【R语言遥感技术】“R+遥感”的水环境综合评价方法
开发语言·数据分析·r语言
就爱学编程1 小时前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
Oneforlove_twoforjob2 小时前
【Java基础面试题025】什么是Java的Integer缓存池?
java·开发语言·缓存