第三章Qt事件系统

1.事件系统

在Qt中,事件是派生抽象QEvent类的对象,它表示应用程序内发生的事情,或应用程序需要知道的外部活动的结果。事件可以由QObject子类的任何实例接收和处理。
Qt程序需要在main函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始Qt的事件循环。执行后,程序将进入事件循环来监听应用程序的事件,当事件发生时,Qt将创建一个事件对象。

事件是如何传递的

事件类型

#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;
};

事件处理

#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);
}

 bool event(QEvent *event) override;
 
bool Widget::event(QEvent *event)
{
    if(event->type()==QEvent::Type::MouseButtonPress)
        return true;//屏蔽了MouseButtonPress事件
    return QWidget::event(event);	//把事件交给父类处理
}

发送事件

  • 自定义事件
#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的区别

2.事件传播机制

事件接受和忽略

事件分发

事件过滤

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

#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.事件和信号的区别

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

04-04 18:40