Qt事件派发流程

QApplication和QWidget默认是不连接的,需要在.pro文件里面加上QT += widgets就可以了

QApplication是一个应用程序抽象类,负责应用程序消息派发管理
QWidget是窗口类,抽象一个区域,部件,窗口
QWidget的show方法是显示窗口以及其子类的部件等
如果要想一个控件在中显示,必须要挂在到widget上去,
通常在创建对象的时候会有直接选定的构造函数,或者有setParent方法,来挂载,只有这样,该控件才会在窗口中展示,和参与消息的派发,并且如果是new出来的对象,还可以通过父类来析构,

Layout布局,只要布局对象选定了父类,那么在布局上的窗口都会自动选定,不必再指定


消息分两类:第一类是硬件产生的例如鼠标点击,键盘按下
第二类是软件产生,例如鼠标进入窗口

QCoreApplication::postEvent和QCoreApplication::SendEvent最终调用了QCoreApplication::notify函数,然后由QCoreApplication::notify去派发消息,如果我们重载了notify,那么就获得了所有消息的处理权.

bool QCoreApplication::notify(QObject * receiver, QEvent * event)
接受这个应用程序的所有的消息

Sends event to receiver: receiver->event(event). Returns the value that is returned from the receiver's event handler. Note that this function is called for all events sent to any object in any thread.
发送消息给接受者,调用receiver->event(event),返回的值是接受者消息处理函数的返回,注意这个函数可以发送所有的消息到任意线程的任意控件(在多线程时,注意加锁)

For certain types of events (e.g. mouse and key events), the event will be propagated to the receiver's parent and so on up to the top-level object if the receiver is not interested in the event (i.e., it returns false).
对于一些消息,比如鼠标和键盘,如果接收者对消息不感兴趣(也就是说接收者的event函数返回false),那么这个消息会传送给它的父对象,一直到有对这个消息感兴趣的接收者或者一直到顶层对象

There are five different ways that events can be processed; reimplementing this virtual function is just one of them. All five approaches are listed below:
有五种方法处理这个消息,重写notify这个虚函数只是其中一种.五种方法从实现普遍性角度来排列如下:

    Reimplementing paintEvent(), mousePressEvent() and so on. This is the commonest, easiest, and least powerful way.
    重写paintEvent(), mousePressEvent()等等,这个是最普遍,最简单的,也是影响最小的方法. 

    Reimplementing this function. This is very powerful, providing complete control; but only one subclass can be active at a time.
    重写notify这个函数,这个影响力很大,提供完全的控制,但是一个子类只能使用一次

    Installing an event filter on QCoreApplication::instance(). Such an event filter is able to process all events for all widgets, so it's just as powerful as reimplementing notify(); furthermore, it's possible to have more than one application-global event filter. Global event filters even see mouse events for disabled widgets. Note that application event filters are only called for objects that live in the main thread.
    安装消息过滤器,如果给QCoreApplication::instance对象安装一个过滤器,那么这个过滤器可以处理所有窗口的所有消息,所以它和重载notify一样强大,而且,它还可以安装许多全局钩子,而重载notify只有一个,全局的过滤器甚至可以探测到disable窗口的鼠标消息.注意Application的消息过滤器只能给那些主线程的QT对象用

    Reimplementing QObject::event() (as QWidget does). If you do this you get Tab key presses, and you get to see the events before any widget-specific event filters.


    Installing an event filter on the object. Such an event filter gets all the events, including Tab and Shift+Tab key press events, as long as they do not change the focus widget.

QT事件传递流程1.png-131.9kB
事件的传播是在组件层次上的,而不是依靠类继承机制

事件处理的几种方法,自下往上的分别是
重写具体事件—–>重写event—–>重写eventFilter—->重写notify

  • 重写具体事件:例void mousePressEvent(QMouseEvent* e)事件

    每个窗口控件是有许多具体事件的,每个事件都可以被重写,
    重写事件中还调用`e->accept()`和`e->ignore()`
    accept()用来告诉Qt这个事件已经被处理完了,所以不会传播给他的父组件
    ignore()用来告诉Qt这个事件没有被处理完,Qt会从其父组件中寻找类外的接受者
    
  • 重写event

    每个窗口控件只有一个`bool event(QEvent* e)`,
    通过`e->type()`这个方法与QEvent的枚举`QEvent::MouseButtonPress`来确定组件接收的是什么事件,然后再进行具体事件的处理
    这个函数是有返回值的,bool类型的
    如果返回true,就说明这个事件已经处理完了,就不会在传播给他的父组件了
    如果返回false,就说明这个事件没有被处理完,会继续向他的父组件传播,
    
    在处理完想要处理的事件之后,要在调用父类的event,以确保这个控件的其他事件可以调用默认的处理函数
    
    我认为true可以类比accept, false可以类比ignore
    
    bool event(QEvent *e)
    {
        if (e->type() == QEvent::MouseButtonPress) {
            qDebug() << "event函数中,重写MouseButtonPress";
            return true;
        } else {
            /* 一定不要忘了这一步 */
            QPushButton::event(e);
        }
    }
  • 重写eventFilter
    Filters events if this object has been installed as an event filter for the watched object.
    过滤事件,如果这个观察目标安装了一个事件过滤器

    事件过滤器`bool QObject::eventFilter(QObject * watched, QEvent * event)`
    第一个参数obj就是触发事件的控件,第二个参数是触发的事件
    如果要使用这个控件过滤器,首先这个控件要安装过滤器
        void QObject::installEventFilter(QObject * filterObj)
        filterObj需要过滤信息的控件,
    
    通常需要过滤出消息的控件会被定义成私有成员,并且这个控件过滤器通常是由父组件安装的
    
    eventFilter的返回值是bool,
    如果返回true,说明该事件已经被过滤处理了,不会再继续传播
    如果返回flase,说明该事件没有被过滤处理,会继续执行控件的event()函数,继续往下传播
    如果在其中调用accept().说明这个事件已经被处理了,所以也不会继续传播
    如果在其中调用了ignore().说明这个事件没有被处理,但会直接去其父组件中传播,而不会在给组件中传播,更不会执行该组件的event()函数
    
    在处理完想要处理的事件之后,要在调用父类eventFilter的,以确保之前父类默认的过滤事件仍然可移植性
    
class MyWidget : public QWidget
{
public:
    MyWidget();
protected:  /* 重载eventFilter */
    bool eventFilter(QObject *obj, QEvent *ev);
private:
    QPushButton* button;
};

MyWidget::MyWidget()
{
    button = new QPushButton(this);
    button->installEventFilter(this);
}
bool MyWidget::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == button) {
        if (event->type() == QEvent::QEvent::MouseButtonPress) {
            qDebug() << "事件过滤器处理的MousePressEvent事件";
            return true;
        } else {
            return false;
        }
    } else {
        // pass the event on to the parent class
        return QWidget::eventFilter(obj, event);
    }
}
事件的传递是直接通过多态直接找到触发事件的组件,如果该组件因为某些原因无法处理该事件,才会向其父组件传播

所以就算给widget组件安装上过滤器,也只会过滤传播到widget的事件,而不会过滤直接传播到widget组件里面子组件的事件

如果给QCoreApplication::instance对象安装一个过滤器,那么这个过滤器可以处理所有窗口的所有消息,所以它和重载notify一样强大

但是如果给QApplication安装上过滤器,就可以过滤所有传给该窗口的事件

如果一个组件安装多个过滤器,那过滤器调用的顺序是怎么安排的
  • 重写notify

    使用方法,继承QApplication类,然后在重写notify
    bool QCoreApplication::notify(QObject * receiver, QEvent * event)
    两个参数,控件及参数

    使用方法大致与过滤器相同,但是执行顺序notify在过滤器之前执行

    返回ture说明这个事件已经被处理了
    返回false
    如果还想程序处理这个事件,就在调用父类的notify,还有其他不想处理的事件,也要调用父类的notify来默认分发事件

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以回答这个问题。Linux qt交叉编译的流程大致如下:首先需要安装交叉编译工具链,然后下载Qt源码并解压,进入源码目录,执行configure命令,指定交叉编译工具链的路径和目标平台的架构等参数,然后执行make命令进行编译,最后将编译好的Qt库和头文件拷贝到目标平台上即可。具体的流程可以根据不同的平台和工具链进行调整。 ### 回答2: Linux qt交叉编译流程主要包括以下几个步骤: 1. 下载和安装交叉编译工具链:首先需要选择适合目标平台的交叉编译工具链,比如arm-none-linux-gnueabi,然后下载并安装这个工具链。 2. 配置环境变量:在安装完工具链后,需要配置PATH环境变量,将交叉编译工具链的路径加入到PATH中,以便可以直接使用工具链中的编译器和链接器等工具。 3. 下载和安装Qt库:接下来需要下载和安装Qt库,可以从官方网站下载适合目标平台的Qt库,然后解压缩安装。 4. 配置Qt编译选项:在安装完Qt库后,需要进入Qt库根目录,执行`configure`命令进行配置。在配置过程中,需要指定交叉编译的工具链,并选择需要编译的模块和插件等。 5. 编译Qt库:配置完编译选项后,可以执行`make`命令进行Qt库的编译。这个过程可能会比较耗时,取决于所选择的模块和插件数量以及目标平台的处理能力。 6. 安装Qt库:在编译完成后,可以执行`make install`命令将Qt库安装到指定目录。安装完成后,可以在这个目录下找到生成的Qt库文件。 7. 编译应用程序:最后一步是使用交叉编译工具链编译Qt应用程序。在编译应用程序时,需要将编译器和链接器等工具指向交叉编译工具链中对应的工具,以确保生成的应用程序能在目标平台上运行。 以上就是Linux Qt交叉编译流程的主要步骤。通过这个流程,可以在一台开发机上编译生成适用于其他平台的Qt应用程序。 ### 回答3: Linux qt交叉编译流程如下: 1. 确保系统已安装交叉编译工具链:使用工具链,可以将源码编译成在目标硬件平台上运行的可执行文件。工具链通常包括交叉编译器、链接器和调试器。 2. 下载源码:从Qt官方网站下载需要交叉编译的Qt版本的源码包。 3. 解压源码包:将下载的源码包解压到指定的目录。 4. 配置交叉编译环境:在解压后的源码目录下,打开终端,输入命令"./configure",然后选择适合的交叉编译选项。 5. 修改配置文件:如果需要,可以通过编辑Qt的配置文件修改编译选项,如修改安装路径、禁用某些模块等。 6. 开始编译:在终端中输入"make"命令,开始进行编译。编译过程可能需要一段时间,具体时间取决于计算机性能和编译选项。 7. 安装编译后的文件:编译完成后,在终端中输入"make install"命令,将编译后的文件安装到指定的路径。 8. 测试:在目标硬件平台上运行编译后的程序,测试其功能和性能。这一步可以通过将程序拷贝到目标硬件平台上运行,或者使用模拟器进行测试。 总结起来,Linux qt交叉编译流程包括下载源码、配置环境、进行编译、安装文件和测试功能等步骤。通过这些步骤,可以在Linux系统上将Qt源码交叉编译成适用于目标硬件平台的可执行文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值