`
gaofen100
  • 浏览: 1228022 次
文章分类
社区版块
存档分类
最新评论

QEventDispatcherWin32 笔记

 
阅读更多

额,还是从一个window程序的基本结构看起吧

Win32程序基本结构

  • 注册窗口类别 RegisterClass

  • 创建窗口 CreateWindow

  • 启动由GetMessage和DispatchMessage构成的事件循环

  • 被注册的回调函数 WndProc 负责相应各类事件

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("Hello");
    HWND   hwnd;
    MSG    msg;
    WNDCLASS wndclass;
    //fill wndclass
    wndclass.lpfnWndProc  = WndProc;
    ...
    RegisterClass(&wndclass);
    hwnd = CreateWindow( .... );      // creation parameters
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    while(GetMessage(&msg, NULL, 0, 0))  {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;
    switch(message) {
        case WM_CREATE:
            return 0;
        case WM_PAINT:
            ...
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

Windows为当前执行的每个Windows程式维护一个消息队列,通过PostMessage、PostThreadMessage可以把消息放入队列,在事件循环中通过GetMessage、PeekMessage可以或者队列中的消息并可通过DispatchMessage将消息派发到相应的窗口回调函数。

  • 消息队列为空时,GetMessage 会阻塞,而PeekMessage不会。现在一般都使用后者

  • SendMessage发送消息直接到窗口回调函数,不进入消息队列

  • WH_GETMESSAGE类型的钩子可以截获GetMessage和PeekMessage的消息

  • 截获SendMessage发送的消息,需要WH_CALLWNDPROC或WH_CALLWNDPROCRET类型的钩子

QEventDispatcherWin32

  • 注册窗口类别,并创建一个隐藏窗口 (QEventDispatcherWin32_Internal_WidgetXXXX)
  • 窗口的回调函数 qt_internal_proc()
  • 安装WH_GETMESSAGE类型的钩子函数qt_GetMessageHook()

这3个比较容易和前面的对应上。但是... 该怎么叙述呢...

事件循环

Qt中的事件循环式通过 QEventLoop::exec() 来启动的。(它通常以QCoreApplication::exec()、QDialog::exec()等身份出现)

在 QEventLoop::exec() 内,是一个while 循环。

int QEventLoop::exec(ProcessEventsFlags flags)
{
    while (!d->exit)
       //...

该循环内,调用的就是QEventDispatcherWin32::processEvents() 函数

bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
{
...
                haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
...
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
...

这样一来,消息被派发到窗口回调函数中。进而可以被

  • 回调函数 qt_internal_proc()
  • 钩子qt_GetMessageHook()

处理

相关函数

  • bool QAbstractEventDispatcher::hasPendingEvents ()

Qt事件队列以及程序的消息队列是否有非空

  • void QAbstractEventDispatcher::wakeUp ()

processEvents() 可能会处于一个阻塞状态,比如调用MsgWaitForMultipleObjectsEx(),此时需要唤醒它。

比如QCoreApplication::postEvent()往队列放入新的事件时,会调用该函数。

  • void QAbstractEventDispatcher::interrupt ()

打断processEvents() ,使其尽快返回,即使队列中还有很多东西。

定时器

主要是定时器的注册与反注册,相关的成员函数

  • int QAbstractEventDispatcher::registerTimer ( int interval, QObject * object )
  • void QAbstractEventDispatcher::registerTimer ( int timerId, int interval, QObject * object )
  • QList<TimerInfo> QAbstractEventDispatcher::registeredTimers ( QObject * object )

  • bool QAbstractEventDispatcher::unregisterTimer ( int timerId )
  • bool QAbstractEventDispatcher::unregisterTimers ( QObject * object )

在Windows层面,

  • 普通定时器由 SetTimer()、KillTimer() 开启和关闭,在窗口回调函数中接收 WM_TIMER 消息,进而转换成Qt事件

  • 多媒体定时器由 timeSetEvent() 和 timeKillEvent() 开启和关闭,在 timeSetEvent参数中指定回调函数qt_fast_timer_proc()用以处理定时器事件,并转换成Qt事件

Socket Notifier

  • void QAbstractEventDispatcher::registerSocketNotifier ( QSocketNotifier * notifier )
  • void QAbstractEventDispatcher::unregisterSocketNotifier ( QSocketNotifier * notifier )

在源码中,你可以看到 WSAAsyncSelect 这个函数的身影,但是它不是Windows的同名的api函数。而是一个本地的函数。

在Qt下,它是通过创建新线程,并在线程内调用 ::select() 函数来实现的。线程内通过SendMessage将消息传递到窗口的回调函数中。

int select(
  __in     int nfds,
  __inout  fd_set *readfds,
  __inout  fd_set *writefds,
  __inout  fd_set *exceptfds,
  __in     const struct timeval *timeout
);
  • The select function determines the status of one or more sockets, waiting if necessary, to perform synchronous I/O.

QSocketNotifier::Read

FD_READ

有可读消息通知

FD_CLOSE

关闭消息通知

FD_ACCEPT

链接请求消息通知

QSocketNotifier::Write

FD_WRITE

有可写消息通知

FD_CONNECT

希望得到connect或多点join操作完成信息通知

QSocketNotifier::Exception

FD_OOB

有外带消息通知

Win Event Notifer

  • bool registerEventNotifier(QWinEventNotifier *notifier);
  • void unregisterEventNotifier(QWinEventNotifier *notifier);
  • void activateEventNotifiers();

这是windows下特有的一个。当某个事件内核对象被触发时,我们可以以异步的方式得到通知。

在是在

QEventDispatcherWin32::processEvents()

函数内,通过调用

MsgWaitForMultipleObjectsEx()

来实现的。

Qt 事件队列

恩,似乎还少点这部分的东西。Qt的事件都是要派发到 QObject::event() 这个函数中去的。

bool QCoreApplication::sendEvent ( QObject * receiver, QEvent * event )

直接将直接派发到 QObject::event()

void QCoreApplication::postEvent ( QObject * receiver, QEvent * event )

确实将事件放置到Qt的事件队列中。可是这些事件是怎么取出来,并派发到 QObject::event() 中去的呢?

负责这个工作的是:

void QCoreApplication::sendPostedEvents()
void QCoreApplication::sendPostedEvents ( QObject * receiver, int event_type )

将事件队列中的事件取出,并使用QCoreApplication::sendEvent ()将其派发出去。

恩,exec() 启动的事件循环调用 event dispatcher 的 processEvents(),该函数负责调用前面的QCoreApplication::sendPostedEvents()函数。

  • 它会启动一个内部的定时器
  • 它会通过PostMessage向程序消息队列放置WM_QT_SENDPOSTEDEVENTS消息

这样工作又转移到了一开始提到窗口回调函数中了。


分享到:
评论

相关推荐

    STM32自学笔记_stm32_STM32自学笔记_

    通过“STM32自学笔记”这样的资料,你可以系统地学习STM32的基础知识和实践技巧,逐步掌握单片机开发的全貌。在实践中,不断实验和调试,加深对外设的理解,是提升技能的关键。同时,参与社区交流,参考他人的项目,...

    STM32自学笔记.pdf

    [STM32自学笔记].蒙博宇

    《STM32自学笔记》随书共享资料

    本资源“《STM32自学笔记》随书共享资料”提供了全面的学习STM32开发所需的知识点,包括基础理论、实践应用和编程技巧。 1. **STM32内核结构**:STM32系列采用的是ARM Cortex-M系列处理器,如M0、M3、M4或M7,它们...

    STM32调试笔记 STM32调试笔记

    STM32 调试笔记 STM32 调试笔记是对 STM32 微控制器的调试过程的详细记录,涵盖了从准备工作到实际调试的各个步骤。本笔记旨在帮助开发者更好地理解 STM32 的工作原理和调试方法。 1. 调试 STM32 前的准备工作: ...

    STM32自学笔记 随书资料

    本资源“STM32自学笔记 随书资料”是一份全面的学习STM32开发的参考资料,旨在帮助初学者快速入门并深入理解STM32的工作原理和编程技巧。 一、STM32架构与特性 STM32系列涵盖了多种型号,主要基于Cortex-M0、M3、M4...

    STM32编程笔记.rar_STM32编程笔记_stm32_stm32 笔记

    STM32编程笔记是针对嵌入式开发领域中广泛应用的STM32微控制器的学习资源,这份笔记详尽地涵盖了从硬件板子设计到软件工程构建的全过程。STM32是意法半导体(STMicroelectronics)推出的基于ARM Cortex-M内核的一...

    STM32自学笔记_stm32_STM32自学笔记_stm32中文资料_

    本自学笔记主要围绕STM32的基础知识、开发环境搭建、程序编写和实践应用展开,旨在帮助初学者快速入门并掌握STM32的使用。 一、STM32基础 STM32系列涵盖多种内核类型,包括Cortex-M0、M3、M4和M7,不同内核提供了...

    stm32 官方应用笔记

    官方应用笔记是STM32开发的重要参考资料,它包含了详细的硬件接口使用、软件开发技巧以及特定功能的应用指南。 本文将围绕STM32官方应用笔记,深入探讨其在入门学习和实际项目开发中的关键知识点。 1. **STM32内核...

    STM32 的所有应用笔记打包下载(共50份)

    STM32 的所有应用笔记打包下载(共50份) 最最详细方便的下载。花了我一天的时间下载和整理。 大家记住:下载完记得打分和评价,除了可以取回自己的被扣的分数外,还额外增加1个积分的。不要把自己的分数浪费了哦! ...

    【经典】STM32自学笔记(完整扫描版)

    本书《STM32自学笔记》由蒙博宇编著,是一本针对STM32微控制器初学者的自学指导书,该书详细介绍了STM32的原理及应用,并通过作者亲身体验和实践总结出的内容,为读者提供了一个清晰的学习路径。本书内容共分为七章...

    51单片机C语言延时函数STM32单片机学习笔记

    51单片机C语言延时函数STM32单片机学习笔记51单片机C语言延时函数STM32单片机学习笔记51单片机C语言延时函数STM32单片机学习笔记51单片机C语言延时函数STM32单片机学习笔记51单片机C语言延时函数STM32单片机学习笔记...

    STM32学习笔记

    STM32学习笔记是针对嵌入式系统开发者的一份详细教程,主要聚焦于基于ARM Cortex-M3内核的32位微控制器STM32。STM32系列由意法半导体(STMicroelectronics)开发,广泛应用于物联网、智能硬件、自动化设备、无人机、...

    stm32F1读书笔记.zip_STM32F1 手册_stm32f1_stm32f1读书笔记_stm32读书笔记

    本文主要根据提供的“stm32F1读书笔记.zip”资料,围绕STM32F1的手册摘要、主要特性以及常见应用进行详述。 首先,STM32F1系列是STM32家族的一员,其核心为32位Cortex-M3处理器,运行速度高达72MHz,提供了强大的...

    九九的STM32笔记

    在“九九的STM32笔记”中,我们可以期待深入学习关于STM32的各种知识,包括基础概念、硬件接口、软件开发流程以及实际应用案例。 一、STM32基础 STM32系列涵盖了多个产品线,如STM32F0、STM32F10x、STM32F4等,它们...

    STM32-learning-notes.rar_stm32 笔记

    STM32学习笔记详解 STM32是一款基于ARM Cortex-M内核的微控制器,由意法半导体(STMicroelectronics)公司生产。这份“STM32-learning-notes.rar”压缩包文件包含了一份作者原创的学习笔记,旨在帮助初学者或有经验...

    STM32笔记.pdf

    STM32笔记.pdf

    stm3自学笔记_stm32_STM32自学笔记_

    stm32自学教程。适合开发者,学生,单片机爱好者

Global site tag (gtag.js) - Google Analytics