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

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

相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript