1. 程式人生 > 其它 >【第3版emWin教程】第51章 emWin6.x的Window視窗控制元件

【第3版emWin教程】第51章 emWin6.x的Window視窗控制元件

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

第51章 emWin6.x的Window視窗控制元件

本章節為大家講解emWin6.x支援的視窗控制元件,視窗控制元件和前面講的視窗本質上面是一樣的,只不過這裡是以控制元件的形式存在。

51.1 初學者重要提示

51.2 視窗控制元件基礎知識

51.3 使用GUIBuilder建立視窗控制元件並用模擬器顯示出來

51.4 官方WIDGET_Window.c例項講解

51.5 實驗例程說明(RTOS)

51.6 實驗例程說明(裸機)

51.7 總結

51.1 初學者重要提示

  1. 視窗控制元件相對比較容易,本章節也沒什麼要特別注意的,重點是學習對話方塊的資源列表裡面建立視窗控制元件的方法。
  2. 視窗控制元件的所有API函式在emWin手冊中都有講解,下圖是中文版手冊裡面API函式位置:

下圖是英文版手冊裡面API函式的位置:

51.2 視窗控制元件基礎知識

視窗控制元件與前面講解視窗管理器時介紹的視窗基本是沒有區別的,這裡的視窗控制元件主要是配合對話方塊一起使用,當然,單獨建立也是沒有問題的。視窗控制元件是使用對話方塊必須建立的控制元件之一,另一個是框架視窗控制元件,這兩個控制元件必須二選一作為對話方塊資源列表裡面的第一個控制元件。

視窗控制元件是對話方塊的主體,其餘的按鈕控制元件,編輯框控制元件,滾動條等控制元件都是建立在視窗控制元件上的。

51.2.1 鍵盤反應(輸入聚焦)

視窗控制元件不支援輸入聚焦,這點要特別注意。不支援輸入聚焦的話,外接鍵盤或者類似外接鍵盤的輸入裝置給視窗控制元件發訊息是沒有任何反應的。

(輸入聚焦是一個重要的知識點,使用外接鍵盤或者類似外接鍵盤的輸入裝置要用到)

51.2.2 視窗控制元件API函式

視窗控制元件的API函式比較簡單,也沒有什麼要特別注意的,大家只需看官方手冊中的API函式說明就夠用了,我們教程這裡不再贅述。

本章節教程配套例子是將視窗控制元件配合對話方塊一起使用的,實際專案中也推薦大家這麼做,可以很方便的進行介面管理。在對話方塊上面使用視窗控制元件是通過函式WINDOW_CreateIndirect()來實現的。根據第47章47.7.1講解的<WIDGET>_CreateIndirect()函式,GUI_WIDGET_CREATE_INFO結構體型別定義如下:

typedef struct {
GUI_WIDGET_CREATE_FUNC * pfCreateIndirect;    // 間接建立函式
const char * pName;                           // 控制元件名(不是所有控制元件都需要)
I16 Id;                                       // 控制元件ID
I16 x0, y0, xSize, ySize;                     // 控制元件的座標位置和大小
I16 Flags;                                    // 控制元件用到的標誌,沒有就寫0
I32 Para;                                     // 控制元件用到的引數,沒有就寫0
U32 NumExtraBytes;                            // 函式 <WIDGET>_SetUserData & <WIDGET>_GetUserData用到的
// 額外位元組。
} GUI_WIDGET_CREATE_INFO;

上面結構體成員裡面的標記Flags和引數Para是可選的,函式WINDOW_CreateIndirect()沒有用到引數Para,但用到了標記Flags,與函式WINDOW_CreateEx的形參WinFlags是等效的,具體形參WinFlags支援哪些標記參看emWin官方手冊中的說明即可。

這裡舉一個對話方塊資源列表裡面建立視窗控制元件的例子,幫助大家更好的理解:

/*
*********************************************************************************************************
*                           GUI_WIDGET_CREATE_INFO型別陣列
*********************************************************************************************************
*/
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
  { WINDOW_CreateIndirect, "Window", ID_WINDOW_0, 0, 0, 800, 480, 0, 0x0, 0},
  { TEXT_CreateIndirect,   "Text",   ID_TEXT_0,   20, 35, 86, 31, 0, 0x64, 0 },
  { BUTTON_CreateIndirect, "Button", ID_BUTTON_0, 16, 87, 128, 37, 0, 0x0, 0 },
};

上面的對話方塊資源列表裡面依次建立了視窗控制元件,文字控制元件和按鈕控制元件。視窗控制元件的引數和GUI_WIDGET_CREATE_INFO結構成員的對應關係如下:

pfCreateIndirect = WINDOW_CreateIndirect;
pName = "Window";
Id = ID_WINDOW_0;
x0 = 0;
y0 = 0
xSize = 800;
ySzie = 480;
Flags = 0;
Para = 0x0;
NumExtraBytes = 0;

51.3 使用GUIBuilder建立視窗控制元件並用模擬器顯示出來

GUIBuilder在MDK5.X的安裝目錄中,路徑\Keil\MDK-Middleware\7.12.0\emWin\Tool (版本不同,紅色數值不同)裡面:

51.3.1 第一步:新增一個對話方塊,主體是視窗控制元件

  • 找到GUIBuilder後,開啟這個軟體,並按照如下方式新增一個視窗控制元件。

  • 修改視窗控制元件的大小為800*480。

51.3.2 第二步:在對話方塊上面建立文字控制元件

僅顯示一個視窗控制元件的話,內容太少了,我們在上面新增一個文字控制元件。文字控制元件的的建立方法和上面視窗控制元件的建立方法是一樣的。文字控制元件的字型大小和顯示內容,大家可以任意設定。

  • 新增文字控制元件。

  • 對於新增的文字控制元件,使用者是可以用滑鼠任意拖動的,下面設定文字控制元件的字型,對齊方式,和顯示的文字。首先,滑鼠左擊選中剛剛新增的檔案,然後右擊滑鼠,選擇Set font。

彈出如下介面,並選擇字型GUI_FONT_32B_ASCII,點選OK。

設定字型後文本顯示不全,使用者可以通過滑鼠調整其大小,調整方法如下:先左擊選中相應控制元件,會出現綠色的邊框,在邊框的地方拖動滑鼠即可修改大小

設定好字型以後再設定對齊方式,還是右擊滑鼠,選擇Set text alignment,並選擇居中

最後還是右擊滑鼠,選擇Set text,並更改Content為armfly,修改的地方在左下角:

設定好以後,文字控制元件就算建立完畢。

51.3.3 第三步:在對話方塊上面建立按鈕控制元件

為了使視窗控制元件內容不至於太少,我們在上面再新增一個按鈕控制元件。文字控制元件的的建立方法和上面視窗控制元件的建立方法是一樣的。按鈕上面的字型大小和顯示內容,大家可以任意設定。按鈕上的文字不支援對齊方式設定,預設是居中顯示,這裡是顯示字元armfly,字型GUI_FONT_24B_ASCII,建立後的效果如下所示:

對於建立的按鈕控制元件,使用者可以任意拖動,並通過滑鼠調整其大小,調整方法如下:先左擊選中相應控制元件,會出現綠色的邊框,在邊框的地方拖動滑鼠即可修改大小。

51.3.4 第四步:建立好後點擊File-save

儲存方法如下:

儲存後生成的檔案在GUIBluder5.32軟體所在的資料夾裡面:

51.3.5 第五步:在模擬器上執行GUIBuilder生成的程式碼

在模擬器上面如何演示GUIBuilder生成的程式碼已經在第11章的11.3小節詳細講述了,這裡不再贅述。可以在模擬器上面執行的完整程式碼如下:

/*********************************************************************
*                                                                    *
*                SEGGER Microcontroller GmbH & Co. KG                *
*        Solutions for real time microcontroller applications        *
*                                                                    *
**********************************************************************
*                                                                    *
* C-file generated by:                                               *
*                                                                    *
*        GUI_Builder for emWin version 5.32                          *
*        Compiled Oct  8 2015, 11:59:02                              *
*        (c) 2015 Segger Microcontroller GmbH & Co. KG               *
*                                                                    *
**********************************************************************
*                                                                    *
*        Internet: www.segger.com  Support: [email protected]       *
*                                                                    *
**********************************************************************
*/

// USER START (Optionally insert additional includes)
// USER END

#include "DIALOG.h"

/*********************************************************************
*
*       Defines
*
**********************************************************************
*/
#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)


// USER START (Optionally insert additional defines)
// USER END

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/

// USER START (Optionally insert additional static data)
// USER END

/*********************************************************************
*
*       _aDialogCreate
*/
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
  { FRAMEWIN_CreateIndirect, "Framewin", ID_FRAMEWIN_0, 0, 0, 800, 480, 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 },
  // USER START (Optionally insert additional widgets)
  // USER END
};

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/

// USER START (Optionally insert additional static code)
// USER END

/*********************************************************************
*
*       _cbDialog
*/
static void _cbDialog(WM_MESSAGE * pMsg) {
  WM_HWIN hItem;
  int     NCode;
  int     Id;
  // USER START (Optionally insert additional variables)
  // USER END

  switch (pMsg->MsgId) {
  case WM_INIT_DIALOG:
    //
    // Initialization of 'Framewin'
    //
    hItem = pMsg->hWin;
    FRAMEWIN_SetFont(hItem, GUI_FONT_32B_ASCII);
    FRAMEWIN_SetTextAlign(hItem, GUI_TA_HCENTER | GUI_TA_VCENTER);
    FRAMEWIN_SetText(hItem, "armfly");
    //
    // Initialization of 'Button'
    //
    hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_0);
    BUTTON_SetFont(hItem, GUI_FONT_24B_ASCII);
    BUTTON_SetText(hItem, "armfly");
    // USER START (Optionally insert additional code for further widget initialization)
    // USER END
    break;
  case WM_NOTIFY_PARENT:
    Id    = WM_GetId(pMsg->hWinSrc);
    NCode = pMsg->Data.v;
    switch(Id) {
    case ID_BUTTON_0: // Notifications sent by 'Button'
      switch(NCode) {
      case WM_NOTIFICATION_CLICKED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      case WM_NOTIFICATION_RELEASED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      // USER START (Optionally insert additional code for further notification handling)
      // USER END
      }
      break;
    case ID_SCROLLBAR_0: // Notifications sent by 'Scrollbar'
      switch(NCode) {
      case WM_NOTIFICATION_CLICKED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      case WM_NOTIFICATION_RELEASED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      case WM_NOTIFICATION_VALUE_CHANGED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      // USER START (Optionally insert additional code for further notification handling)
      // USER END
      }
      break;
    case ID_SLIDER_0: // Notifications sent by 'Slider'
      switch(NCode) {
      case WM_NOTIFICATION_CLICKED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      case WM_NOTIFICATION_RELEASED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      case WM_NOTIFICATION_VALUE_CHANGED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      // USER START (Optionally insert additional code for further notification handling)
      // USER END
      }
      break;
    // USER START (Optionally insert additional code for further Ids)
    // USER END
    }
    break;
  // USER START (Optionally insert additional message handling)
  // USER END
  default:
    WM_DefaultProc(pMsg);
    break;
  }
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       CreateFramewin
*/
WM_HWIN CreateFramewin(void);
WM_HWIN CreateFramewin(void) {
  WM_HWIN hWin;

  hWin = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0);
  return hWin;
}

/*********************************************************************
*
*       MainTask
*/
void MainTask(void) 
{
     /* 初始化 */
    GUI_Init();

    /* 視窗自動使用儲存裝置 */
    WM_SetCreateFlags(WM_CF_MEMDEV);

    /* 建立對話方塊,使用GUIBulder5.32生成的對話方塊建立函式 */
    CreateWindow();

    while(1)
    {
        GUI_Delay(10);
    }
}

/*************************** End of file ****************************/

實際顯示效果如下,解析度800*480:

對於這個建立和演示過程,強烈建議初學者實際動手操作。

51.4 官方WIDGET_Window.c例項講解

這個DEMO在模擬器中的位置:

主要功能介紹:

這個例子簡單的演示了視窗控制元件的使用,主要功能是建立一個阻塞式對話方塊,如果使用者點選按鈕將控制元件關閉了,1秒後重新建立這個對話方塊。

程式程式碼如下:

#include "GUI.h"
#include "DIALOG.h"

/*********************************************************************
*
*       Defines
*
**********************************************************************
*/
//
// Recommended memory to run the sample with adequate performance
//
#define RECOMMENDED_MEMORY (1024L * 5)

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
/*********************************************************************
*
*       _aDialog
*
* Function description
*   Dialog resource using a WINDOW widget
*/
static const GUI_WIDGET_CREATE_INFO _aDialog[] = {
  { WINDOW_CreateIndirect, "",       0,               0,  0,   260, 200, 0               },
  { TEXT_CreateIndirect,   "Dialog", 0,               80, 5,   100, 20,  TEXT_CF_HCENTER },
  { BUTTON_CreateIndirect, "Close",  GUI_ID_BUTTON0,  80, 160, 100, 20,  0               }
};

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
/*********************************************************************
*
*       _cbDialog
*
* Function description
*   Callback routine of the dialog
*/
static void _cbDialog(WM_MESSAGE *pMsg) {
  int NCode;
  int Id;

  switch (pMsg->MsgId) {
  case WM_PAINT:
    GUI_SetBkColor(GUI_GREEN);
    GUI_Clear();
    break;
  case WM_NOTIFY_PARENT:
    Id    = WM_GetId(pMsg->hWinSrc);    // Id of widget
    NCode = pMsg->Data.v;               // Notification code
    switch (NCode) {
    case WM_NOTIFICATION_RELEASED:      // React only if released
      switch (Id) {
      case GUI_ID_BUTTON0:
        GUI_EndDialog(pMsg->hWin, 0);
        break;
      }
      break;
    }
    break;
  default:
    WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  GUI_Init();
  //
  // Check if recommended memory for the sample is available
  //
  if (GUI_ALLOC_GetNumFreeBytes() < RECOMMENDED_MEMORY) {
    GUI_ErrorOut("Not enough memory available."); 
    return;
  }
  while(1) {
GUI_DispStringHCenterAt("WIDGET_Window sample\nshows how to use a WINDOW widget", 160, 5);
/* 阻塞式對話方塊 */
    GUI_ExecDialogBox(_aDialog, GUI_COUNTOF(_aDialog), _cbDialog, WM_HBKWIN, 30, 30);
    GUI_Clear();
    GUI_DispStringHCenterAt("Dialog has been closed", 160, 5);
    GUI_Delay(1000);
    GUI_Clear();
  }
}

這個例子重點看對話方塊資源列表中視窗控制元件的建立。設定了視窗控制元件在對話方塊中起始座標是(0, 0),長260個畫素,高200個畫素,Flags標記位設定為0。

實際顯示效果如下:

51.5 實驗例程說明(RTOS)

配套例子:

V7-566_emWin6.x實驗_Window視窗控制元件(RTOS)

實驗目的:

  1. 本實驗主要學習視窗管理器之定時器的使用方法。
  2. emWin功能的實現在MainTask.c檔案裡面

實驗內容:

1、K1按鍵按下,串列埠或者RTT列印任務執行情況(串列埠波特率115200,資料位8,奇偶校驗位無,停止位1)。

2、(1) 凡是用到printf函式的全部通過函式App_Printf實現。

(2) App_Printf函式做了訊號量的互斥操作,解決資源共享問題。

3、預設上電是通過串列埠列印資訊,如果使用RTT列印資訊:

MDK AC5,MDK AC6或IAR通過使能bsp.h檔案中的巨集定義為1即可

#define Enable_RTTViewer 1

4、各個任務實現的功能如下:

App Task Start 任務 :啟動任務,這裡用作BSP驅動包處理。

App Task MspPro任務 :訊息處理,這裡用作LED閃爍。

App Task UserIF 任務 :按鍵訊息處理。

App Task COM 任務 :暫未使用。

App Task GUI 任務 :GUI任務。

μCOS-III任務除錯資訊(按K1按鍵,串列埠列印):

RTT 列印資訊方式:

程式設計:

任務棧大小分配:

μCOS-III任務棧大小在app_cfg.h檔案中配置:

#define APP_CFG_TASK_START_STK_SIZE 512u

#define APP_CFG_TASK_MsgPro_STK_SIZE 2048u

#define APP_CFG_TASK_COM_STK_SIZE 512u

#define APP_CFG_TASK_USER_IF_STK_SIZE 512u

#define APP_CFG_TASK_GUI_STK_SIZE 2048u

任務棧大小的單位是4位元組,那麼每個任務的棧大小如下:

App Task Start 任務 :2048位元組。

App Task MspPro任務 :8192位元組。

App Task UserIF 任務 :2048位元組。

App Task COM 任務 :2048位元組。

App Task GUI 任務 :8192位元組。

系統棧大小分配:

μCOS-III的系統棧大小在os_cfg_app.h檔案中配置:

#define OS_CFG_ISR_STK_SIZE 512u

系統棧大小的單位是4位元組,那麼這裡就是配置系統棧大小為2KB

emWin動態記憶體配置:

GUIConf.c檔案中的配置如下:

#define EX_SRAM   1/*1 used extern sram, 0 used internal sram */

#if EX_SRAM
#define GUI_NUMBYTES  (1024*1024*24)
#else
#define GUI_NUMBYTES  (100*1024)
#endif

通過巨集定義來配置使用內部SRAM還是外部的SDRAM做為emWin的動態記憶體,當配置:

#define EX_SRAM 1 表示使用外部SDRAM作為emWin動態記憶體,大小24MB。

#define EX_SRAM 0 表示使用內部SRAM作為emWin動態記憶體,大小100KB。

預設情況下,本教程配套的所有emWin例子都是用外部SDRAM作為emWin動態記憶體。

emWin介面顯示效果:

800*480解析度介面效果。

51.6 實驗例程說明(裸機)

配套例子:

V7-565_emWin6.x實驗_Window視窗控制元件(裸機)

實驗目的:

  1. 本實驗主要學習視窗管理器之定時器的使用方法。
  2. emWin功能的實現在MainTask.c檔案裡面

emWin介面顯示效果:

800*480解析度介面效果。

emWin動態記憶體配置:

GUIConf.c檔案中的配置如下:

#define EX_SRAM   1/*1 used extern sram, 0 used internal sram */

#if EX_SRAM
#define GUI_NUMBYTES  (1024*1024*24)
#else
#define GUI_NUMBYTES  (100*1024)
#endif

通過巨集定義來配置使用內部SRAM還是外部的SDRAM做為emWin的動態記憶體,當配置:

#define EX_SRAM 1 表示使用外部SDRAM作為emWin動態記憶體,大小24MB。

#define EX_SRAM 0 表示使用內部SRAM作為emWin動態記憶體,大小100KB。

預設情況下,本教程配套的所有emWin例子都是用外部SDRAM作為emWin動態記憶體。

51.7 總結

本章節主要為大家講解了視窗控制元件的使用,相對比較簡單,建議初學者多使用模擬器或者開發板做練習,熟能生巧。

微信公眾號:armfly_com 安富萊論壇:www.armbbs.cn 安富萊淘寶:https://armfly.taobao.com