启用自定义VCL样式时,如何通过TMenuItem OnClick安全隐藏TMainMenu?
问题描述
在窗体上放置TMainMenu,并将以下处理程序附加到某个TMenuItem上时,启用自定义VCL样式会触发访问冲突错误:
procedure TForm1.HideMenuClick(Sender: TObject); begin Menu := nil; { 触发异常:$C0000005,访问地址0x00000008时读取错误 } end;
使用带延迟的TThread.ForceQueue可以解决,但仅在延迟足够大时生效:
procedure TForm1.HideMenuClick(Sender: TObject); begin TThread.ForceQueue(nil, procedure begin Menu := nil end, 20); end;
补充细节:
- 鼠标操作触发菜单项时必现问题
- 键盘打开并激活菜单项时,仅需调用无延迟的
ForceQueue即可避免冲突 - 快捷键激活菜单项时,直接
Menu := nil就能正常工作
可靠实现方式
最简洁且不依赖延迟的方案是使用无延迟的TThread.ForceQueue,它会把设置Menu := nil的任务放到主线程消息队列末尾,等当前菜单的点击事件处理流程完全结束后再执行,从根源上避免VCL样式代码在后续处理中访问已被释放的菜单对象:
procedure TForm1.HideMenuClick(Sender: TObject); begin TThread.ForceQueue(nil, procedure begin Menu := nil; end); end;
这个方案能统一适配鼠标、键盘、快捷键三种激活场景,无需判断操作方式,也不用依赖不确定的延迟时间,完全符合VCL消息处理的机制逻辑。
内容的提问来源于stack exchange,提问作者A. Bonic
相关产品推荐
相关产品推荐

