作者:丁健 张万军 江南
右顺序对齐菜单就是菜单在菜单条的最右侧对齐,往左排列。平时,我们能看到很多右顺序对齐菜单的例子,如“WPS2000集成办公系统”有文件打开时的“定制界面”菜单、Origin2.5的“Help”菜单等。将右顺序对齐菜单应用于应用程序中,可以打破常规菜单左顺序对齐的显示方式,给人耳目一新的感觉;另外,我们可以将一些需要实时更新的消息、提示等显示在右顺序对齐菜单中,醒目突出,既符合人体肉眼查询信息的习惯,又可避免占用窗体或状态栏空间。因此,右顺序对齐菜单具有一定的实用性。
Visual C++环境下的实现方法
Visual C++的编程环境支持可视化的菜单设计,在设计菜单时可直接将菜单指定为“右顺序对齐菜单”。具体方法是:选定菜单后双击或在右键菜单中选“属性”,打开菜单属性对话框,选“Extended Styles”标签,在“Extended Styles”标签板上只有“右-左顺序对齐”项,选择“右-左顺序对齐”项即可。注意,上述指定只对菜单条上的菜单有效,对子菜单项也可指定但运行时没有效果。图1为经过Visual C++编译后的右顺序对齐菜单应用程序运行时的显示效果。
图1 VC环境下右顺序对齐菜单应用程序
Visual Basic环境下的实现方法
Visual Basic环境不支持直接指定、创建右顺序对齐菜单,必须通过编程实现。根据MSDN对菜单信息数据结构、相关API函数的解释,可概括出实现这项功能的四个步骤或称具体程序流程:
1.定义菜单信息数据结构MenuItemInfo全局对象;
2.用GetMenuItemInfo API函数取得指定的菜单信息,并将信息存放于定义的MenuItemInfo对象内;
3.将定义的MenuItemInfo全局对象的fType部分设为MFT_RIGHTJUSTIFY(设置右顺序对齐菜单的关键参数);
4. 用SetMenuItemInfo API函数重新设置菜单。
MenuItemInfo的定义
MenuItemInfo存放菜单特征信息如: 类型、状态、标识号、句柄指针值等,这些特征信息决定了菜单的标题内容、排列顺序、响应方式等等。适当改变其中某些信息即可实现菜单右顺序对齐。
MenuItemInfo的定义如下:
typedef struct tagMENUITEMINFO {
UINT cbSize;
UINT fMask;
UINT fType;
UINT fState;
UINT wID;
HMENU hSubMenu;
HBITMAP hbmpChecked;
HBITMAP hbmpUnchecked;
DWORD dwItemData;
LPTSTR dwTypeData;
UINT cch;
} MENUITEMINFO,FAR *
LPMENUITEMINFO。
MenuItemInfo结构中与右顺序对齐菜单实现密切相关的是fType参数,fType存放菜单项的类型参数,它可以是预定义值中的一个或几个。
其中的MFT_RIGHTJUSTIFY常数可将本菜单项及其随后的菜单调整到菜单条的右侧排列。
API函数GetMenuItemInfo、SetMenuItemInfo简介
GetMenuItemInfo函数简介:
函数功能:取得一个菜单项的信息。
函数原型:BOOL GetMenuItemInfo(HMENU hMenu, UINT uItem, BOOL fByPosition, LPMENUITEMINFO Ipmii)。
参数:
hMenu:包含指定菜单项的菜单的句柄。
uItem: 将要取得其信息的菜单项的标识符或位置,此参数的含义取决于参数fByPosition的值。
fByPosition: 此值用于指定参数uItem的含义,如果此参数是FALSE,则uItem表示菜单项的标识符; 否则,表示菜单项的位置。
Ipmii:指向结构MenuItemInfo的指针,该结构指定要取得的信息并接收菜单项的信息。
返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。
调用注意点:Windows CE环境下,由参数Ipmii指向的MenuItemInfo结构中的fMask不能取MIM_CHECKMARKS。
SetMenuItemInfo函数简介:
函数功能:该函数改动一个菜单项的信息。
函数原型:BOOL SetMenuItemInfo(HMENU hMenu, UINT uItem, BOOL fByPosition, LPMENUITEMINFO Ipmii)。
参数:
hMenu: 包含菜单项的菜单的句柄。
uItem: 将被修改的菜单项的标识或位置,此参数的含义由参数fByPosition确定。
fByPosition: 此值用于指定uItem的含义。如果此参数值为FALSE,则参数uItem是菜单项的标识;否则,表示菜单项的位置。
Ipmii:指向结构MenuItemInfo的指针,该结构含有菜单项的信息,并且指定将被修改的菜单项的属性。
返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。
调用注意点:为了使键盘加速键能控制位图或自己绘制的菜单项,菜单的拥有者必须处理WM_MENUCHAR消息。Windows CE环境下,只有下列值对参数Ipmii指向的MenuItemInfo结构中的fMask成员有效:MIIM_DATA、MIIM_ID和MIIM_TYPE 。如果MIIM_TYPE被指定,结构MenuItemInfo的fType成员必须为菜单项的当前类型,也就是说,该类型不能被改变。
Visual Basic环境下的源代码(以实现图2所示菜单为例):
’数据结构声明
Public Type menuItemInfo
cbSize As Long
fMask As Long
fType As Long
……
End Type
’API函数声明
Public Declare Function SetMenuItemInfo Lib “user32” Alias “SetMenuItemInfoA” (ByVal hMenu As Long, ByVal un As Long, ByVal bool As Boolean, lpcMenuItemInfo As menuItemInfo) As Long
Public Declare Function GetMenuItemInfo Lib “user32” Alias “GetMenuItemInfoA” (ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As menuItemInfo) As Long
Public Declare Function DrawMenuBar Lib “user32” (ByVal hwnd As Long) As Long
Public Declare Function GetMenu Lib “user32” (ByVal hwnd As Long) As Long
’在窗体载入过程(也可放在其他过程)中对菜单设置进行更改
Private Sub Form_Load()
Dim my_menuItemInfo As menuItemInfo
Dim return_value As Long
my_menuItemInfo.cbSize = 44
my_menuItemInfo.fMask = 16
’MIIM_TYPE
my_menuItemInfo.cch = 128
my_menuItemInfo.dwTypeData
= Space$(128)
return_value = GetMenuItemInfo(GetMenu(Me.hwnd), 2, 1, my_menuItemInfo)
my_menuItemInfo.fType = 16384
’MFT_RIGHTJUSTIFY
return_value = SetMenuItemInfo(GetMenu(Me.hwnd),2, 1, my_menuItemInfo)
DrawMenuBar GetMenu(Me.hwnd)
End Sub
图2为Visual Basic环境下编译的应用程序右顺序对齐菜单显示效果。
图2 Visual Basic编译的右顺序对齐菜单应用程序
存在的问题
在程序运行过程中,我们常要对菜单标题进行更改,对用上述程序更改为右顺序对齐后的菜单来说,由此带来的一个问题是右顺序对齐显示效果失效,即已经在最右侧的菜单恢复到左侧排列,其原因是菜单标题字符串所在内存空间数据的更改。我们可以在Visual Basic程序中做实验,在窗体鼠标单击事件过程内加入如下语句:
Private Sub Form_Click()
location.Caption = “改变”
’目标位置菜单的名称为location
End Sub
上述程序对显示目标位置的菜单标题作了修改。运行该程序,用鼠标单击窗体部分,结果如图3所示。
图3 失效的右顺序对齐菜单
通过摸索,我们提出了一个变通解决方法:在欲将其调整到右侧的菜单前面加一个空菜单,并在程序中对该空菜单进行右顺序对齐编程。
仍以Visual Basic编译环境下图2所示应用程序的菜单为例,先打开“菜单编辑器”,在“目标位置”菜单前插入一个标题字符为空、名称为“void_menu”的空菜单,接着编译该程序。运行时API函数SetMenuItemInfo将“void_menu”空菜单及其右侧的所有菜单(“目标位置”菜单等)均调整到菜单条最右侧,因为“void_menu”空菜单的标题字符为空,所以该菜单不显示,程序中接下来可以对“目标位置”菜单的标题字符内容作任意修改、更新。图4为对添加的空菜单进行右顺序对齐编程后的显示效果,用前面窗体中的单击事件过程的代码进行测试,可以发现标题更改为“改变”的location菜单仍显示在右侧,完全达到目的。Visual C++编程环境中也可采用类似方法。
……