如何动态使用VB快捷键?

yulinlover 2009-10-18 06:03:36
我有个功能需要实现VB.Form上的菜单的动态添加、修改、删除功能,现遇到以下一个问题一直未能克服,特来向大师们求教:
1、我已有的Form上的菜单是用VB自带的MenuEditor生成的,里面的有个别的菜单是有快捷键的,我子类化了此窗体。现在鼠标点击此菜单的时候,我都能感应到相应的消息(WM_COMMAND),可是我用快捷键去激活菜单,VBIDE里的代码能相应,但是我子类化的过程却收不到相应消息,请问是什么原因造成的呢?

Form菜单代码:(快捷键是:Ctrl+N)

Private Sub mnuFileOpen_Click()
'/* 快捷键及鼠标点击都能执行到
MsgBox "FormMenu Clicked!" & mnuFileOpen.Name
End Sub


子类化代码:(快捷键激活菜单时,下面过程捕捉不到,但是点击是可以捕捉到得)

Private Function ISubclass_WindowProc(ByVal Hwnd As Long, ByVal iMsg As Long, ByVal wParam As Long, ByVal lParam As Long, Optional bCancel As Boolean = False) As Long
Dim tWinMessage As MSG
Dim lMenuID As Long
Dim oMenuItem As MenuItem
Select Case iMsg
Case WM_COMMAND
If lParam = 0 Then
lMenuID = LOWORD(wParam)
Set oMenuItem = m_oMenuHelper.FindMenuItemByID(lMenuID)
If Not oMenuItem Is Nothing Then
MsgBox "MenuItem(" & oMenuItem.Name & ") Clicked!"
End If
End If
Case WM_SYSKEYUP, WM_KEYUP, WM_KEYDOWN, WM_SYSKEYDOWN
tWinMessage.Hwnd = Hwnd
tWinMessage.message = iMsg
tWinMessage.wParam = wParam
tWinMessage.lParam = lParam
tWinMessage.time = CLng(Now)
TranslateMessage tWinMessage
MsgBox "wParam:" & wParam & ",lParam:" & lParam
Case Else

End Select
End Function


是不是因为我捕捉的消息不对,VB的MenuEditor编辑出来的快捷键再按得时候会触发什么消息呢?
...全文
320 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
yulinlover 2009-10-21
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 tiger_zhao 的回复:]
没要求你自己做消息循环,而是在 ISubclass_WindowProc 中做 TranslateAccelerator。
WM_KEYDWN 当然是发生在输入焦点控件上。
[/Quote]

TranslateAccelerator这个API,我在上面的子类过程里一直没有使用成功,好在知道它就是翻译一个按键消息为WM_COMMAND的菜单消息,于是用我上面讲到过的思路搞定了,感谢majian与Tiger的回答。

由于公司内网没办法上传东西,否则我会把此功能点传上网,以供有相同需要的同志使用研究。
Tiger_Zhao 2009-10-20
  • 打赏
  • 举报
回复
这需要用到加速键表,这是 MSDN 的步骤
[Quote=MSDN:]
Using an Accelerator Table Created at Run Time
==============================================
The Win32 API allows you to create accelerator tables at run time. The steps involved in creating and using an accelerator table at run time are as follows:

·Define the accelerators by filling an array of ACCEL structures, and then create an accelerator table by passing the array to the CreateAcceleratorTable function.
·Activate the accelerator table and process WM_COMMAND messages generated by the accelerators.
·Destroy the accelerator table before the application closes. [/Quote]
相关的 例子1 例子2

你没有用 TranslateAccelerator,这样是无法生成成 WM_COMMAND 的。
Tiger_Zhao 2009-10-20
  • 打赏
  • 举报
回复
没要求你自己做消息循环,而是在 ISubclass_WindowProc 中做 TranslateAccelerator。
WM_KEYDWN 当然是发生在输入焦点控件上。
嗷嗷叫的老马 2009-10-20
  • 打赏
  • 举报
回复
这个的话,貌似子类化是帮不到你了......

我用SPY++分析了一下,当菜单设置了快捷键时,按下时根本就是只有键盘消息产生:

<00318> 00580312 P WM_KEYDOWN nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:1 fAltDown:0 fRepeat:0 fUp:0
<00319> 00580312 P WM_KEYDOWN nVirtKey:'O' cRepeat:1 ScanCode:18 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00320> 00580312 P WM_CHAR chCharCode:'15' (15) cRepeat:1 ScanCode:18 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00321> 00580312 P WM_KEYUP nVirtKey:'O' cRepeat:1 ScanCode:18 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
<00322> 00580312 P WM_KEYUP nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:1 fAltDown:0 fRepeat:1 fUp:1

除此之外再无别的消息(SPY++已经设置为拦截所有消息)

因此从子类化里你除了能得到这个所按的热键外,是无法得到其它信息的....

yulinlover 2009-10-20
  • 打赏
  • 举报
回复
感谢老马与TIger得回答。
老马的方法我都试过了,与你得到的是一样的结果,只是有WM_KEYDOWN相关的按键事件。
Tiger提供的资源我一开始就考虑过了,不太适用我的场景,我需要重构的Form窗体是在dll里,而且这个窗体显示的时候还不一定是非模态的,所以那个在sub main()里用消息循环不太适用。其实就是TranslateAccelreator放在哪里合适的问题?

经过最近的尝试,我准备把Form上的所有菜单的快捷键建立一个内存字典(Dictionary),然后设置Form.KeyPreview=true,这样就可以在Form_KeyDown里用GetAsyncKeyState(结合字典)获取按键状态,然后使用SendMessage去转发,这样我的子类化的类是可以收到WM_KEYDOWN的消息了,接着就需要自己把这个消息翻译成WM_COMMAND消息。上面是思路,没有实际去完成了。

另外在问一个问题:不知道我在Form_KeyDown里面得到的信息构造成消息结构后调用TranslateAccelerator,但是不成功,我也把相应的快捷键创建到加速键表里了(CreateAcceleratorTable)。但是子类化的类不会响应。
还有在我试验的过程中发现,子类化了Form后,却收不到WM_KEYDOWN之类的按键消息(目前FOrm上的焦点控件是输入控件,是因为这个原因吗?)。看来我的在用SetWindowHook看看了,能不能接收到WM_KEYDOWN消息,如果能接受到,就不用我上面的那个“曲线救国”的思路了。
舉杯邀明月 2009-10-19
  • 打赏
  • 举报
回复
只有帮顶了...........

-_-!!!
yulinlover 2009-10-19
  • 打赏
  • 举报
回复
同志们帮顶,同时有请majian赐教
yulinlover 2009-10-18
  • 打赏
  • 举报
回复
好像“嗷嗷叫的老马”在VB方面颇有造诣,希望能够指教。分不够我再加。
Flyingdragon168 2009-10-18
  • 打赏
  • 举报
回复
帮顶一下
yulinlover 2009-10-18
  • 打赏
  • 举报
回复
感谢大家的积极回答。不过我现在是重构代码,不是重写,所以即使有第三方控件,但是不会考虑使用,因为已有的功能太过复杂,迁移的话风险太高,我们现在新作的功能都是用ActiveBar3的菜单控件。但是老功能,我希望直接子类化它平台Form,然后动态操纵其含有的菜单,并且我的子类化类也会持有插件接口,现在我所有动态的功能基本完成了,就不知道VB原有菜单按快捷键的时候,我再子类化里如何去截获,所以有此一问。其他的都不是问题了。
threenewbee 2009-10-18
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 yulinlover 的回复:]
不是单纯实现的问题,我的问题主要是动态操作菜单,我的项目需要对以前的老代码进行重构,而直接再设计器写死的菜单便是首当其冲需要重构的,否则在平台的插件里没有办法动态响应菜单的点击以及动态操作相应的菜单。我相信现在如果用VB做项目,为了扩展性,应该没有人愿意使用MenuEditor再框架平台上提供菜单功能,因为那样没办法使窗体元素元数据和动态化。
[/Quote]
考虑到subclass在VB的不可靠性,可以使用三方菜单。
参见http://topic.csdn.net/u/20090827/02/bfbd01d4-b7ce-41ee-ad00-bbf2f0274a41.html

为了隔绝界面实现和插件,可以定义一个模型,使用接口来进行调用。
getemail 2009-10-18
  • 打赏
  • 举报
回复
牛银
鉴定完毕

[Quote=引用 3 楼 yulinlover 的回复:]
不是单纯实现的问题,我的问题主要是动态操作菜单,我的项目需要对以前的老代码进行重构,而直接再设计器写死的菜单便是首当其冲需要重构的,否则在平台的插件里没有办法动态响应菜单的点击以及动态操作相应的菜单。我相信现在如果用VB做项目,为了扩展性,应该没有人愿意使用MenuEditor再框架平台上提供菜单功能,因为那样没办法使窗体元素元数据和动态化。
[/Quote]
yulinlover 2009-10-18
  • 打赏
  • 举报
回复
不是单纯实现的问题,我的问题主要是动态操作菜单,我的项目需要对以前的老代码进行重构,而直接再设计器写死的菜单便是首当其冲需要重构的,否则在平台的插件里没有办法动态响应菜单的点击以及动态操作相应的菜单。我相信现在如果用VB做项目,为了扩展性,应该没有人愿意使用MenuEditor再框架平台上提供菜单功能,因为那样没办法使窗体元素元数据和动态化。
threenewbee 2009-10-18
  • 打赏
  • 举报
回复
Form的KeyPreview设为true
在Form的Key_Press里面直接写就行了。

似乎不用subclass。
getemail 2009-10-18
  • 打赏
  • 举报
回复
up

1,486

社区成员

发帖
与我相关
我的任务
社区描述
VB API
社区管理员
  • API
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧