1. 程式人生 > 其它 >【第3版emWin教程】第43章 emWin6.x視窗管理器例項(含自定義訊息)

【第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