• 【第3版emWin教程】第43章 emWin6.x窗口管理器实例(含自定义消息)


    教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

    第43章       emWin6.x窗口管理器实例(含自定义消息)

    为了帮助大家更好的理解窗口管理器的回调函数和消息机制,本章教程专门做了两个相关的例子,帮助大家更好的理解。

    43.1  初学者重要提示

    43.2 用户自定义消息类型实例

    43.3 桌面窗口回调函数实例

    43.4 总结

    43.1 初学者重要提示

    •   通过实例来学习emWin是最佳的学习捷径。
    •   本章节举的两个例子都用到了对话框,对于初学者来说,仅需知道这是对话框即可,重点是看对话框回调函数的实现,后面章节会专门讲解对话框。
    •   窗口管理器这块的API函数应该是emWin手册所有章节中函数最多的,以后需要用到什么功能了,查询就行,或者看官方的实例,哪个函数不理解了也可以查手册。下图是中文版手册里面API函数位 

     

     

    下图是英文版手册里面API函数的位置:

     

     

    43.2 用户自定义消息类型实例

    第42章为大家讲解的都是emWin支持的消息类型,这里我们通过一个实例来实现自定义消息,这个功能在大家以后的实际项目中都有机会用到,比较有实战价值。

    下面我们直接通过如下的代码来讲解实现方法和用到的函数(可以直接将代码复制到模拟器或者开发板上面运行)。

    #include "DIALOG.h"
    
    
    
    /*
    *********************************************************************************************************
    *                                         变量
    *********************************************************************************************************
    */
    static GUI_COLOR _acColor[3] = {GUI_BLUE,GUI_RED,GUI_YELLOW};   //--------------(1)
    static unsigned char ucBackColor; 
    
    /*
    *********************************************************************************************************
    *                                         宏定义
    *********************************************************************************************************
    */
    #define ID_FRAMEWIN_0  (GUI_ID_USER + 0x00)
    #define ID_BUTTON_0    (GUI_ID_USER + 0x01)
    #define ID_SCROLLBAR_0 (GUI_ID_USER + 0x02)
    #define ID_SLIDER_0    (GUI_ID_USER + 0x03)
    
    #define WM_UPDATE      (WM_USER + 0x00) /* 自定义消息 */  // --------------(2)
    
    
    /*
    *********************************************************************************************************
    *                           GUI_WIDGET_CREATE_INFO类型数组
    *********************************************************************************************************
    */
    static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
      { FRAMEWIN_CreateIndirect, "Framewin", ID_FRAMEWIN_0, 0, 0, 480, 272, 0, 0x64, 0 },
      { BUTTON_CreateIndirect, "Button", ID_BUTTON_0, 130, 28, 147, 35, 0, 0x0, 0 },
      { SCROLLBAR_CreateIndirect, "Scrollbar", ID_SCROLLBAR_0, 129, 74, 147, 28, 0, 0x0, 0 },
      { SLIDER_CreateIndirect, "Slider", ID_SLIDER_0, 133, 118, 137, 25, 0, 0x0, 0 },
    };
    
    /*
    *********************************************************************************************************
    *    函 数 名: _cbDialog
    *    功能说明: 对话框回调函数        
    *    形    参: pMsg  回调参数 
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void _cbDialog(WM_MESSAGE * pMsg) 
    {
        WM_HWIN hItem;
        int     NCode;
        int     Id;
    
    
        switch (pMsg->MsgId) 
        {
            case WM_INIT_DIALOG:
                
                //
                // 初始化 'Framewin'
                //
                hItem = pMsg->hWin;
                FRAMEWIN_SetFont(hItem, GUI_FONT_32B_ASCII);
                FRAMEWIN_SetTextAlign(hItem, GUI_TA_HCENTER | GUI_TA_VCENTER);
                FRAMEWIN_SetText(hItem, "armfly");
            
                //
                // 初始化 'Button'
                //
                hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_0);
                BUTTON_SetFont(hItem, GUI_FONT_24B_ASCII);
                BUTTON_SetText(hItem, "armfly");
    
                /* 默认颜色取*/
                ucBackColor = 0;
                break;
    
            case WM_PAINT:      
                GUI_SetBkColor(_acColor[ucBackColor]);
               GUI_Clear();
                break;
    
            case WM_UPDATE:      //--------------(3)
                ucBackColor++;
                if (ucBackColor == 3)
                {
                    ucBackColor = 0;
                }
                WM_InvalidateWindow(pMsg->hWin);
                break;
        
    
            case WM_KEY:  
                switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key) 
                {
                    case GUI_KEY_ESCAPE:
                        GUI_EndDialog(pMsg->hWin, 1);
                        break;
    
                    case GUI_KEY_ENTER:
                        GUI_EndDialog(pMsg->hWin, 0);
                        break;
                }
                break;
    
            case WM_NOTIFY_PARENT:
                Id    = WM_GetId(pMsg->hWinSrc);
                NCode = pMsg->Data.v;
                switch(Id) 
                {
                    case ID_BUTTON_0:
                        switch(NCode) 
                        {
                            case WM_NOTIFICATION_CLICKED:
                                break;
                            
                            case WM_NOTIFICATION_RELEASED:
                                break;
                        }
                        break;
                    
                    case ID_SCROLLBAR_0: 
                        switch(NCode) 
                        {
                            case WM_NOTIFICATION_CLICKED:
                                break;
                            
                            case WM_NOTIFICATION_RELEASED:
                                break;
                            
                            case WM_NOTIFICATION_VALUE_CHANGED:
                                break;
                        }
                        break;
                    
                    case ID_SLIDER_0:
                        switch(NCode) 
                        {
                            case WM_NOTIFICATION_CLICKED:
                                break;
                            
                            case WM_NOTIFICATION_RELEASED:
                                break;
                            
                            case WM_NOTIFICATION_VALUE_CHANGED:
                                break;
                        }
                        break;
                }
                break;
                
            default:
                WM_DefaultProc(pMsg);
                break;
        }
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: CreateFramewin
    *    功能说明: 创建对话框        
    *    形    参: 无
    *    返 回 值: 返回对话框句柄
    *********************************************************************************************************
    */
    WM_HWIN CreateFramewin(void) 
    {
        WM_HWIN hWin;
    
        hWin = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0);
    
        return hWin;
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: MainTask
    *    功能说明: GUI主函数
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void MainTask(void) 
    {
        WM_HWIN hDlg;
    
        /* 初始emWin */
        GUI_Init();
    
        /* 创建对话框 */
        hDlg = CreateFramewin();
    
        while(1)
        {
            /* 给对话框hDlg发送自定义消息WM_UPDATE */
            WM_SendMessageNoPara(WM_GetClientWindow(hDlg), WM_UPDATE);   // --------------(4)
            GUI_Delay(500);
        }
    }

    实现自定义消息的关键是函数WM_SendMessageNoPara的使用,学会了这个函数基本就学会了自定义消息的实现:

    1. 定义一个数组,里面有三种颜色,再定义一个变量,用于三种颜色的切换。
    2. 定义一个用户消息WM_UPDATE,一定要以WM_USER作为起始值,防止跟系统其他的数值冲突。如果还要实现其它自定义消息,在这个数值的基础上面定义即可。
    3. 在回调函数中加入自定义消息WM_UPDATE,在这个消息里面切换对话框的背景色变量,然后调用函数WM_InvalidateWindow将对话框进行无效化,从而会触发窗口管理器去执行WM_PAINT消息,这样就实现了对话框背景色的变化。
    4. 通过函数WM_SendMessageNoPara()每隔500ms给对话框发送WM_UPDATE消息。函数原型如下:

    void WM_SendMessageNoPara(WM_HWIN hWin, int MsgId)

    此函数用于将不带参数的消息发送到指定窗口,使用也比较简单,第一个参数hWin是要接受消息的窗口句柄,第二个参数MsgId是消息类型。其中第一个参数要特别注意,如果是给对话框发消息,且对话框的主体是框架窗口FrameWin或者直接给框架窗口FrameWin发消息,第一个参数必须要使用函数WM_GetClientWindow获得框架窗口的客户区,这一点非常重要,经常有初学者在这个地方犯错误。如果对话框的主体是Windows或者直接给Windows窗口发消息,无需使用函数WM_GetClientWindow,直接填句柄就可以了。

    此时初学者还会有个疑问,能否使用函数WM_SendMessageNoPara可以发送类似WM_PAINT的系统消息?答案是可以的,不过跟发自定义消息稍有区别:

    /* 设置要用于绘制操作的活动窗口 */
    WM_SelectWindow(WM_GetClientWindow(hDlg));
    
    /* 给对话框hDlg发送系统消息WM_PAINT */
    WM_SendMessageNoPara(WM_GetClientWindow(hDlg), WM_PAINT); 
    
    /* 切换回默认的桌面窗口 */
    WM_SelectWindow(WM_HBKWIN);

    另外还有一个带参数的消息发送函数WM_SendMessage,在第38章会有一个例子调用这个函数。最后,本程序的显示效果如下(分辨率480*272),每500ms更新一次对话框的客户区背景色:

     

     

    43.3 桌面窗口回调函数实例

    这个例子为大家讲解如何给桌面窗口配置回调函数。实现源码如下(可以直接将代码复制到模拟器或者开发板上面运行)。

    #include "DIALOG.h"
    
    
    
    /*
    *********************************************************************************************************
    *                                         宏定义
    *********************************************************************************************************
    */
    #define ID_FRAMEWIN_0  (GUI_ID_USER + 0x00)
    #define ID_BUTTON_0    (GUI_ID_USER + 0x01)
    #define ID_SCROLLBAR_0 (GUI_ID_USER + 0x02)
    #define ID_SLIDER_0    (GUI_ID_USER + 0x03)
    
    
    /*
    *********************************************************************************************************
    *                           GUI_WIDGET_CREATE_INFO类型数组
    *********************************************************************************************************
    */
    static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {   //--------------(1)
      { FRAMEWIN_CreateIndirect, "Framewin", ID_FRAMEWIN_0, 0, 0, 480, 272, FRAMEWIN_CF_MOVEABLE, 0x64, 0 },
      { BUTTON_CreateIndirect, "Button", ID_BUTTON_0, 130, 28, 147, 35, 0, 0x0, 0 },
      { SCROLLBAR_CreateIndirect, "Scrollbar", ID_SCROLLBAR_0, 129, 74, 147, 28, 0, 0x0, 0 },
      { SLIDER_CreateIndirect, "Slider", ID_SLIDER_0, 133, 118, 137, 25, 0, 0x0, 0 },
    };
    
    /*
    *********************************************************************************************************
    *    函 数 名: _cbDialog
    *    功能说明: 对话框回调函数        
    *    形    参: pMsg  回调参数 
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void _cbDialog(WM_MESSAGE * pMsg) 
    {
        WM_HWIN hItem;
        int     NCode;
        int     Id;
    
    
        switch (pMsg->MsgId) 
        {
            case WM_INIT_DIALOG:
                
                //
                // 初始化 'Framewin'
                //
                hItem = pMsg->hWin;
                FRAMEWIN_SetFont(hItem, GUI_FONT_32B_ASCII);
                FRAMEWIN_SetTextAlign(hItem, GUI_TA_HCENTER | GUI_TA_VCENTER);
                FRAMEWIN_SetText(hItem, "armfly");
            
                //
                // 初始化 'Button'
                //
                hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_0);
                BUTTON_SetFont(hItem, GUI_FONT_24B_ASCII);
                BUTTON_SetText(hItem, "armfly");
                break;
    
            case WM_PAINT:
                  GUI_SetBkColor(GUI_RED);
                GUI_Clear();
                  break;
    
            case WM_KEY:  
                switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key) 
                {
                    case GUI_KEY_ESCAPE:
                        GUI_EndDialog(pMsg->hWin, 1);
                        break;
    
                    case GUI_KEY_ENTER:
                        GUI_EndDialog(pMsg->hWin, 0);
                        break;
                }
                break;
    
            case WM_NOTIFY_PARENT:
                Id    = WM_GetId(pMsg->hWinSrc);
                NCode = pMsg->Data.v;
                switch(Id) 
                {
                    case ID_BUTTON_0:
                        switch(NCode) 
                        {
                            case WM_NOTIFICATION_CLICKED:
                                break;
                            
                            case WM_NOTIFICATION_RELEASED:
                                break;
                        }
                        break;
                    
                    case ID_SCROLLBAR_0: 
                        switch(NCode) 
                        {
                            case WM_NOTIFICATION_CLICKED:
                                break;
                            
                            case WM_NOTIFICATION_RELEASED:
                                break;
                            
                            case WM_NOTIFICATION_VALUE_CHANGED:
                                break;
                        }
                        break;
                    
                    case ID_SLIDER_0:
                        switch(NCode) 
                        {
                            case WM_NOTIFICATION_CLICKED:
                                break;
                            
                            case WM_NOTIFICATION_RELEASED:
                                break;
                            
                            case WM_NOTIFICATION_VALUE_CHANGED:
                                break;
                        }
                        break;
                }
                break;
                
            default:
                WM_DefaultProc(pMsg);
                break;
        }
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: CreateFramewin
    *    功能说明: 创建对话框        
    *    形    参: 无
    *    返 回 值: 返回对话框句柄
    *********************************************************************************************************
    */
    WM_HWIN CreateFramewin(void) 
    {
        WM_HWIN hWin;
    
        hWin = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0);
    
        return hWin;
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: _cbBkWindow
    *    功能说明: 桌面窗口回调函数        
    *    形    参: 无
    *    返 回 值: 返回对话框句柄
    *********************************************************************************************************
    */
    static void _cbBkWindow(WM_MESSAGE * pMsg) //--------------(2)
    {
        WM_HWIN hWin = pMsg->hWin;
    
        switch (pMsg->MsgId) 
        {
            case WM_PAINT:  
                GUI_SetBkColor(GUI_BLUE);
                GUI_Clear();
                  break;
    
            default:
                WM_DefaultProc(pMsg);
        }
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: MainTask
    *    功能说明: GUI主函数
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void MainTask(void) 
    {
        WM_HWIN hDlg;
    
        /* 
           使能窗口使用内存设备,这样可以有效避免闪烁, 放在GUI_Init前面就包括桌面
           窗口,如果放在后面就不包括桌面窗口。
        */
        WM_SetCreateFlags(WM_CF_MEMDEV);  //--------------(3)
    
        /* 初始emWin */
        GUI_Init();
    
        /* 设置桌面窗口的回调函数 */
        WM_SetCallback(WM_HBKWIN, _cbBkWindow); //--------------(4)
    
        /* 创建对话框 */
        hDlg = CreateFramewin();
    
        while(1)
        {
            GUI_Delay(10);
        }
    }
    1. 对话框资源列表第一个选项FrameWin设置了一个参数FRAMEWIN_CF_MOVEABLE,这样对话框就是可以移动的,方便查看桌面窗口回调函数的刷新。关于对话框的使用会在后面章节为大家详细讲解,这里有个感性的认识即可。
    2. 桌面窗口的回调函数(桌面窗口是emWin最底层的窗口,是初始化后自动创建的),这里仅实现了一个WM_PAINT消息。
    3. 使用函数WM_SetCreateFlags(WM_CF_MEMDEV)分两种情况,如果此函数是放在函数GUI_Init前面,那么所有的窗口将自动使用内存设备,使用内存设备的好处是有效避免闪烁感。如果此函数是放在函数GUI_Init后面调用,那么桌面窗口是没有使用内存设备的,这点要特别注意。
    4. 通过函数WM_SetCallback来设置桌面窗口的回调函数,实现的功能比较简单,仅设置重绘消息。这里的功能基本等同于调用函数WM_SetDesktopColor(GUI_BLUE)。实现的效果是一样的,都是可以自动重绘桌面窗口。

    另外,测试中还发现一点,如果用户将函数WM_SetCreateFlags(WM_CF_MEMDEV)放在GUI_Init前面,桌面窗口也是可以自动重绘的,这样就可以不需要使用WM_SetCallback来设置桌面窗口回调函数或者使用函数WM_SetDesktopColor(GUI_BLUE),不过重绘的颜色固定为灰色。

    ----------------------------

    这个程序的显示效果如下(分辨率480*272):

     

     

    用户可以拖动这个窗口,鼠标点击到标题栏就可以拖动了,跟操作电脑端软件是一样的:

     

     

    如果不设置桌面窗口回调函数,且函数WM_SetCreateFlags(WM_CF_MEMDEV)没有放在GUI_Init前面调用,那么拖动窗口的话,显示效果就是这个样子的:

     

     

    显示成这个样子是因为桌面窗口没有执行重绘,导致拖动对话框的时候一直有上次显示的残影。

    43.4 总结

    本章节就跟大家讲这么多,希望通过本章教程让大家对窗口管理器有更好的认识,不过还需要大家在模拟器或者开发板上面多做这方面的练习,将其它的窗口管理器API函数也调用测试下。

    微信公众号:armfly_com 安富莱论坛:www.armbbs.cn 安富莱淘宝:https://armfly.taobao.com
  • 相关阅读:
    什么是单例模式?
    下拉列表(web),用jQuery实现
    PS基础
    C#笔记
    C#基础篇--文件(流)
    C#基础篇03
    今天自学了网页上注册某某时的倒计时设置
    主数据管理的Jill Dyche, Evan Levy六层次模型
    scala akka 修炼之路6(scala函数式柯里化风格应用场景分析)
    OpenWrt mt7620n双SSID实现原理
  • 原文地址:https://www.cnblogs.com/armfly/p/15343998.html
Copyright © 2020-2023  润新知