Toolbar制作菜单条过程详解

时间:2022-11-29 04:13:59 

文章来源:互联网 作者:ggg82/CSDN

现在许多用户界面都使用工具栏制作菜单条,小弟最近对此感兴趣,便从网上求助,可是得到的帮助大多是BCGControlBar的源代码或者是SizableRebar的源代码,对于只希望是自己的界面具有该功能的朋友来说,这也许是不错的选择,只要看一下demo,然后直接调用别人的类库就可以了,但对于我等对此话题感兴趣,希望弄懂其来龙去脉的读者来说,直接看这些没有详细解释的源代码,要从中弄出个所以然来,实不是件容易的是,至少对于像我这样的菜鸟来说是这样的,本文出于此种原因,希望对还在寻求此帮助的读者能提供一些帮助。

下面我们边看边侃:

在接收到toolbarbutton按下消息时,我们一般使用TrackPopupMenuEx弹出菜单,问题的关键是,在菜单未关闭时,TrackPopupMenuEx并不返回,并拦截鼠标和键盘消息,使用spy可以看到,此时的工具栏收不到任何消息,当然无从改变热点,这就需要我们自己探测鼠标位置并在鼠标移动到下一个热点时关闭上一个菜单并显示下一个菜单。这里我们使用钩子函数SetWindowsHookEx在调用TrackPupupMenuEx前安装WH_MSGFILTER钩子,代码如下:
m_hMsgHook = SetWindowsHookEx( WH_MSGFILTER, MessageProc, 0, GetCurrentThreadId() );
MssageProc是钩子函数,代码如下:



LRESULT CALLBACK MessageProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code == MSGF_MENU)
{
HookMessageProc(lParam);
}
return CallNextHookEx(m_hMsgHook, code, wParam, lParam);
}
函数检查消息,如果是来自菜单,则将消息传递给函数HookMessageProc处理,我们所要做的就是在该函数中检测消息WM_MOUSEMOVE,并测试鼠标位置,如果鼠标已经移动到另一个按钮上,则关闭菜单并显示下一个菜单,关闭菜单使用消息WM_CANCELMODE,当菜单关闭后,我们要释放钩子,在下一个菜单弹出时重新安装钩子,弹出菜单示例代码如下:



 void TrackPopup(HWND hWndToolBar, int iButton)
 {
 while (iButton >= 0)
 {
 SendMessage(hWndToolBar,TB_SETHOTITEM,iButton,0);
 iPopup = iButton;
 //安装钩子
 g_hMsgHook = SetWindowsHookEx(WH_MSGFILTER, MessageProc, 0, GetCurrentThreadId());
 //弹出菜单
 TrackPopupMenuEx(…);
 //卸载钩子
 UnhookWindowsHookEx(g_hMsgHook);
 iButton = iNextPop; //下一个弹出项,若为负,则退出
 }
 SendMessage(hWndToolBar,TB_SETHOTITEM,-1,0);

}

(经验与建议:如果button使用样式TBSTYLE_DROPDOWN,请不要在消息TBN_DROPDOWN中直接调用该函数,应使用中间消息,然后使用PostMessa个发送该消息,以使TBN_DROPDOWN可以直接返回,否则消除第一个高亮热点是很麻烦的事。)

iPopup为当前弹出项,iNextPop为下一个弹出项,这些变量需要在函数HookMessageProc中处理,示例代码如下:



void HookMessageProc(MSG * pMsg)
{
if (pMsg->message == WM_MOUSEMOVE)
{
int iButton, iCount;
POINT pt = { LOWORD(pMsg->lParam), HIWORD(pMsg->lParam) };
ScreenToClient(hWndToolbar, &pt);
iButton = SendMessage(hWndToolbar, TB_HITTEST, 0, &pt);
iCount = SendMessage(hWndToolbar, TB_BUTTONCOUNT, 0, 0);
if (iPopup != iButton && iButton < iCount && iButton >= 0)
{
iNextPop = iButton;
SendMessage(hWndMain, WM_CANCELMODE, 0, 0);
}
else
{
iNextPop = -1;
}
}
}
(经验与建议:不要试图在此处调用TrackPopup,我曾试图取消该函数内的while循环,直接在此调用该函数,结果是在TrackPopupMenuEx未返回之前,该函数已被调用)

这里,仅仅处理了鼠标移动消息,真正的菜单还应处理键盘导航消息,详细的代码可以参考
BCGControlBar(http://www.vckbase.com/code/downcode.asp?id=1382)
或SizableRebar(http://www.codeproject.com/docking/sizablerebar/SizableRebar_demo.zip


有了这底层框架,这些处理过程应该不再困难,文章所涉及到的一些API函数可以参考msdn。
Msdn上相关资料:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/faq/iemenubar.asp
http://www.microsoft.com/msj/0199/c/c0199.aspx

标签:To,oo,ol,lb,ba,ar,r制,制作,作菜,菜单,单条,条过,过程,程详,详解,解
0
投稿

猜你喜欢

  • 简单了解JavaBean作用及常用操作

    2023-09-08 19:59:29
  • WPF实现雷达图(仿英雄联盟)的示例代码

    2023-07-13 18:46:53
  • Redis集群与SSM整合使用方法

    2023-07-02 02:17:05
  • java中Statement 与 PreparedStatement接口之间的关系和区别

    2023-11-25 03:11:11
  • C#中一些你可能没用过的调试窗口的方法

    2022-08-07 09:01:16
  • java基础之Object类

    2022-11-17 21:20:10
  • SpringBoot整合Apollo配置中心快速使用详解

    2022-12-25 17:00:34
  • JAVA递归生成树形菜单的实现过程

    2023-07-15 08:57:22
  • Android优雅地处理按钮重复点击的几种方法

    2021-11-23 05:09:14
  • 新手初学Java对象内存构成

    2022-05-10 07:21:25
  • 在 C# 中使用 Span<T> 和 Memory<T> 编写高性能代码的详细步骤

    2022-06-06 05:06:41
  • C#算法之整数反转

    2021-09-24 18:36:49
  • spring中bean id相同引发故障的分析与解决

    2023-08-05 11:30:41
  • jvm虚拟机类加载机制详解

    2021-10-21 08:33:28
  • Spring Boot整合Web项目常用功能详解

    2023-06-04 17:14:21
  • C#编程总结(一)序列化总结

    2022-04-07 04:25:19
  • SpringBoot使用GraphQL开发Web API实现方案示例讲解

    2023-05-17 16:50:22
  • SpringCloud @RefreshScope刷新机制浅析

    2022-12-13 11:38:15
  • Java 数据结构与算法系列精讲之排序算法

    2023-11-01 13:25:40
  • 详解Java获取环境变量及系统属性的方法

    2021-08-23 16:58:03
  • asp之家 软件编程 m.aspxhome.com