所有者绘制菜单项的示例

【勇芳软件工作室】汉化HomePreviousNext

本主题中的示例在菜单中使用所有者绘制的菜单项。菜单项选择特定的字体属性,应用程序使用具有相应属性的字体显示每个菜单项。例如,斜体菜单项以斜体字显示。菜单栏上的字符菜单名称打开菜单。

菜单栏和下拉菜单最初由扩展菜单模板资源定义。因为菜单模板不能指定所有者绘制的项目,菜单最初包含四个文本菜单项,其中包含以下字符串:“常规”,“粗体”,“斜体”和“下划线”。应用程序的窗口过程在处理WM_CREATE消息时将其更改为所有者绘制的项目。当接收到WM_CREATE消息时,窗口过程调用应用程序定义的OnCreate函数,该函数对每个菜单项执行以下步骤:

1.分配应用程序定义的MYITEM结构。

2.获取菜单项的文本并将其保存在应用程序定义的MYITEM结构中。

3.创建用于显示菜单项的字体,并将其句柄保存在应用程序定义的MYITEM结构中。

4.将菜单项类型更改为MFT_OWNERDRAW,并将一个指针指向应用程序定义的MYITEM结构作为项目数据。

因为指向每个应用程序定义的MYITEM结构的指针被保存为项目数据,所以将它传递给窗口过程,并结合相应菜单项的WM_MEASUREITEMWM_DRAWITEM消息。该指针包含在MEASUREITEMSTRUCTDRAWITEMSTRUCT结构的的ItemData成员中。

首次显示每个所有者绘制的菜单项时会发送WM_MEASUREITEM消息。应用程序通过将菜单项的字体选择到设备上下文中,然后确定显示该字体中的菜单项文本所需的空间来处理此消息。字体和菜单项文本都由菜单项的MYITEM结构(应用程序定义的结构)指定。应用程序使用GetTextExtentPoint32函数确定文本的大小。

窗口过程通过以适当的字体显示菜单项文本来处理WM_DRAWITEM消息。字体和菜单项文本都由菜单项的MYITEM结构指定。应用程序选择适合菜单项状态的文本和背景颜色。

窗口过程处理WM_DESTROY消息以销毁字体和可用内存。应用程序删除字体,并为每个菜单项释放应用程序定义的MYITEM结构。

以下是应用程序头文件的相关部分。

//字符菜单的菜单项标识符

#define IDM_BOLD 11

#define IDM_REGULAR 11

#define IDM_BOLD 12

#define IDM_ITALIC 13

#define IDM_UNDERLINE 14

//与菜单项相关联的结构

typedef struct tagMYITEM {en

HFONT hfont;

int cchItemText;

char szItemText[1];

} MYITEM;

#定义CCH_MAXITEMTEXT 256

以下是应用程序的窗口过程及其相关功能的相关部分。

LRESULT CALLBACK MainWindowProc(

HWND hwnd,

UINT uMsg,

WPARAM wParam,

if(!OnCreate(hwnd))

)

{

开关(uMsg){

case WM_CREATE:

if(!OnCreate(hwnd))

return -1;

break;

case WM_DESTROY:

OnDestroy(hwnd);

PostQuitMessage(0);

break;

case WM_MEASUREITEM:

OnMeasureItem(hwnd, (LPMEASUREITEMSTRUCT) lParam);

return TRUE;

case WM_DRAWITEM:

OnDrawItem(hwnd, (LPDRAWITEMSTRUCT) lParam);

return TRUE;

.

. //附加消息处理在这里。

.

默认:

return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

return 0;

}

BOOL WINAPI OnCreate(HWND hwnd)

{

HMENU hmenuBar = GetMenu(hwnd);

HMENU hmenuPopup;

MENUITEMINFO mii;

UINT uID;

MYITEM *pMyItem;

//获取弹出菜单的句柄。

mii.fMask = MIIM_SUBMENU; //获取信息

GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

hmenuPopup = mii.hSubMenu;

//修改每个菜单项。假设ID为IDM_REGULAR

//通过IDM_UNDERLINE是连续的数字。

for (uID = IDM_REGULAR; uID <= IDM_UNDERLINE; uID++) {

//分配一个项目结构,留出一个空格

//字符串最多为CCH_MAXITEMTEXT个字符。

pMyItem = (MYITEM *) LocalAlloc(LMEM_FIXED,

sizeof(MYITEM) + CCH_MAXITEMTEXT);

//将项目文本保存在项目结构中。

mii.fMask = MIIM_TYPE;

mii.dwTypeData = pMyItem->szItemText;

mii.cch = CCH_MAXITEMTEXT;

GetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

pMyItem->cchItemText = mii.cch;

//将结构重新分配到最小所需大小。

pMyItem = (MYITEM *) LocalReAlloc(pMyItem,

sizeof(MYITEM) + mii.cch, LMEM_MOVEABLE);

//创建用于绘制项目的字体。

pMyItem->hfont = CreateMenuItemFont(uID);

//将项目更改为所有者绘制的项目,并保存

//项目结构的地址作为项目数据。

mii.fMask = MIIM_TYPE | MIIM_DATA;

mii.fType = MFT_OWNERDRAW;

mii.dwItemData = (DWORD) pMyItem;

SetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

}

return TRUE;

}

HFONT CreateMenuItemFont(UINT uID)

{

LOGFONT lf;

ZeroMemory(&lf, sizeof(lf));

lf.lfHeight = 20;

lstrcpy(lf.lfFaceName, "Times New Roman");

switch(uID){

case IDM_BOLD:

lf.lfWeight = FW_HEAVY;

break;

case IDM_ITALIC:

lf.lfItalic = TRUE;

break;

case IDM_UNDERLINE:

lf.lfUnderline = TRUE;

break;

}

return CreateFontIndirect(&lf);

}

VOID WINAPI OnDestroy(HWND hwnd)

{

HMENU hmenuBar = GetMenu(hwnd);

HMENU hmenuPopup;

MENUITEMINFO mii;

UINT uID;

MYITEM *pMyItem;

//获取菜单的句柄。

mii.fMask = MIIM_SUBMENU; //获取信息

GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

hmenuPopup = mii.hSubMenu;

//与每个菜单项相关联的空闲资源。

for (uID = IDM_REGULAR; uID <= IDM_UNDERLINE; uID++) {

//获取项目数据。

mii.fMask = MIIM_DATA;

GetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

pMyItem = (MYITEM *) mii.dwItemData;

//破坏字体并释放项目结构。

DeleteObject(pMyItem->hfont);

LocalFree(pMyItem);

}

}

VOID WINAPI OnMeasureItem(HWND hwnd,LPMEASUREITEMSTRUCT lpmis)

{

MYITEM *pMyItem = (MYITEM *) lpmis->itemData;

HDC hdc = GetDC(hwnd);

HFONT hfntOld = SelectObject(hdc, pMyItem->hfont);

SIZE size;

GetTextExtentPoint32(hdc,pMyItem- > szItemText,

pMyItem->cchItemText, &size);

lpmis->itemWidth = size.cx;

lpmis->itemHeight = size.cy;

SelectObject(hdc, hfntOld);

ReleaseDC(hwnd, hdc);

}

VOID WINAPI OnDrawItem(HWND hwnd,LPDRAWITEMSTRUCT lpdis)

{

MYITEM *pMyItem = (MYITEM *) lpdis->itemData;

COLORREF clrPrevText, clrPrevBkgnd;

HFONT hfntPrev;

int x, y;

//设置相应的前景色和背景色。

if(lpdis- > itemState & ODS_SELECTED){

clrPrevText = SetTextColor(lpdis->hDC,

GetSysColor(COLOR_HIGHLIGHTTEXT));

clrPrevBkgnd = SetBkColor(lpdis->hDC,

GetSysColor(COLOR_HIGHLIGHT));

}

else {

clrPrevText = SetTextColor(lpdis->hDC,

GetSysColor(COLOR_MENUTEXT));

clrPrevBkgnd = SetBkColor(lpdis->hDC,

GetSysColor(COLOR_MENU));

}

//确定要绘制的位置,并留出空格用于复选标记。

x = lpdis->rcItem.left;

y = lpdis->rcItem.top;

x += LOWORD(GetMenuCheckMarkDimensions());

//选择字体并绘制文字。

hfntPrev = SelectObject(lpdis->hDC, pMyItem->hfont);

ExtTextOut(lpdis- > hDC,x,y,ETO_OPAQUE,

& lpdis- > rcItem,pMyItem- > szItemText,

pMyItem->cchItemText, NULL);

//恢复原始字体和颜色。

SelectObject(lpdis->hDC, hfntPrev);

SetTextColor(lpdis->hDC, clrPrevText);

SetBkColor(lpdis->hDC, clrPrevBkgnd);

}