您当前的位置: 首页 >  qt

风间琉璃•

暂无认证

  • 1浏览

    0关注

    337博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Qt之事件处理机制

风间琉璃• 发布时间:2022-10-02 21:36:37 ,浏览量:1

目录

一、事件简介

二、事件的处理

1.重写notify处理函数

2.事件过滤器

3.重写event处理函数

4.重写特定事件处理函数

三、事件的发送

一、事件简介

Qt 是一个基于 C++ 的框架,主要用来开发带窗口的应用程序。使用的基于窗口的应用程序都是基于事件,其目的主要是用来实现回调(因为只有这样程序的效率才是最高的)。所以在 Qt 框架内部提供了一些列的事件处理机制,当窗口事件产生之后,事件会经过:事件派发 -> 事件过滤->事件分发->事件处理四个阶段。Qt 窗口中对于产生的一系列事件都有默认的处理动作,如果有特殊需求就需要在合适的阶段重写事件的处理动作。

事件(event)是由系统或者 Qt 本身在不同的场景下发出的。当用户按下 / 移动鼠标、敲下键盘,或者是窗口关闭 / 大小发生变化 / 隐藏或显示都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如鼠标 / 键盘事件等;另一些事件则是由系统自动发出,如计时器事件。

每一个 Qt 应用程序都对应一个唯一的 QApplication 应用程序对象,然后调用这个对象的 exec() 函数,这样 Qt 框架内部的事件检测就开始了(程序将进入事件循环来监听应用程序的事件)。

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow* w = new MainWindow;
    w.show();
    return a.exec();
}

事件在 Qt 中产生后的分发过程:

 1.当事件产生之后,Qt 使用用应用程序对象调用 notify() 函数将事件发送到指定的窗口:

[override virtual] bool QApplication::notify(QObject *receiver, QEvent *e);

2.事件在发送过程中可以通过事件过滤器进行过滤,默认不对任何产生的事件进行过滤。

// 需要先给窗口安装过滤器, 该事件才会触发
[virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)

3.当事件发送到指定窗口之后,窗口的事件分发器会对收到的事件进行分类:

[override virtual protected] bool QWidget::event(QEvent *event);

 4.事件分发器会将分类之后的事件(鼠标事件、键盘事件、绘图事件...)分发给对应的事件处理器函数进行处理,每个事件处理器函数都有默认的处理动作,也可以重写这些事件处理器函数。

// 鼠标按下
[virtual protected] void QWidget::mousePressEvent(QMouseEvent *event);
// 鼠标释放
[virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event);
// 鼠标移动
[virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event);

二、事件的处理

实际应用中事件处理的四层不会对其全部重写,而是根据实际情况选择合适位置重写事件处理的方法。

1.重写notify处理函数

程序中事件循环QApplication类中捕获事件的总接口:notify函数。

重定义方法:继承QApplication类,重写notify函数

//继承QApplication类
class MyApplication:public QApplication{
public:
    MyApplication(int argc,char *argv[]):QApplication(argc,argv)
    {

    }

    //重写notify
    virtual bool notify(QObject *reciever,QEvent *event)
    {
        //捕获关心的事件
        //鼠标点击按钮事件
        if(event->type()==QEvent::MouseButtonPress){
            qDebug()key() == Qt::Key_Enter ||         // 小键盘确认
                keyEv->key() == Qt::Key_Return)     // 大键盘回车
            {
                qDebug() textEdit->installEventFilter(窗口A对象); ui->textEdit->installEventFilter(窗口B对象); ui->textEdit->installEventFilter(窗口C对象);

如果一个对象存在多个事件过滤器,那么最后一个安装的会第一个执行,也就是说窗口C先进行事件过滤,然后窗口B,最后窗口A。 

注意:事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效。

3.重写event处理函数

当事件产生被发送到对应的窗口之后,窗口并不会直接处理这个事件,而是对这些事件进行细分,然后根据事件的类型再次进行分发,对应的事件处理器函数得到这个分发的事件之后就开始处理这个事件。

关于窗口事件的分发,对应一个事件分发器,叫做 event。

[override virtual protected] bool QWidget::event(QEvent *event);

通过事件分发器的函数原型可以得知,关于事件类型的判断是基于参数完成的,这个参数是一个 QEvent 类型的对象,这个类中常用的一些 API 函数:

void QEvent::accept();

作用:让窗口接受传递过来的事件,事件不会向上层窗口(父窗口)传递。

void QEvent::ignore();

作用:让窗口忽略传递过来的事件,事件被传递给父窗口(向上传递)。

bool QEvent::isAccepted() const; void QEvent::setAccepted(bool accepted);

作用:设置传递过来的事件是被接受还是被忽略 setAccepted(true) == accept() setAccepted(false) == ignore()

QEvent::Type QEvent::type() const;

作用得到传递的窗口的事件的类型,返回值是一个枚举类型

事件分发器的分发流程,

bool QWidget::event(QEvent *ev)
{
    switch(ev->type())
    {
    // 鼠标移动
    case QEvent::MouseMove:		
        mouseMoveEvent((QMouseEvent*)event);
        break;
    // 鼠标按下
    case QEvent::MouseButtonPress:	
        mousePressEvent((QMouseEvent*)event);
        break;
    // 鼠标释放
    case QEvent::MouseButtonRelease:	
        mouseReleaseEvent((QMouseEvent*)event);
        break;
    // 鼠标双击
    case QEvent::MouseButtonDblClick:	
        mouseDoubleClickEvent((QMouseEvent*)event);
        break;
    // 键盘按键被按下事件
    case QEvent::KeyPress:
        break;
        ...
        ...
        ...
    default:
        break;
    }
}

 事件分发器在对事件进行判定之后会调用相关的事件处理器函数,这样事件就被最终处理掉了。如果不想让某些触发的事件进入到当前窗口中,可以在事件分发器中进行拦截,拦截之前先来了解一下事件分发器函数的返回值:

①如果传入的事件已被识别并且处理,则需要返回 true,否则返回 false。如果返回值是true,那么 Qt 会认为这个事件已经处理完毕,不会再将这个事件发送给其它对象,而是会继续处理事件队列中的下一事件。

②在event()函数中,调用事件对象的 accept() 和 ignore() 函数是没有作用的,不会影响到事件的传播。

所有如果想过滤某个事件,只需要在判断出这个事件之后直接返回 true 就可以了 。

在窗口中过滤掉鼠标按下的事件:

bool MainWindow::event(QEvent *ev)
{
    if(ev->type() == QEvent::MouseButtonPress ||ev->type() == QEvent::MouseButtonDblClick)
    {
        // 过滤调用鼠标按下的事件
        return true;
    }
    return QWidget::event(ev);
}

这样窗口就不会收到鼠标的单击和双击事件,对于这两个事件以外的其他事件是没有任何影响的,因为在重写的事件分发器函数的最后调用了父类的事件分发器函数 return QWidget::event(ev);这样就能保证其他事件按照默认的分发流程进行分发,并最终被窗口处理掉。

也可以在捕获到某个事件后,对该事件重写

    //重写所有事件的事件处理函数
    virtual bool event(QEvent *evt)
    {
        //鼠标点击按钮事件
        if(evt->type()==QEvent::MouseButtonPress)
        {
            //新的处理动作....
            qDebug()            
关注
打赏
1665385461
查看更多评论
0.0423s