现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

UI线程消息处理过程

2014-07-01 06:10 工业·编程 ⁄ 共 1658字 ⁄ 字号 暂无评论

只有在使用MFC框架时才有UI线程和工作者线程之分。UI线程与工作者线程的区别是操作系统为UI线程创建并维护了一个消息队列

其实线程在创建时(无论是API还是MFC),都是工作者线程。当线程调用发送消息或提取消息或图形用户界面相关的函数时,系统才为其创建一个消息队列和THREADINFO结构,这时的线程才称为UI线程。

VC开发的控制台程序的主线程是工作线程,其他程序的主线程为UI线程。_beginthreadex/CreateThread等函数创建的线程默认为工作线程,AfxBeginThread可以根据参数创建工作者线程和UI线程。

1 从用户输入到系统消息队列

操作系统会监视计算机的键盘和鼠标等输入设备,为每一个输入事件生成一个消息,将消息统一临时放到“系统消息队列”内。其中消息的窗口句柄由系统根据鼠标或光标所在区域计算出的。

2 从系统消息队列到线程消息队列

系统有专门的线程负责从系统消息队列中取出消息,根据消息的目标对象(窗口句柄),将消息投递到创建它的UI线程对应的消息队列中。每个UI线程有且仅有一个消息队列。

3 UI线程处理消息

UI线程启动一个消息循环(Message Loop),每次从本线程所对应的消息队列中取出一条消息,然后根据消息所包容的信息,将其转发给特定的窗体对象,此窗体对象所对应的“窗体过程”函数被调用以处理这些消息。

    MSG msg; // 代表一条消息

    BOOL bRet;

    // 从UI线程消息队列中取出一条消息

    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)

    {

        if (bRet == -1)

        {

            // 错误处理代码,通常是直接退出程序

        }

        else

        {

            TranslateMessage(&msg); // 转换消息格式

            DispatchMessage(&msg); // 分发消息给相应的窗体

        }

    }

GetMessage()等到有消息才返回,peekmessage()则马上返回消息或空值;GetMessage()获得消息后从队列中删除(WM_PAINT除外),peekmessage()则根据参数PM_NOREMOVE或PM_REMOVE来决定要不要删除。

TranslateMessage()函数主要用于将WM_KEYDOWN和WM_KEYUP消息转换WM_CHAR消息。所以如果要截获WM_KEYDOWN和WM_KEYUP消息,需要重载窗体类的PreTranslateMessage()函数进行分析。

DispatchMessage()函数根据取出的消息中所包含的窗体句柄,将这一消息转发给引此句柄所对应的窗体对象。负责响应消息的函数称为窗体过程(Window Procedure)。如果需要自定义处理,则重载窗体类的DefWindowProc()函数。窗体过程是一个函数,每个窗体一个,形式如下:

LRESULT CALLBACK MainWndProc(……)

    {

        //……

        switch (uMsg) // 依据消息标识符进行分类处理

        {

            case WM_CREATE:

                // 初始化窗体.

                return 0;

            case WM_PAINT:

                // 绘制窗体

                return 0;

            //

            // 处理其他消息

            //

            default:

                // 转去调用系统默认的消息处理函数

                return DefWindowProc(hwnd, uMsg, wParam, lParam);

        }

        //……

    }

给我留言

留言无头像?