单片机/MCU论坛
直播中

lee_st

12年用户 45163经验值
擅长:可编程逻辑 嵌入式技术 处理器/DSP RF/无线
私信 关注
[资料]

第48章 MENU-菜单控件

转stemwin教程
本期教程讲解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时的相应外观。菜单控件还可以与所有其他效果配合使用。

回帖(12)

lee_st

2016-10-17 10:45:11
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。

举报

lee_st

2016-10-17 10:45:24
下面是一个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:
_UpdateStatu***ar(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);
}
}
举报

lee_st

2016-10-17 10:45:36
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

如果该菜单项代表一个子菜单,则此元素包含子菜单的句柄。

举报

lee_st

2016-10-17 10:45:54
48.1.3 菜单支持键盘反应
    如果控件具有输入焦点,则它将对下列各键做出反应:

按键

反应

GUI_KEY_RIGHT

- 如果菜单为水平菜单,则选定范围将向右移动一个项。
- 如果菜单为垂直菜单并且当前项为子菜单,则子菜单将会打开,并且输入焦点将移到该子菜单。
- 如果菜单为垂直菜单,但当前项非子菜单,并且顶层菜单为水平菜单,则顶层菜单的下一个项会打开,并且输入焦点将移到该菜单项。

GUI_KEY_LEFT

- 如果菜单为水平菜单,则选定范围将向左移动一个项。
- 如果菜单为垂直菜单而非顶层菜单,则当前菜单会关闭,并且输入焦点将移到上一个菜单。如果上一个菜单为水平菜单,则其上一个子菜单将会打开,并且输入焦点将移到上一个子菜单。

GUI_KEY_DOWN

- 如果菜单为水平菜单并且当前菜单项为子菜单,则此子菜单将会打开。
- 如果菜单为垂直菜单,则选定范围将移到下一个项。

GUI_KEY_UP

- 如果菜单为垂直菜单,则选定范围将移到上一个项。

GUI_KEY_ESCAPE

- 如果菜单不是顶层菜单,则当前菜单将关闭,并且输入焦点将移到上一个菜单。
- 如果菜单为顶层菜单,则当前菜单项将变为未选定。

GUI_KEY_ENTER

- 如果当前菜单项为子菜单,则子菜单将会打开,并且输入焦点将移到该子菜单。
- 如果当前菜单项不是子菜单,则顶层菜单的所有子菜单将会关闭,并且将发送
MENU_ON_ITEMSELECT消息给菜单的所有者。

举报

lee_st

2016-10-17 10:46:05
48.2 官方WIDGET_Menu实例
    官方的这个实例很好的演示了Header的使用,这个例子在模拟器中的位置:

举报

lee_st

2016-10-17 10:46:25
源码如下(程序中进行了详细的注释):
复制代码
----------------------------------------------------------------------
File        : WIDGET_Menu.c
Purpose     : Shows how to work with menu widget
Requirements: WindowManager - (x)
              MemoryDevices - (x)
              AntiAliasing  - ( )
              VNC-Server    - ( )
              PNG-Library   - ( )
              TrueTypeFonts - ( )
----------------------------------------------------------------------
*/
#include
#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 MENUn"
"widget. Use the keyboard or the pointern"
"input device for playing with the widget.n"
"On highlighting a menu item the statusn"
"bar shows a small description. On selectingn"
"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 selectednitem 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);
  }
}
举报

lee_st

2016-10-17 10:46:39
例子的实际显示效果如下:

举报

lee_st

2016-10-17 10:47:09
48.3 使用官方GUIBulder建立MENU控件
    官方GUIBulder5.22对MENU控件的支持还不够完善,只能建立简单的菜单,菜单里面具体的子项需要用户自己添加。这里用GUIBulder5.22建立一个如下的界面(分辨率480*272):

举报

lee_st

2016-10-17 10:47:29
MENU控件中选项的添加也比较容易,在MENU控件上右击鼠标,可以看到如下界面:

举报

lee_st

2016-10-17 10:47:48
添加后具体每个MENU选项的名字左下角这里进行设置:

    设置好以后,将生成的代码复制到模拟器或者开发板上面并稍作修改(生成的代码在本期教程配套的例子中),显示效果如下:

举报

lee_st

2016-10-17 10:48:02
48.4 总结
    本期教程主要是跟大家讲解了菜单控件的使用,希望大家可以把本期教程中讲的这两个例子跑跑,然后自己设计一个相关的例子进行试验学习。教程中只是使用了部分的菜单控件API,其它的API大家都可以试试。
举报

lee_st

2016-10-17 10:48:35
分享完成,,,,,,,,,,,
举报

更多回帖

发帖
×
20
完善资料,
赚取积分