|
特别说明:完整STemWin的1-60期教程和配套实例下载地址:链接 第48章 MENU-菜单控件
本期教程讲解STemWin支持的菜单控件。
48. 1 菜单控件介绍
48. 2 官方WIDGET_Menu实例
48. 3使用官方GUIBulder建立MENU控件
48. 4 总结
48.1 列表框控件介绍
MENU控件可用于创建若干种菜单。每个菜单项代表一个应用程序命令或子菜单。MENU可水平显示和/或垂直显示。菜单项可使用分隔符进行分组。水平菜单和垂直菜单均支持分隔符。选择一个菜单项会发送WM_MENU消息给菜单的所有者,或打开一个子菜单。如果已启用鼠标支持,则MENU小工具会对菜单项上方的鼠标移动作出反应。
下表显示水平MENU控件带垂直菜单的外观:
上表显示菜单控件使用其默认效果WIDGET_Effect_3D1L和使用WIDGET_Effect_Simple时的相应外观。菜单控件还可以与所有其他效果配合使用。
48.1.1 菜单消息
为了通知其所有者有关选择一个项或打开一个子菜单的信息,菜单控件将发送WM_MENU类型的消息给其所有者。
WM_MENU:发送此消息的目的是通知菜单的所有者有关选择一个项或打开一个子菜单的信息。已禁用的菜单项将不发送此消息。
WM_MENU中的MENU_MSG_DATA数据结构介绍如下:
数据类型 |
元素 |
描述 |
U16 |
MsgType |
MENU_ON_INITMENU 菜单打开之前会立即将此消息发送给菜单的所有者。这使得应用程序有机会在菜单打开之前对其进行修改。
MENU_ON_ITEMACTIVATE 菜单项被高亮显示之后,菜单的所有者窗口将收到此消息。将子菜单高亮显示之后,则不会发送此消息。
MENU_ON_ITEMPRESSED 按下菜单项之后,将发送此消息给小工具的所有者窗口。对于已禁用的菜单项,也将发送此消息
MENU_ON_ITEMSELECT 选择菜单项之后将立即发送此消息给菜单的所有者。ItemId元素包含已按下的菜单项的Id。 |
U16 |
ItemId |
菜单项的Id。 |
下面是一个WM_MENU的简单示例:
- void Callback(WM_MESSAGE * pMsg) {
- MENU_MSG_DATA * pData;
- WM_HWIN hWin = pMsg->hWin;
- switch (pMsg->MsgId) {
- case WM_MENU:
- pData = (MENU_MSG_DATA *)pMsg->Data.p;
- switch (pData->MsgType) {
- case MENU_ON_ITEMACTIVATE:
- _UpdateStatusbar(pData->ItemId);
- break;
- case MENU_ON_INITMENU:
- _OnInitMenu();
- break;
- case MENU_ON_ITEMSELECT:
- switch (pData->ItemId) {
- case ID_MENU_ITEM0:
- ... /* React on selection of menu item 0 */
- break;
- case ID_MENU_ITEM1:
- ... /* React on selection of menu item 1 */
- break;
- case ...
- ...
- }
- break;
- }
- break;
- default:
- MENU_Callback(pMsg);
- }
- }
复制代码
48.1.2 数据结构
MENU_ITEM_DATA:此结构充当一个容器,用于设置或检索有关菜单项的信息,MENU_ITEM_DATA的元素介绍如下:
数据类型 |
元素 |
描述 |
const char * |
pText |
菜单项文本。 |
U16 |
Id |
菜单项的Id。 |
U16 |
Flags |
MENU_IF_DISABLED 菜单项已被禁用。
MENU_IF_SEPARATOR 菜单项为分隔符。 |
MENU_Handle |
hSubmenu |
如果该菜单项代表一个子菜单,则此元素包含子菜单的句柄。 |
48.1.3 菜单支持键盘反应
如果控件具有输入焦点,则它将对下列各键做出反应:
按键 |
反应 |
GUI_KEY_RIGHT |
- 如果菜单为水平菜单,则选定范围将向右移动一个项。
- 如果菜单为垂直菜单并且当前项为子菜单,则子菜单将会打开,并且输入焦点将移到该子菜单。
- 如果菜单为垂直菜单,但当前项非子菜单,并且顶层菜单为水平菜单,则顶层菜单的下一个项会打开,并且输入焦点将移到该菜单项。 |
GUI_KEY_LEFT |
- 如果菜单为水平菜单,则选定范围将向左移动一个项。
- 如果菜单为垂直菜单而非顶层菜单,则当前菜单会关闭,并且输入焦点将移到上一个菜单。如果上一个菜单为水平菜单,则其上一个子菜单将会打开,并且输入焦点将移到上一个子菜单。 |
GUI_KEY_DOWN |
- 如果菜单为水平菜单并且当前菜单项为子菜单,则此子菜单将会打开。
- 如果菜单为垂直菜单,则选定范围将移到下一个项。 |
GUI_KEY_UP |
- 如果菜单为垂直菜单,则选定范围将移到上一个项。 |
GUI_KEY_ESCAPE |
- 如果菜单不是顶层菜单,则当前菜单将关闭,并且输入焦点将移到上一个菜单。
- 如果菜单为顶层菜单,则当前菜单项将变为未选定。 |
GUI_KEY_ENTER |
- 如果当前菜单项为子菜单,则子菜单将会打开,并且输入焦点将移到该子菜单。
- 如果当前菜单项不是子菜单,则顶层菜单的所有子菜单将会关闭,并且将发送
MENU_ON_ITEMSELECT消息给菜单的所有者。 |
48.2 官方WIDGET_Menu实例
官方的这个实例很好的演示了Header的使用,这个例子在模拟器中的位置:
源码如下(程序中进行了详细的注释):
- ----------------------------------------------------------------------
- File : WIDGET_Menu.c
- Purpose : Shows how to work with menu widget
- Requirements: WindowManager - (x)
- MemoryDevices - (x)
- AntiAliasing - ( )
- VNC-Server - ( )
- PNG-Library - ( )
- TrueTypeFonts - ( )
- ----------------------------------------------------------------------
- */
-
- #include <stdio.h>
- #include "GUI.h"
- #include "DIALOG.h"
- #include "MENU.h"
- #include "MESSAGEBOX.h"
-
- /*********************************************************************
- *
- * Defines
- *
- **********************************************************************
- */
- #define ID_MENU (GUI_ID_USER + 0)
- #define ID_MENU_FILE_NEW (GUI_ID_USER + 1)
- #define ID_MENU_FILE_OPEN (GUI_ID_USER + 2)
- #define ID_MENU_FILE_CLOSE (GUI_ID_USER + 3)
- #define ID_MENU_FILE_EXIT (GUI_ID_USER + 4)
- #define ID_MENU_FILE_RECENT (GUI_ID_USER + 5)
- #define ID_MENU_RECENT_0 (GUI_ID_USER + 6)
- #define ID_MENU_RECENT_1 (GUI_ID_USER + 7)
- #define ID_MENU_RECENT_2 (GUI_ID_USER + 8)
- #define ID_MENU_RECENT_3 (GUI_ID_USER + 9)
- #define ID_MENU_EDIT_UNDO (GUI_ID_USER + 10)
- #define ID_MENU_EDIT_REDO (GUI_ID_USER + 11)
- #define ID_MENU_EDIT_COPY (GUI_ID_USER + 12)
- #define ID_MENU_EDIT_PASTE (GUI_ID_USER + 13)
- #define ID_MENU_EDIT_DELETE (GUI_ID_USER + 14)
- #define ID_MENU_HELP_ABOUT (GUI_ID_USER + 15)
-
- /*********************************************************************
- *
- * Static data
- *
- **********************************************************************
- */
- static WM_HWIN _hMenu;
- static WM_HWIN _hText;
- static WM_HWIN _hFrame;
-
- static char * _paDescription[] = {
- "Creates a new file",
- "Opens an existing file",
- "Closes the file",
- "Quits the application",
- "",
- "Opens file 1",
- "Opens file 2",
- "Opens file 3",
- "Opens file 4",
- "Undoes the last action",
- "Redoes the previously undone action",
- "Copies to clipboard",
- "Inserts contents of clipboard",
- "Deletes the selection",
- "Displays program information"
- };
-
- /*********************************************************************
- *
- * Static code
- *
- **********************************************************************
- */
- /*********************************************************************
- *
- * _AddMenuItem
- */
- static void _AddMenuItem(MENU_Handle hMenu, MENU_Handle hSubmenu, const char* pText, U16 Id, U16 Flags) {
- MENU_ITEM_DATA Item;
-
- Item.pText = pText;
- Item.hSubmenu = hSubmenu;
- Item.Flags = Flags;
- Item.Id = Id;
- MENU_AddItem(hMenu, &Item);
- }
-
- /*********************************************************************
- *
- * _CreateMenu
- * 创建菜单控件
- */
- static WM_HWIN _CreateMenu(WM_HWIN hParent) {
- MENU_Handle hMenu;
- MENU_Handle hMenuFile;
- MENU_Handle hMenuEdit;
- MENU_Handle hMenuHelp;
- MENU_Handle hMenuRecent;
-
- //
- // Create main menu
- //
- hMenu = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_HORIZONTAL, ID_MENU);
- //
- // Create sub menus
- //
- hMenuFile = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_VERTICAL, 0);
- hMenuEdit = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_VERTICAL, 0);
- hMenuHelp = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_VERTICAL, 0);
- hMenuRecent = MENU_CreateEx(0, 0, 0, 0, WM_UNATTACHED, 0, MENU_CF_VERTICAL, 0);
- //
- // Add menu items to menu 'Recent'
- //
- _AddMenuItem(hMenuRecent, 0, "File 1", ID_MENU_RECENT_0, 0);
- _AddMenuItem(hMenuRecent, 0, "File 2", ID_MENU_RECENT_1, 0);
- _AddMenuItem(hMenuRecent, 0, "File 3", ID_MENU_RECENT_2, 0);
- _AddMenuItem(hMenuRecent, 0, "File 4", ID_MENU_RECENT_3, 0);
- //
- // Add menu items to menu 'File'
- //
- _AddMenuItem(hMenuFile, 0, "New", ID_MENU_FILE_NEW, 0);
- _AddMenuItem(hMenuFile, 0, "Open", ID_MENU_FILE_OPEN, 0);
- _AddMenuItem(hMenuFile, 0, "Close", ID_MENU_FILE_CLOSE, MENU_IF_DISABLED);
- _AddMenuItem(hMenuFile, 0, 0, 0, MENU_IF_SEPARATOR);
- _AddMenuItem(hMenuFile, hMenuRecent, "Files...", ID_MENU_FILE_RECENT, 0);
- _AddMenuItem(hMenuFile, 0, 0, 0, MENU_IF_SEPARATOR);
- _AddMenuItem(hMenuFile, 0, "Exit", ID_MENU_FILE_EXIT, 0);
- //
- // Add menu items to menu 'Edit'
- //
- _AddMenuItem(hMenuEdit, 0, "Undo", ID_MENU_EDIT_UNDO, 0);
- _AddMenuItem(hMenuEdit, 0, "Redo", ID_MENU_EDIT_REDO, 0);
- _AddMenuItem(hMenuEdit, 0, 0, 0, MENU_IF_SEPARATOR);
- _AddMenuItem(hMenuEdit, 0, "Copy", ID_MENU_EDIT_COPY, 0);
- _AddMenuItem(hMenuEdit, 0, "Paste", ID_MENU_EDIT_PASTE, 0);
- _AddMenuItem(hMenuEdit, 0, "Delete", ID_MENU_EDIT_DELETE, 0);
- //
- // Add menu items to menu 'Help'
- //
- _AddMenuItem(hMenuHelp, 0, "About", ID_MENU_HELP_ABOUT, 0);
- //
- // Add menu items to main menu
- //
- _AddMenuItem(hMenu, hMenuFile, "File", 0, 0);
- _AddMenuItem(hMenu, hMenuEdit, "Edit", 0, 0);
- _AddMenuItem(hMenu, hMenuHelp, "Help", 0, 0);
- //
- // Attach menu to parent window
- //
- FRAMEWIN_AddMenu(hParent, hMenu);
- return hMenu;
- }
-
- /*********************************************************************
- *
- * _DrawGradientV
- * 实现垂直的颜色梯度
- */
- static void _DrawGradientV(int x0, int y0, int x1, int y1, GUI_COLOR Color0, GUI_COLOR Color1) {
- int r0;
- int g0;
- int b0;
- int r1;
- int g1;
- int b1;
- int y;
- int ySize;
- int r;
- int g;
- I32 b;
- int Diff;
-
- ySize = y1 - y0 + 1;
- r0 = (Color0 >> 0) & 0x000000ff;
- g0 = (Color0 >> 8) & 0x000000ff;
- b0 = (Color0 >> 16) & 0x000000ff;
- r1 = (Color1 >> 0) & 0x000000ff;
- g1 = (Color1 >> 8) & 0x000000ff;
- b1 = (Color1 >> 16) & 0x000000ff;
- for (y = y0; y <= y1; y++) {
- GUI_COLOR Color;
- Diff = y - y0;
- r = r0 + (r1 - r0) * Diff / ySize;
- g = g0 + (g1 - g0) * Diff / ySize;
- b = b0 + (b1 - b0) * Diff / ySize;
- Color = r | (g << 8) | (b << 16);
- GUI_SetColor(Color);
- GUI_DrawHLine(y, x0, x1);
- }
- }
-
- /*********************************************************************
- *
- * _MessageBox
- * 创建并执行模态的消息框
- */
- static void _MessageBox(const char * pText, const char * pCaption) {
- WM_HWIN hBox;
-
- hBox = MESSAGEBOX_Create(pText, pCaption, GUI_MESSAGEBOX_CF_MODAL | GUI_MESSAGEBOX_CF_MOVEABLE);
- WM_SetStayOnTop(hBox, 1);
- WM_BringToTop(hBox);
- GUI_ExecCreatedDialog(hBox);
- WM_SetFocus(_hMenu);
- MENU_SetSel(_hMenu, -1);
- }
-
- /*********************************************************************
- *
- * _cbClient
- * 框架窗口的回调函数
- */
- static void _cbClient(WM_MESSAGE * pMsg) {
- char acBuffer[50];
- int Index;
- int xSize;
- int ySize;
- int xPos;
- int yPos;
- WM_HWIN hWin;
- WM_HWIN hClient;
- MENU_MSG_DATA * pData;
- MENU_ITEM_DATA Data;
-
- hWin = pMsg->hWin;
- hClient = WM_GetClientWindow(hWin);
- xSize = WM_GetWindowSizeX(hClient);
- ySize = WM_GetWindowSizeY(hClient);
- switch (pMsg->MsgId) {
- case WM_SIZE:
- //
- // 如果改变窗口控件大小的话,这里是重新设置文本控件的位置。
- //
- xPos = WM_GetWindowOrgX(hClient);
- yPos = WM_GetWindowOrgY(hClient);
- WM_SetWindowPos(_hText, xPos + 4, yPos + ySize - 10, xSize, 10);
- WM_SetWindowPos(_hMenu, xPos , yPos , xSize, WM_GetWindowSizeY(_hMenu));
- TEXT_SetText(_hText, "Ready");
- break;
- case WM_PAINT:
- //
- // 绘制框架窗口中用户区部分的背景
- //
- _DrawGradientV(0, 0, xSize - 1, ySize - 12 - 1, GUI_WHITE, GUI_LIGHTBLUE);
- GUI_SetColor(GUI_LIGHTGRAY);
- GUI_FillRect(0, ySize - 12, xSize - 1, ySize - 1);
- GUI_SetTextMode(GUI_TM_TRANS);
- GUI_SetColor(GUI_BLACK);
- GUI_SetFont(&GUI_Font24B_ASCII);
- GUI_DispStringHCenterAt(
- "MENU widget sample"
- , xSize / 2, 40);
- GUI_SetFont(&GUI_Font16B_ASCII);
- GUI_DispStringHCenterAt(
- "The sample shows how to use the MENU\n"
- "widget. Use the keyboard or the pointer\n"
- "input device for playing with the widget.\n"
- "On highlighting a menu item the status\n"
- "bar shows a small description. On selecting\n"
- "a menu item a message box will be shown."
- , xSize / 2, 70);
- break;
- case WM_MENU:
- pData = (MENU_MSG_DATA*)pMsg->Data.p;
- switch (pData->MsgType) {
- case MENU_ON_ITEMPRESSED:
-
- //按下菜单项之后,将发送此消息给小工具的所有者窗口。对于
- //已禁用的菜单项,也将发送此消息
- MENU_GetItem(pMsg->hWinSrc, pData->ItemId, &Data);
- if (Data.Flags & MENU_IF_DISABLED) {
- _MessageBox("The pressed item was disabled", "Message");
- }
- break;
- case MENU_ON_ITEMACTIVATE:
- //
- // 菜单项被高亮显示之后,菜单的所有者窗口将收到此消息。将
- // 子菜单高亮显示之后,则不会发送此消息
- //
- Index = pData->ItemId - ID_MENU_FILE_NEW;
- if (Index >= 0) {
- TEXT_SetText(_hText, _paDescription[pData->ItemId - ID_MENU_FILE_NEW]);
- } else {
- TEXT_SetText(_hText, "Ready");
- }
- break;
- case MENU_ON_ITEMSELECT:
- //
- // 选择菜单项之后将立即发送此消息给菜单的所有者。ItemId
- // 元素包含已按下的菜单项的Id。
- sprintf(acBuffer, "ID of the selected\nitem is 0x%X", pData->ItemId);
- _MessageBox(acBuffer, "Message");
- break;
- }
- }
- WM_DefaultProc(pMsg);
- }
-
- /*********************************************************************
- *
- * Public code
- *
- **********************************************************************
- */
- /*********************************************************************
- *
- * MainTask
- */
- void MainTask(void) {
- int xSize;
- int ySize;
- WM_HWIN hClient;
- GUI_Init();
- //
- // 通过下面两个函数使能所有窗口使用内存设备
- //
- #if GUI_SUPPORT_MEMDEV
- WM_SetCreateFlags(WM_CF_MEMDEV);
- WM_EnableMemdev(WM_HBKWIN);
- #endif
- WM_SetDesktopColor(GUI_BLACK);
- MENU_SetDefaultEffect(&WIDGET_Effect_3D1L);
- //
- // 创建框架窗口
- //
- _hFrame = FRAMEWIN_CreateEx(10, 10, 300, 220, WM_HBKWIN, WM_CF_SHOW, FRAMEWIN_CF_MOVEABLE, 0, "Application with menu", _cbClient);
- FRAMEWIN_SetFont(_hFrame, &GUI_Font13_ASCII);
- FRAMEWIN_AddMaxButton(_hFrame, FRAMEWIN_BUTTON_RIGHT, 0); /* 添加框架窗口最大化按钮 */
- FRAMEWIN_AddMinButton(_hFrame, FRAMEWIN_BUTTON_RIGHT, 2); /* 添加框架窗口最小化按钮 */
- //
- // 创建菜单控件
- //
- _hMenu = _CreateMenu(_hFrame);
- //
- // 创建文本控件
- //
- hClient = WM_GetClientWindow(_hFrame);
- xSize = WM_GetWindowSizeX(hClient);
- ySize = WM_GetWindowSizeY(hClient);
- _hText = TEXT_CreateEx(4, ySize - 10, xSize, 10, hClient, WM_CF_SHOW, 0, GUI_ID_TEXT0, "Ready");
- TEXT_SetFont(_hText, &GUI_Font8_ASCII);
- //
- // 创建菜单控件
- //
- WM_SetFocus(_hMenu);
- MENU_SetSel(_hMenu, -1);
- while (1) {
- GUI_Delay(100);
- }
- }
复制代码 例子的实际显示效果如下:
48.3 使用官方GUIBulder建立MENU控件
官方GUIBulder5.22对MENU控件的支持还不够完善,只能建立简单的菜单,菜单里面具体的子项需要用户自己添加。这里用GUIBulder5.22建立一个如下的界面(分辨率480*272):
MENU控件中选项的添加也比较容易,在MENU控件上右击鼠标,可以看到如下界面:
添加后具体每个MENU选项的名字左下角这里进行设置:
设置好以后,将生成的代码复制到模拟器或者开发板上面并稍作修改(生成的代码在本期教程配套的例子中),显示效果如下:
48.4 总结
本期教程主要是跟大家讲解了菜单控件的使用,希望大家可以把本期教程中讲的这两个例子跑跑,然后自己设计一个相关的例子进行试验学习。教程中只是使用了部分的菜单控件API,其它的API大家都可以试试。 |
|