You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FMX跨平台应用移动TMenuItem后丢失OnClick事件问题

Delphi FMX跨平台菜单迁移问题:顶层菜单项OnClick失效

问题背景

我开发了一款支持Windows和macOS的Delphi FMX跨平台应用,Windows平台使用TMenuBar,macOS平台使用TMainMenu。设计阶段统一使用TMainMenu,在Windows平台启动主窗体时,通过以下代码将TMainMenu的菜单项移至TMenuBar:

procedure TPartViewer.CopyMenu(MenuBar: TMenuBar);
var
  smi: TMenuItem;
begin
  while MainMenu1.ItemsCount > 0 do begin
    smi := TMenuItem(MainMenu1.items[0]);
    MenuBar.AddObject(smi);
  end;
end;

问题现象

顶层菜单项的OnClick事件失效,其余功能均正常:菜单可正常展开,下层菜单项功能完全正常。我原本通过顶层菜单项的OnClick事件触发下层菜单项的启用/禁用逻辑。

排查结果

经追踪发现,问题源于FMX.Platform.Win未收到WM_LBUTTONUP消息,但奇怪的是WM_RBUTTONUP消息可正常触发OnClick事件。尝试重新为OnClick事件绑定新方法也无效,而当菜单项留在TMainMenu中时,功能完全正常。

思考方向?


改进方案

问题核心在于缺失MouseUp事件——没有MouseUp就无法触发OnClick,但MouseDown事件是正常的。由于MouseUp是公共属性而非发布属性,因此遍历顶层菜单项,若存在OnClick事件则将其转换为MouseDown事件:

// 用于存储事件的小型组件
type
TEventHolder = class(TComponent)
public
  Notify: TNotifyEvent;
end;

// 转换事件处理函数
procedure TPartViewer.FixMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  TEventHolder(TMenuItem(Sender).TagObject).Notify(sender);
end;

procedure TPartViewer.CopyMenu(MenuBar: TMenuBar);
var
  smi: TMenuItem;
  holder: TEventHolder; 
begin
  while MainMenu1.ItemsCount > 0 do begin
    smi := TMenuItem(MainMenu1.items[0]);
    if assigned(smi.OnClick) then begin
      smi.OnMouseDown := FixMouseDown;
      holder := TEventHolder.Create(self);
      holder.Notify := smi.OnClick;
      smi.TagObject := holder;
      // 清空原事件,避免后续修复后触发两次
      smi.OnClick := nil;
    end;
    MenuBar.AddObject(smi);
  end;
end;

内容的提问来源于stack exchange,提问作者Bill F

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 20:50:15