【转】菜单设计 CMenu

VC MFC菜单栏(CMenu)控件 一个API函数SetMenuInfo,这个函数可以设置菜单重绘时选择的填充画刷类型,该函数有两个参数,第一个是要设置的菜单句柄,第二个是一个MENUINFO结构指针,我们只要了解这结构里有一个成员hbrBack就行了,hbrBack是一个画刷句柄,而菜单背景位图就通过创建位图画刷来实现的。//调用CNewMenu类的MeasureItem成员函数。nPostion指明具体要设置的菜单项,可以是菜单项索引,菜单项ID,具体由nFlags参数指明,为MF_BYPOSITION,则以菜单项索引指明, 阅读详情
 

6.1  菜 单 设计

菜单是可视化编程的重要组成部分,是一种方便地给命令分组并访问这些命令的方法。菜单通常用来显示程序的各项功能,以方便用户选择执行,通过对菜单命令进行编程可以调用程序中相应的功能。

 

6.1.1  菜单类CMenu

在MFC中,CMenu类封装了Windows的菜单功能,它提供了多个方法用于创建、修改、合并菜单。CMenu类的主要方法如下。

(1)Attach方法:该方法用于将句柄关联到菜单对象上。语法如下:

BOOL Attach( HMENU hMenu );

参数说明

     hMenu:标识菜单句柄。

返回值:为非零,表示执行成功,否则执行失败。

(2)Detach方法:该方法从菜单对象上分离菜单句柄。语法如下:

HMENU Detach( );

返回值:分离的菜单句柄。

(3)FromHandle方法:该方法根据菜单句柄返回一个菜单对象指针,如果句柄没有关联的菜单对象,则一个临时的菜单对象指针将要被创建。语法如下:

static CMenu* PASCAL FromHandle( HMENU hMenu );

参数说明

     hMenu:标识菜单句柄。

返回值:菜单对象指针。

(4)CreateMenu方法:该方法用于创建一个菜单窗口,并将其关联到菜单对象上。语法如下:

     BOOL CreateMenu( );

返回值:执行成功,返回值为非零,否则为零。

(5)CreatePopupMenu方法:该方法用于创建一个弹出式菜单窗口,并将其关联到菜单对象上。语法如下:

BOOL CreatePopupMenu( );

返回值:执行成功,返回值为非零,否则为零。对于弹出式菜单,如果菜单窗口被释放,菜单对象将要被自动释放。

(6)LoadMenu方法:该方法从应用程序的可执行文件中加载一个菜单资源,将其关联到菜单对象上。语法如下:

BOOL LoadMenu( LPCTSTR lpszResourceName );

BOOL LoadMenu( UINT nIDResource );

参数说明

     lpszResourceName:标识资源名称。

     nIDResource:标识资源ID。

返回值:执行成功,返回值为非零,否则为零。

(7)DestroyMenu方法:该方法用于释放菜单窗口,当菜单窗口被释放前,它将从菜单对象上分离出来。语法如下:

BOOL DestroyMenu( );

   说明:当菜单对象的析构函数被调用时,将自动调用DestroyMenu方法释放菜单窗口。

(8)DeleteMenu方法:该方法用于从菜单中删除一个菜单项。语法如下:

BOOL DeleteMenu( UINT nPosition, UINT nFlags );

参数说明

     nPosition:标识某一个菜单项。

     nFlags:表示如何删除菜单项,可选值如下。

            MF_BYCOMMAND:根据nPosition标识的菜单ID删除菜单项。

            MF_BYPOSITION:根据nPosition标识的菜单位置删除菜单项。

(9)TrackPopupMenu方法:该方法用于显示一个弹出式菜单。语法如下:

BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL );

参数说明

     nFlags:表示屏幕位置标记和鼠标按钮标记。可选值如下。

            TPM_CENTERALIGN:在x水平位置居中显示菜单。

            TPM_LEFTALIGN:在x水平位置左方显示菜单。

            TPM_RIGHTALIGN:在x水平位置右方显示菜单。

            TPM_LEFTBUTTON:单击鼠标左键显示弹出式菜单。

            TPM_RIGHTBUTTON :单击鼠标右键显示弹出式菜单。

     x:以屏幕坐标标识弹出式菜单的水平坐标。

     y:以屏幕坐标标识弹出式菜单的垂直坐标。

     pWnd:标识弹出式菜单的所有者。

     lpRect:以屏幕坐标表示用户在菜单中的单击区域,如果为NULL,当用户单击弹出式菜单之外的区域,将释放菜单窗口。

(10)AppendMenu方法:该方法用于在菜单项的末尾添加一个新菜单。语法如下:

BOOL AppendMenu( UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL );

BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );

参数说明

     nFlags:标识菜单项的状态信息。

     nIDNewItem:标识菜单项的ID。

     lpszNewItem:标识菜单项的内容。

     pBmp:标识关联菜单项的位图对象指针。

(11)CheckMenuItem方法:该方法用于在弹出的菜单项中放置或删除标记。语法如下:

UINT CheckMenuItem( UINT nIDCheckItem, UINT nCheck );

参数说明

     nIDCheckItem:指定由nCheck确定的将要检测的菜单项。

     nCheck:指定如何检测菜单项,并如何决定菜单中子菜单的位置。可选值如下。

            MF_BYCOMMAND:指定参数给出已存在菜单项的命令ID号,为默认值。

            MF_BYPOSITION:指定参数给出已存在菜单项的位置,第一项位置为0。

            MF_CHECKED:与MF_UNCHECKED一起用作开关,在菜单项之前放置默认的检测标记。

            MF_UNCHECKED:与MF_CHECKED一起用作开关,删除菜单项之前的检测标记。

(12)CheckMenuRadioItem方法:该方法用于将单选按钮放置在菜单项之前,或从组中所有的其他菜单项中删除单选按钮。语法如下:

BOOL CheckMenuRadioItem( UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags );

参数说明

     nIDFirst:指定单选按钮组中的第一个菜单项的值。

     nIDLast:指定单选按钮组中的最后一个菜单项的值。

     nIDItem:指定单选按钮组中被选中的菜单项的值。

     nFlags:对nIDFirst、nIDLast和nIDItem的解释,可选值如下:

            MF_BYCOMMAND:指定参数给出已存在菜单项的命令ID号,若没有设置MF_ BYCOMMAND和MF_BYPOSITION,该值为默认值。

            MF_BYPOSITION:指定参数给出已存在菜单项的位置,第一项位置为0。

(13)EnableMenuItem方法:该方法用于设置菜单项有效、无效或变灰。语法如下:

UINT EnableMenuItem( UINT nIDEnableItem, UINT nEnable );

参数说明

     nIDEnableItem:指定nEnable决定的将要有效的菜单项,该参数既可以指定弹出式菜单,也可以指定标准菜单项。

     nEnable:指定了将要进行的动作,可选值如下。

            MF_BYCOMMAND:指定参数给出已存在的菜单项的命令ID号,此值为默认值。

            MF_BYPOSITION:指定参数给出已存在菜单项的位置,第一项位置为0。

            MF_DISABLED:使菜单项无效,但不变灰。

            MF_ENABLED:使菜单项有效。

            MF_GRAYED:使菜单项变灰。

(14)GetMenuItemCount方法:该方法用于返回弹出式菜单或顶层菜单的菜单数。语法如下:

UINT GetMenuItemCount( ) const;

返回值:如果菜单项没有子菜单,函数返回值为-1,否则返回子菜单数。

(15)GetMenuItemID方法:该方法根据菜单项的位置返回菜单ID,如果菜单项是一个弹出式菜单,返回值为-1;如果菜单项是一个分隔条,返回值为0。语法如下:

UINT GetMenuItemID( int nPos ) const;

参数说明

     nPos:标识菜单项的位置。

(16)GetMenuState方法:该方法用于返回指定菜单项的状态或弹出菜单的项数。语法如下:

UINT GetMenuState( UINT nID, UINT nFlags ) const;

参数说明

     nID:指定由nFlags决定的菜单项ID。

     nFlags:指定nID的特性,值为MF_BYCOMMAND和MF_BYPOSITION之一。

(17)GetMenuString方法:该方法用于设置菜单项的文本。语法如下:

int GetMenuString( UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags ) const;

int GetMenuString( UINT nIDItem, CString& rString, UINT nFlags ) const;

参数说明

     nIDItem:标识菜单项位置或菜单项命令ID,具体含义依赖于nFlags参数。

     lpString:标识一个字符缓冲区。

     nMaxCount:标识向字符缓冲区中复制的最大字符数。

     rString:标识一个字符串。

     nFlags:表示如何解释nIDItem。如果为MF_BYCOMMAND,nIDItem标识菜单项命令ID;如果为MF_BYPOSITION,nIDItem标识菜单项位置。

返回值:实际复制到缓冲区中的字符数。

(18)GetSubMenu方法:该方法用于获取弹出式菜单中的一个菜单项。语法如下:

CMenu* GetSubMenu( int nPos ) const;

参数说明

     nPos:标识菜单项位置,第一个菜单项对应的位置是0,第二个菜单项对应的位置是1,依次类推。

(19)InsertMenu方法:该方法用于向菜单中指定位置插入菜单项。语法如下:

BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem

= NULL );

BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );

参数说明

     nPosition:标识某一个菜单项。

     nFlags:表示如何解释nPosition,可选值如下:

            MF_BYCOMMAND:根据nPosition标识的菜单ID插入菜单项。

            MF_BYPOSITION:根据nPosition标识的菜单位置插入菜单项。

     nIDNewItem:标识菜单项的ID。

     lpszNewItem:标识菜单项的内容。

     pBmp:标识关联菜单项的位图对象指针。

(20)ModifyMenu方法:该方法用于修改菜单项信息。语法如下:

BOOL ModifyMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem

= NULL );

BOOL ModifyMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );

参数说明

     nPosition:标识某一个菜单项。

     nFlags:表示如何解释nPosition,可选值如下。

            MF_BYCOMMAND:根据nPosition标识的菜单ID修改菜单项。

            MF_BYPOSITION:根据nPosition标识的菜单位置修改菜单项。

     nIDNewItem:标识菜单项的ID。

     lpszNewItem:标识菜单项的内容。

     pBmp:标识关联菜单项的位图对象指针。

(21)RemoveMenu方法:该方法用于移除一个菜单项。语法如下:

BOOL RemoveMenu( UINT nPosition, UINT nFlags );

参数说明

     nPosition:标识某一个菜单项。

     nFlags:表示如何删除菜单项,可选值如下:

            MF_BYCOMMAND:根据nPosition标识的菜单ID删除菜单项。

            MF_BYPOSITION:根据nPosition标识的菜单位置删除菜单项。

(22)DrawItem方法:该方法是一个虚方法,用户可以改写该方法实现菜单的绘制。语法如下:

virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );

参数说明

     lpDrawItemStruct:是一个DRAWITEMSTRUCT结构指针,该结构包含了菜单项的ID、类型、画布、句柄等详细信息。

 

6.1.2  菜单资源设计

下面来介绍如何设计菜单资源,步骤如下。

(1)在工作区窗口中选择资源视图(ResourceView),鼠标右键单击一个节点,在弹出的快捷菜单中选择“Insert”菜单项,将打开“Insert Resource”对话框,如图6.1所示。

 

图6.1 “Insert Resource”对话框

(2)在资源类型列表中选择“Menu”节点,单击“New”按钮,将创建一个菜单,如图6.2所示。

 

图6.2  菜单设计窗口

(3)在菜单设计窗口中按<Enter>键打开“Menu Item Properties”窗口,在“Caption”编辑框中设计菜单标题,如图6.3所示。

 

图6.3 “Menu Item Properties”窗口

(4)关闭“Menu Item Properties”窗口,返回到菜单设计窗口中,如图6.4所示。

 

图6.4  菜单设计窗口

(5)在新建菜单下的虚线框上按<Enter>键打开“Menu Item Properties”窗口可以添加子菜单,在“Menu Item Properties”窗口中设置子菜单ID和菜单的标题,如图6.5所示。

 

图6.5  “Menu Item Properties”窗口

如果用户不设置菜单ID,系统将会自动生成一个ID。

(6)关闭菜单属性窗口,返回到菜单设计窗口中,如图6.6所示。

   说明:如果要插入一个分隔线,可以选择Separator属性,并且菜单资源设计窗口支持鼠标拖曳功能,可以在选中菜单项后将其拖曳至适当位置,从而调整各个菜单的位置。

(7)如果想要设计一个级联菜单,可以在菜单项的属性窗口中选中Pop-up复选框,这样,在菜单项的右侧将显示一个箭头,效果如图6.7所示。

                     

                  图6.6  菜单设计窗口                              图6.7  菜单设计窗口

   说明:如果为菜单项选中Pop-up属性,则该菜单项的ID将不能编辑。

(8)打开级联子菜单的属性窗口,设置菜单ID和菜单标题。重复以上的步骤就可以设置需要的菜单。

   说明:在设计菜单项信息时,可以为菜单项设置加速键来简化用户操作。在菜单标题的后面加“&+字母”即可实现加速键的设置,程序运行时,用户按下〈Alt〉键加上该字母键,便可激活并操作该菜单。如果设置加速键的菜单项是子菜单,还需要为该菜单的上级菜单设置加速键,否则上级菜单没有加速键就不能运行子菜单的加速键。

 

6.1.3  菜单的显示与命令处理

在编辑了菜单资源之后运行程序并不能显示菜单,要显示菜单,还需要将菜单和对话框资源进行关联,打开“Dialog Properties”窗口,在“General”选项卡的“Menu”列表框中选择要进行关联的菜单ID,如图6.8所示。

 

图6.8  “Dialog Properties”窗口

现在运行程序就包含菜单了。但是想要用菜单进行对程序的操作还需要设置菜单的命令处理。打开类向导,选择“Message Maps”选项卡,在“Class name”列表框选择关联菜单的对话框类,在“Object Ids”列表中选择菜单项ID,在“Messages”列表中选择“COMMAND”项,如图6.9所示。

 

图6.9  类向导

单击“Add Function…”按钮,弹出“Add Member Function”对话框,并给出默认时的命令处理函数名,如图6.10所示。

 

图6.10 “Add Member Function”对话框

单击“OK”按钮,就添加了菜单项的命令处理函数。再单击“Edit Code”按钮可以打开添加的OnMenumessage命令处理函数,在这里可以编辑菜单项的功能,代码如下:

void CMenuDlg::OnMenumessage()

{

    MessageBox("菜单消息处理函数");

    return;

}

 

6.1.4  动态创建菜单

在前面已经介绍了如何编辑菜单资源以及通过类向导编写菜单的命令处理函数。本节将通过CMenu类实现动态创建菜单。

(1)创建一个基于对话框的应用程序。

(2)向对话框中添加一个按钮控件。

(3)在主窗口的头文件中声明一个CMenu类对象,代码如下:

CMenu m_Menu;

(4)在资源头文件(Resource.h)中定义命令ID,如图6.11所示。

 

图6.11  Resource.h文件

(5)在主窗口的头文件中添加消息处理函数,如图6.12所示。

 

图6.12  DynamicMenuDlg.h文件

(6)在主窗口的源文件中添加消息映射宏,将命令ID关联到消息处理函数中,如图6.13所示。

(7)在主窗口的源文件中添加消息处理函数的实现代码,代码如下:

 

图6.13  DynamicMenuDlg.cpp文件

void CDynamicMenuDlg::OnMenured()

{

   MessageBox("打开菜单被按下");

}

void CDynamicMenuDlg::OnMenublue()

{

   MessageBox("保存菜单被按下");

}

void CDynamicMenuDlg::OnMenugreen()

{

    MessageBox("另存为菜单被按下");

}

MessageBox函数用来弹出一个消息框,该函数有3个参数,第一个参数表示消息框显示的文本,第二个参数表示消息框的标题,默认为可执行文件名,第3个参数表示消息框显示的按钮风格和图标风格的组合。

(8)处理“创建”按钮的消息响应事件,用代码创建菜单,代码如下:

void CDynamicMenuDlg::OnButton1()

{

   m_Menu.CreateMenu();

   CMenu popmenu;

   popmenu.CreatePopupMenu();

   m_Menu.AppendMenu(MF_POPUP,(UINT)popmenu.m_hMenu,"系统");

   popmenu.AppendMenu(MF_STRING,ID_MENURED,"打开");

   popmenu.AppendMenu(MF_STRING,ID_MENUBLUE,"保存");

   popmenu.AppendMenu(MF_STRING,ID_MENUGREEN,"另存为");

   popmenu.Detach();

   SetMenu(&m_Menu);

}

SetMenu函数用于分配一个菜单到指定窗口。

程序运行结果如图6.14所示。

 

图6.14  动态创建菜单

6.1.5  菜单项的更新机制

在使用类向导为菜单添加命令处理函数时,发现菜单除了COMMAND消息外,还有一个UPDATE_COMMAND_UI消息,该消息是“更新命令用户接口消息”。菜单项的状态维护就依赖于UPDATE_COMMAND_UI消息。下面就来看看如何使用这个消息。

打开一个基于单文档的应用程序,运行程序后发现“编辑”菜单下的菜单项都不可用,如图6.15所示。

如果想要使“编辑”菜单下的菜单项都可用,就要为相应的菜单项处理UPDATE_ COMMAND_UI消息。以“撤销”菜单项为例,打开类向导,选择“Message Maps”选项卡,在“Class name”列表框中选择“CmainFrame”类,在“Object Ids”列表中选择“撤销”菜单项“ID_EDIT_UNDO”,在“Messages”列表中选择“UPDATE_COMMAND_UI”项,单击“Add Function…”按钮,创建该消息的处理函数,如图6.16所示。

 

图6.16  类向导

单击“Edit Code”按钮,定位到新建的消息处理函数,在函数中添加代码使“撤销”菜单项可用,代码如下:

void CMainFrame::OnUpdateEditUndo(CCmdUI* pCmdUI)

{

   pCmdUI->Enable(); //使菜单项可用

}

   说明:参数pCmdUI可以设置菜单项是否可用、是否具有标记和改变菜单项标题。

程序运行结果如图6.17所示。

 

图6.17  菜单项的更新机制

通过上面的运行结果发现“撤销”菜单项已经可用,这是因为MFC菜单项的命令更新机制,当要显示菜单时,系统发出WM_INITMENUPOPUP消息,该消息被程序窗口的基类接管后会创建一个CCmdUI对象,CCmdUI对象会与程序的第一个菜单项相关联,并调用CCmdUI对象的DoUpdate方法发送UPDATE_COMMAND_UI消息,系统会查找是否有捕获这个消息的宏,如果找到就调用相应的函数进行处理。当这个菜单项更新后,CCmdUI对象会继续对下一个菜单项进行关联,直到完成所有菜单项的处理。

6.1.6  自绘弹出式菜单

在Windows操作系统中单击鼠标右键弹出的菜单称为弹出式菜单。弹出式菜单可以方便用户的操作,下面来介绍一下如何创建弹出式菜单。

(1)创建一个基于对话框的程序。

(2)向工程中导入两个位图,将资源ID改为IDB_LEFTBITMAP和IDB_ITEMBITMAP。

(3)以CMenu类为基类派生一个CCustomMenu类,定义一个记录菜单项信息的数据结构CMenuItemInfo,代码如下:

struct CMenuItemInfo

{

   CString m_ItemText;  //菜单项文本

   int     m_ItemIndex; //菜单项索引

   int     m_ItemID;     //菜单标记0分隔条,其他普通菜单

};

(4)在CCustomMenu类的头文件中声明如下变量:

CMenuItemInfo m_ItemLists[10]; //菜单项信息

int                    m_ImageIndex;  //图像索引

CFont                 m_TitleFont;   //标题字体

(5)在CCustomMenu类中添加DrawMenuTitle方法,用于绘制菜单左侧标题,代码如下:

void CCustomMenu::DrawMenuTitle(CDC *pDC, CRect rect, CString title)

{

   CBitmap m_bitmap;

   m_bitmap.LoadBitmap(IDB_LEFTBITMAP);

   BITMAP m_size;

   m_bitmap.GetBitmap(&m_size);

   CDC m_memdc;

   m_memdc.CreateCompatibleDC(pDC);

   CGdiObject* m_oldobject;

   m_oldobject = m_memdc.SelectObject(&m_bitmap);

   pDC->StretchBlt(0,0,28,rect.bottom,&m_memdc,0,0,m_size.bmWidth,m_size.bmHeight,SRCCOPY);

   m_bitmap.DeleteObject();

   CFont* m_oldfont = pDC->SelectObject(&m_TitleFont);

   pDC->TextOut(rect.left+5,rect.Height()+130,title);

   pDC->SelectObject(m_oldfont);

}

通过LoadBitmap方法装载位图IDB_LEFTBITMAP,再使用StretchBlt方法将位图绘制成标题大小。

(6)在CCustomMenu类中添加DrawItemText方法,用于绘制菜单项文本,代码如下:

void CCustomMenu::DrawItemText(CDC *pDC, LPSTR str, CRect rect)

{

   rect.DeflateRect(40,0,0,0);

   pDC->DrawText(str,rect,DT_SINGLELINE|DT_VCENTER|DT_LEFT);

}

(7)在CCustomMenu类中添加DrawSeparater方法,用于绘制分隔条,代码如下:

void CCustomMenu::DrawSeparater(CDC *pDC, CRect rect)

{

   if(pDC != NULL)

   {

      rect.DeflateRect(29,0,0,0);

      pDC->Draw3dRect(rect,RGB(0,0,255),RGB(0,0,255));

   }

}

(8)在CCustomMenu类中添加ChangeMenuItem方法,用于修改菜单项信息,代码如下:

BOOL CCustomMenu::ChangeMenuItem(CMenu *menu)

{

    int m_index=0;

    if(menu != NULL)

    {

       int m_itemcount = menu->GetMenuItemCount(); //获得菜单项个数

       for(int i=0;i<m_itemcount;i++)

       {

            //获得菜单项文本

            menu->GetMenuString(i,m_ItemLists[m_index].m_ItemText,MF_BYPOSITION);

            int m_itemID = menu->GetMenuItemID(i); //获得菜单项ID

            m_ItemLists[m_index].m_ItemID = m_itemID;

            if(m_itemID>0)

            {

                m_ItemLists[m_index].m_ItemIndex= m_ImageIndex;

                m_ImageIndex++;

            }

            //修改菜单项信息

            menu->ModifyMenu(i,MF_OWNERDRAW | MF_BYPOSITION | MF_STRING,

                m_ItemLists[m_index].m_ItemID,(LPSTR)&(m_ItemLists[m_index]));

            m_index++;

            CMenu* m_subMenu = menu->GetSubMenu(i);

            if(m_subMenu)

            {

                ChangeMenuItem(m_subMenu);

            }

        }

    }

    return TRUE;

}

(9)改写CMenu类的MeasureItem方法,设置菜单项大小,代码如下:

void CCustomMenu::MeasureItem(LPMEASUREITEMSTRUCT lpStruct)

{

    if(lpStruct->CtlType= =ODT_MENU)

    {

       lpStruct->itemHeight = 22; //设置菜单项的高

       lpStruct->itemWidth = 100; //设置菜单项的宽

       CMenuItemInfo* m_iteminfo;

       m_iteminfo = (CMenuItemInfo*)lpStruct->itemData;

       if(m_iteminfo->m_ItemID = = 0)

       {

             lpStruct->itemHeight = 1; //设置分隔条

       }

    }

}

(10)改写CMenu类的DrawItem方法,重绘菜单项,代码如下:

void CCustomMenu::DrawItem(LPDRAWITEMSTRUCT lpStruct)

{

    if(lpStruct->CtlType= =ODT_MENU)

    {

       if(lpStruct->itemData = = NULL)    return;

       unsigned int m_state = lpStruct->itemState; //获得菜单项状态

       CDC* pDC = CDC::FromHandle(lpStruct->hDC);

       CString str = ((CMenuItemInfo*)(lpStruct->itemData))->m_ItemText;

       LPSTR m_str = str.GetBuffer(str.GetLength());

       int m_itemID = ((CMenuItemInfo*)(lpStruct->itemData))->m_ItemID;     

       int m_itemicon = ((CMenuItemInfo*)(lpStruct->itemData))->m_ItemIndex;

       CRect m_rect = lpStruct->rcItem;      

       pDC->SetBkMode(TRANSPARENT); //设置菜单项文本背景透明        

       switch(m_itemID)

       {

       case 0:     //绘制分隔条

                 DrawSeparater(pDC,m_rect);

                 break;

        default:   //绘制菜单项和左侧标题

                 DrawComMenu(pDC,m_rect,m_state&ODS_SELECTED);

                 DrawItemText(pDC,m_str,m_rect);

                 DrawMenuTitle(pDC,m_rect,"明日科技有限公司");             

                 break;

        }

    }

}

(11)在主窗口的头文件中声明一个CCustomMenu类对象m_Menu,在主窗口的OnInit Dialog函数中添加如下代码,装载菜单资源。

m_Menu.LoadMenu(IDR_MENU1); //装载菜单资源

m_Menu.ChangeMenuItem(&m_Menu);

(12)处理主窗口的WM_CONTEXTMENU消息,弹出菜单,代码如下:

void CPopMenuDlg::OnContextMenu(CWnd* pWnd, CPoint point)

{

   CMenu* m_tempmenu = m_Menu.GetSubMenu(0);

   m_tempmenu->TrackPopupMenu(TPM_LEFTBUTTON|TPM_LEFTALIGN,point.x,point.y,this);

}

当鼠标右键单击程序窗口的客户区时,程序会收到一条WM_CONTEXTMENU消息,在该消息的处理函数中使用TrackPopupMenu方法弹出菜单。

(13)在主窗口中添加消息WM_DRAWITEM和WM_MEASUREITEM,并分别在这两个消息的处理函数中调用m_Menu对象的DrawItem方法和MeasureItem方法。

A006 MFC从零开始【MFC菜单】 在win32中,菜单是一个句柄对象 - HMENU在MFC中,菜单是一个CMenu类对象根据我们分析的源代码,如果想要让CMenu代表一个菜单,必须让CMenu与HMENU实现绑定。 阅读详情

相关推荐

MFC自定义弹出式菜单实战:从CMenu类到TrackPopupMenu高级应用

弹出式菜单作为经典的桌面软件交互元素,其核心原理是通过资源定义与动态加载实现按需触发的快捷操作。在Windows编程中,菜单资源管理与消息映射机制构成了其技术基础,CMenu类作为菜单控制器,通过LoadMenu加载资源、GetSubMenu获取子菜单、TrackPopupMenu控制显示位置与行为。这种设计模式在嵌入式上位机、工控软件等对交互效率要求高的场景中价值显著,能够提升操作的专业性与用户体验。本文以MFC框架为例,深入解析如何为CListCtrl等控件实现智能右键菜单,涵盖坐标转换、动态菜单项更新

weixin_30591551的博客 466

MFC CMenu类

CMenu类的主要成员函数        MFC为菜单的操作提供了CMenu类,下面鸡啄米就常用的几个成员函数进行简单的介绍。        BOOL LoadMenu(UINT nIDResource);        加载菜单资源,并将其附加到CMenu对象上。参数nIDResource指定了要加载的菜单资源的ID。如果菜单加载成功则返回TRUE,否则返回FALSE。

Alexander_Frank的博客 2255

MFC透明菜单CMenu

MFC CMenu透明菜单,创建透明菜单。

MFC---菜单资源详解及CMenu类(菜单、工具栏与状态栏)

上一节讲了标签控件Tab Control以后,常用控件的内容就全部讲完了,当然并没有包括所有控件,主要是一些很常用很重要的控件。本节开始将为大家讲解菜单的概念及使用。菜单简介菜单在界面设计中是经常使用的一种元素,包括Windows系统中的窗口、智能终端设备的应用界面等都会经常见到菜单的身影。我们在对可视化窗口操作时,菜单确...

weixin_40523030的博客 795

MFC 自定义菜单栏背景颜色,位置,宽度,高度,选中高亮

MFC 自定义菜单栏背景颜色,位置,宽度,高度,选中高亮以及颜色设置,菜单栏加载,菜单栏位置显示设置等等。

自绘/重绘MFC右键菜单CMenu

自绘/重绘MFC右键菜单CMenu

MFC菜单栏(CMenu)控件

1.设置菜单左边显示位图和背景位图 CMenu类里要了解的函数 SetMenuItemBitmaps//设置菜单项左边的位图 函数定义:BOOL SetMenuItemBitmaps( UINT nPosition, UINT nFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked ); nPostion

lanmeng_smile的专栏 5897

阿里云Windows服务器部署网站全流程:从IIS配置到安全上线

Web服务器是承载网站应用、处理HTTP请求的核心软件。其工作原理是监听特定网络端口,接收客户端请求,并返回相应的网页、文件或动态生成的内容。在Windows Server环境中,IIS(Internet Information Services)作为微软官方Web服务器,凭借其与操作系统深度集成、图形化管理界面和对ASP.NET等微软技术栈的良好支持,成为许多开发者和运维人员的首选。其技术价值在于提供了稳定、可扩展的托管平台,支持从简单的静态网站到复杂的企业级Web应用。在云服务器普及的今天,将IIS部署

weixin_33552698的博客 327

转:VC MFC菜单栏(CMenu)控件(菜单栏字体大小的更改。。。等等)

菜单栏 在对话框窗口里显示菜单栏 像工具栏一样,菜单栏在按件面板里没有对应的选项,但有一个菜单控件类CMenu,所以如果想要在对话框里显示菜单栏,就得像工具栏那样,到ResourceView选项卡里新建一个菜单栏资源,步骤跟新建工具栏资源一样,只是资源类型是:Menu,菜单资

2万+

Qt UI界面美化教程1:【“飞扬青云” Qt精美控件】使用教程1

相信很多小伙伴在使用Qt Widget的过程中都会遇到一个问题,开发出来的界面,丑!丑!丑!当然Qt做界面美化可以用到QSS,需要对前端知识有一定了解,后续本套教程将会做讲解。本篇文章,我们直接站在巨人(大佬飞扬青云)的肩膀上,使用他开发好的163款自定义控件,请大家一定支持他,去给他小心心,他的个人主页:本篇文章只讲述如何在 QtDesigner 安装这些控件。

2401_87556704的博客 1420

Cadence 17.4 PSpice仿真555定时器输出方波

这里利用555定时器组成多谐振荡器产生1Hz的方波并用PSpice仿真其输出的方波波形。555定时器是一种广泛应用的中规模集成电路。根据其内部组成的不同,可分为双极型(555B)和CMOS型(555C)两类。两种类型的定时器各有所长。双极型定时器具有较大的驱动能力,其输出电流可达200mA,可直接驱动发光二级管、扬声器、继电器等负载。而CMOS型定时器的输入阻抗高、功耗低。

tj_nonstoper的博客 1万+

菜单设计 CMenu

6.1  菜 单 设计 菜单是可视化编程的重要组成部分,是一种方便地给命令分组并访问这些命令的方法。菜单通常用来显示程序的各项功能,以方便用户选择执行,通过对菜单命令进行编程可以调用程序中相应的功能。   6.1.1  菜单类CMenu 在MFC中,CMenu类封装了Windows的菜单功能,它提供了多个方法用于创建、修改、合并菜单。CMenu类的主要方法如下。 (1

season的博客 4109

Allan方差这个工具,怎么把它用的更顺手?(附Allan方差、动态Allan方差代码)

本文详细说明了Allan方差和动态Allan方差的计算过程,并通过递归运算和时间序列选择两种算法提高动态Allan方差的计算效率。文末提供了快速动态Allan方差计算代码。

victoryqian528的博客 374

CMenu菜单自绘

 

маО⌒кц的专栏 1642

基于物联网设计的蜂箱智能监测系统设计

为解决传统养蜂业依赖人工、管理效率低下、干扰蜂群等问题,本项目设计并实现了一套基于物联网(IoT)的蜂箱智能监测系统。

685

AgentScope 2.0 源码解析-工具系统解读:从内置工具到权限管控的完整实践

本文深入解析AgentScope 2.0工具系统的完整架构,覆盖内置工具集(文件读写、命令执行、搜索匹配)、MCP协议集成(STDIO/HTTP双传输、客户端封装、工作空间网关)、工具包管理与动态分组、权限引擎的多级决策机制(危险路径保护、只读识别、模式控制),以及自定义工具开发流程。通过分层架构图和时序图直观展示组件协作关系,结合安全最佳实践与故障排除指南,为开发者提供从工具使用到安全管控的全链路参考。

program哲学 570

VC MFC菜单栏(CMenu)控件用法

VC MFC菜单栏(CMenu)控件用法

eickandy的专栏 3556

单片机:实现FFT快速傅里叶变换算法(附完整源码)

单片机:实现FFT快速傅里叶变换算法(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 1101

CMenu 菜单隐藏

1 在设置CMenu 项中还有这个变量,在构造函数中进行设置:m_bAutoMenuEnable = FALSE; 2 GetMenu()->GetSubMenu(0)->EnableMenuItem(0,  MF_GRAYED);

835

GEE 案例:基于陆地卫星8号(大气层顶反射率数据)LANDSAT/LC08/C02/T1_TOA的生态遥感指数RSEI计算、可视化和下载

摘要:基于GEE的遥感生态指数(RSEI)计算方法 本文介绍了利用Google Earth Engine(GEE)平台计算遥感生态指数(RSEI)的全流程方法。主要内容包括:研究区域定义、Landsat8数据获取与去云预处理、关键生态指标计算(地表温度LST、植被指数NDVI、湿度指数WET和建筑指数NDBSI)、主成分分析(PCA)降维处理,以及结果可视化与数据导出。通过结合多源遥感指标并采用归一化处理,构建了综合反映区域生态环境质量的RSEI指数。该方法为生态环境监测提供了高效的技术方案,所有计算过程均

此星光明博客 451

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

MFC小练手:详解自绘右键菜单(继承CMenu)

也许女生被人感觉审美观会好点,所以第一个任务就是设计一个菜单。   而我的审美观觉得我做的东西都不会很colorful,因为我是个素色主义者,平日里穿的衣服裙子都是黑白灰红的深女风。(咳跑题了)   于是我做的东西都是十分简约的扁平化设计。但是问了身边的朋友,貌似女生更能接受这种风格,男生貌似认为xp那种左边有条蓝边的更好看,我表示十分不能理解。 废话一大堆,入正题吧。   从网上

恩小习 是一只程序猿 6713

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

CMenu

Menu可以看做是一个2维的表 子菜单1  子菜单2   子菜单3 菜单项1 菜单项2 子菜单是一个PopUp是弹出菜单,不能响应消息,作用弹出子菜单下面的菜单项目 CMenu.GetSubMenu CMenu.GetSubItem

fysy0000的专栏 2068

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

MFC学习笔记--菜单类CMenu和控件类CButton

8.3 菜单类 菜单允许用户用一种标准的方法与Windows应用程序进行交互:样式一致的用户界面对象----菜单栏。 位于窗口顶端的菜单栏是“顶层菜单”,单击时再出现的是下拉菜单,其中包含一个或多个“菜单项”。菜单可以分为下拉式和弹出式。 可以定义菜单的热键(在Caption属性字母前加&),可以定义菜单的快捷键。 菜单一般存在在资源脚本中,在程序运行时才调用。一个菜单项一般有两个必要的部分,他们分别是字符串名和整数标识符。一般来说,菜单的标识符ID在资源的头文件Resource.h中定义,例...

S_BlueSky的博客 903

怎样使用CMenu类

CMenu类从CObject类派生而来。为什么要使用CMenu类呢?AppWzard不是把菜单做好了吗?在资源编辑器上修改菜单不是很方便吗?我是个vc++初学者,自从当斑竹以来,天天看贴子,也学到了不少东西。感觉学vc++稍微深入一点好,至少要能搞清楚AppWizard在背后都干了些什么东西。事实上mfc就是用CMenu类来生成菜单的。让我们就从CMenu开始吧。CMenu...

SurpassLi的专栏 38
上一篇: 转:表达式左值右值(C++学习) .
下一篇: 转:VC MFC菜单栏(CMenu)控件(菜单栏字体大小的更改。。。等等)
露儿
博客等级 码龄17年 11粉丝 8原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值