• Qt中的事件处理


    引入

    事件不是信号与槽;
    这两个概念很容易混淆,究其本质信号与槽其实是Qt用来处理事件的一种处理机制,我们不能把它混为一谈。

    其实还有很多不同的事件处理机制的,例如js使用的事件绑定机制,windows采用的消息机制,详情大家可以看我另外几篇博客windows消息机制学习

    事件是什么?

    事件就是一件事情,或者说是一个操作行为,用户移动鼠标、点击鼠标、敲击键盘等等所有的操作都称为事件(系统也可以发出事件,如计时器事件等)

    事件的具体实现方式

    事件的实现是通过订阅发布模式实现的,即在代码运行中预先定义事件,在后面某个操作中触发这个预先定义好的事件,执行事件处理程序(具体的源码大家可以看看windows的官方文档

    在Qt中我们处理事件采用的链式处理,和浏览器的DOM2事件模型一致,共有三个过程:

    1. 事件捕获阶段(自上而下)
      捕获指的是事件从Windows对象一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行,不然
    2. 处于目标阶段
      又称事件处理阶段,这个阶段执行目标元素绑定的监听事件
    3. 事件冒泡阶段(自下而上)
      冒泡指的是事件从目标元素冒泡到Windows对象,依次检查经过的节点是否绑定了事件监听函数

    为啥事件都处理还要再冒泡呢?我们来看一个代码就明白了!

    void MyLabel::mousePressEvent(QMouseEvent * event)
    {
            if(event->button() == Qt::LeftButton) {
                    // do something
            } else {
                    QLabel::mousePressEvent(event);
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    我们在子类中重写了事件函数,在鼠标按下的事件中检测,如果按下的是左键,做我们的处理工作,如果不是左键,则调用父类的函数,这可以说事件向上传递给父类去响应,也就是我们在子类中忽略了这个事件导致事件必须冒泡

    我们可以把Qt的事件传递看成责任链结构,如果在事件捕获阶段子类没有找到事件处理函数,就会继续向其他类传递

    (其实,Qt的事件对象都有一个 accept()函数和 ignore()函数。正如它们的名字,前者用来告诉 Qt,事件处理函数“接收”了这个事件,不要再传递;后者则告诉 Qt,事件处理函数“忽略”了这个事件,需要继续传递,寻找另外的接受者。在事件处理函数中,可以使用 isAccepted()来查询这个事件是不是已经被接收了)

    我们很少使用 accept()和 ignore()函数,而是想上面的示例一样,如果希望忽略事件,只要调用父类的响应函数即可。记得我们曾经说过,Qt 中的事件大部分是 protected 的,因此,重写的函数必定存在着其父类中的响应函数,这个方法是可行的。为什么要这么做呢?因为我们无法确认父类中的这个处理函数没有操作,如果我们在子类中直接忽略事件,Qt 不会再去寻找其他的接受者,那么父类的操作也就不能进行,这可能会有潜在的危险。

    但是有一个情景下,我们也必须使用accept()和ignore()函数,就是在窗口关闭的时候,你想有个询问对话框就必须要主动使用accept()函数去主动接受这个消息(也可以把他想成一种Hook机制,它将发送给QObject的消息给主动拦截下来了,用来处理自己的工作)

    void MainWindow::closeEvent(QCloseEvent * event)
    {
            if(continueToClose()) {
                    event->accept();
            } else {
                    event->ignore();
            }
    }
    
    bool MainWindow::continueToClose()
    {
            if(QMessageBox::question(this,
                                                tr("退出"),
                                                tr("你确定要关闭窗口吗?"),
                                                QMessageBox::Yes | QMessageBox::No,
                                                QMessageBox::No)
                    == QMessageBox::Yes) {
                    return true;
            } else {
                    return false;
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    参考

    我们还可以站在网页编程的角度来定义事件:
    事件是什么?事件模型?

    浏览器还可以直接处理DOM0事件,Qt因为存在Windows类和Qtapplication类的交互的问题,我还不知道能不能直接在Qt窗口的DOM内直接写事件处理函数

  • 相关阅读:
    鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统
    Prompts(二)
    小班安全优质课教案《防止拥挤踩踏事故》
    2022年,你还在犯这些Python错误吗?
    华曙高科冲刺科创板:拟募资6.6亿 实控人许小曙父子均为美国籍
    I2C 死锁原因及解决方法
    Java----HashSet集合、equals(判断两个字符串是否相等)、LinkedHashSet集合、迭代器、可变参数
    OpenCV之cv::undistort
    uniapp移动端h5设计稿还原
    面试官:熟悉Redis?请讲讲Redis缓存穿透、缓存击穿、缓存雪崩有什么区别
  • 原文地址:https://blog.csdn.net/Albert_weiku/article/details/125517879