到目前的 Version 11 Beta 2 为止,PB 仍不支持如图1 所示的单选菜单项。但实际应用中,我们需要用类似的菜单来选择字体大小、缩放比例等等。如果用复选菜单项代替的话,也不尽如人意。本文将介绍使用 Win32 API 函数来实现单选菜单项。
图1
这里笔者先创建菜单对象 m_base,并声明 Local External Function 的 Powersoft 原型:
function ulong GetMenu(ulong hWnd) library "user32.dll" //获取指定窗口的菜单句柄
function ulong GetSubMenu(ulong hMenu, long nPos) library "user32.dll" //获取指定菜单的子菜单
function boolean CheckMenuRadioItem(ulong hmenu, ulong idFirst, ulong idLast, ulong idCheck, ulong uFlags) library "user32.dll" //在指定菜单上设置单选菜单项
建议将参数 uFlags 设为 MF_BYPOSITION(1024),而非 MF_BYCOMMAND(0) 以避免要预先获取 COMMANDID 的麻烦。
定义 m_base 的方法 position:
/**/ /************************************************************************************
用途:获取指定菜单项在菜单中的位置
参数:
menuItem 待确定位置的菜单项
返回值:
如果菜单有效且菜单项是可见的,则返回非0值;否则,返回0。
************************************************************************************/
int i, j, n
menu mParent
mParent = menuItem.GetParent( )
if not IsValid(mParent) then return 0
n = upperBound(mParent.Item)
for i = 1 to n
if mParent.Item[i].visible then
j ++
if mParent.Item[i] = menuItem then return j
end if
next
return 0
end function
注意,由于 PB 不会使用 Win32 API 函数 InsertMenuItem( ) 创建 visible = false 的菜单项 (但其 COMMANDID 仍被预留),所以在计算位置时要跳过不可见的菜单项。
定义 m_base 的方法 handle:
/**/ /***********************************************************************
用途:获取指定菜单项的菜单句柄
参数:
menuItem 待确定菜单句柄的菜单项
返回值:
返回菜单句柄
************************************************************************/
menu mParent
mParent = menuItem.GetParent( )
if not IsValid(mParent) then
return GetMenu(handle(ParentWindow))
else
return GetSubMenu(handle(mParent), position(menuItem) - 1 )
end if
end function
需要说明的是:
本身不是子菜单的菜单项是没有句柄的,只有菜单才有句柄。
所以方法 handle 获取的是指定菜单项 (无论是否是子菜单) 所在的父菜单的句柄。
定义 m_base 的方法 checkradio:
/**/ /***************************************************************************************
用途:设置单选菜单项
参数:
itemFirst 组里的第一个菜单项
itemLast 组里的最后一个菜单项
itemCheck 组里的被选中的菜单项
返回值:
如果父菜单存在且 API 调用成功,则返回 TRUE;否则,返回 FALSE。
****************************************************************************************/
menu mParent
mParent = itemFirst.GetParent( )
if IsValid(mParent) then
return CheckMenuRadioItem(handle(mParent), position(itemFirst) - 1 , &
position(itemLast) - 1 , position(itemCheck) - 1 , 1024 ) // MF_BYPOSITION
else
return false
end if
end function
现举例说明如何调用方法。如图2所示的菜单派生自菜单 m_base,菜单 m_view 的菜单项 m_largeIcon、m_smallIcon、m_list 和 m_detail 要构成一个单选菜单项的组,为此需定义 m_view 的 Clicked 事件脚本:
图2
ListView listCtrl
listCtrl = ParentWindow.dynamic GetLeftSideListCtrl( )
choose case listctrl.view
case ListViewLargeIcon !
CheckRadio(m_largeicon, m_detail, m_largeicon)
case ListViewSmallIcon !
CheckRadio(m_largeicon, m_detail, m_smallicon)
case ListViewList !
CheckRadio(m_largeicon, m_detail, m_list)
case ListViewReport !
CheckRadio(m_largeicon, m_detail, m_detail)
end choose
end event