建了三个Action, 一个右键菜单上三个菜单项分别对应了三个Action, 但是每个菜单项中间都一个分隔条, 故意让第二个Action不可见, 
act1
-
act2
-
act3右键菜单第一次弹出

act1
-
-
act3
再弹一次就正确了
act1
-
act3(不要让我把分隔条也设上一个Action, 我不喜欢那样做)object Form1: TForm1
  Left = 255
  Top = 136
  Width = 696
  Height = 480
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PopupMenu = pm1
  PixelsPerInch = 96
  TextHeight = 13
  object actlst1: TActionList
    Left = 480
    Top = 119
    object act1: TAction
      Caption = 'act1'
      OnExecute = act1Execute
    end
    object act2: TAction
      Caption = 'act2'
      OnExecute = act2Execute
      OnUpdate = act2Update
    end
    object act3: TAction
      Caption = 'act3'
      OnExecute = act3Execute
    end
  end
  object pm1: TPopupMenu
    Left = 188
    Top = 95
    object act21: TMenuItem
      Action = act1
    end
    object N1: TMenuItem
      Caption = '-'
    end
    object act22: TMenuItem
      Action = act2
    end
    object N2: TMenuItem
      Caption = '-'
    end
    object act31: TMenuItem
      Action = act3
    end
  end
end
//---------
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ActnList, Menus;type
  TForm1 = class(TForm)
    actlst1: TActionList;
    pm1: TPopupMenu;
    act1: TAction;
    act2: TAction;
    act3: TAction;
    act21: TMenuItem;
    act22: TMenuItem;
    act31: TMenuItem;
    N1: TMenuItem;
    N2: TMenuItem;
    procedure act1Execute(Sender: TObject);
    procedure act2Execute(Sender: TObject);
    procedure act3Execute(Sender: TObject);
    procedure act2Update(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.dfm}procedure TForm1.act1Execute(Sender: TObject);
begin
  ShowMessage('1');
end;procedure TForm1.act2Execute(Sender: TObject);
begin
  ShowMessage('2');
end;procedure TForm1.act3Execute(Sender: TObject);
begin
  ShowMessage('3');
end;procedure TForm1.act2Update(Sender: TObject);
begin
  with Sender as TAction do Visible := False;
end;end.

解决方案 »

  1.   

    不是
    你应该放在PopupMenuPopup里面
      

  2.   

    第一次和第二次不一样, 还正常, 正常应该是第二种, 并且菜单的AutoLineReduction属性都设成了maAutomatic,问题虽小, 但能解决的人不一定有
      

  3.   

    LZ:
    我跟踪了一下Delphi的源码,其实问题不在Delphi,而在于你的代码。也就是说,问题在于TAction.Update事件到底什么时候激发的问题。在Delphi的内部,InternalRethinkLines方法被用来处理重复分隔条的显示问题。当上下文菜单被激活的时候,将会执行TMenu.Popup方法,在Popup方面内部,InternalRethinkLines被调用用来处理分隔条,请注意:
    此时LZ的子菜单仍然Visible=True, 于是InternalRethinkLines方法什么也没做。然后Popup方法调用Win32API函数TrackPopupMenu执行菜单的绘制……绘制完毕在菜单显示前,Dephi做了一些手脚,于是调用了每个菜单的InitiateAction方法,最后调用了LZ的Action的Update方法。虽然LZ已经把Visible设置成False,但分隔条却并没有隐藏,于是还是显示了出来。下一次调用的时候,InternalRethinkLines方法注意到有两个重复的分隔条,于是隐藏了最下面的一个,菜单显示出来之后正常了。根据以上的流程,LZ要隐藏菜单条的显示,最好的办法是放到其它的方法中,最好的地方是Popup菜单的OnPopup事件中来处理。
      

  4.   

    难道你不认为这是Delphi的Bug吗?这绝对算作一个Bug吗
      

  5.   

    既然你已经跟踪过了,你就应该知道自己无非在钻牛角尖而已。什么叫Bug?通过精心测试可以避免却没有避免的代码错误或者缺陷,可以称之为bug。任何框架都不可能把问题考虑的滴水不漏,我认为Delphi在这个问题上已经做的很不错,而且相当直观。我在跟踪源代码的时候就在想,Delphi在层层封装的时候,一方面增强了便利性,同时也减少了灵活性。用户必须按照指定的路线来安排代码,否则就达不到预期的目标。这只能说是封装带来的灵活性的损失,但不能说是bug。如果认为自己足够高明,可以把menus单元拷到自己的项目中,修改为需要的执行顺序,必然符合楼主的“业务逻辑”,何乐而不为呢?
      

  6.   

    以下是我能想到的一点解决办法:
    procedure TFormMain.act2Update(Sender: TObject);
    begin
      with Sender as TAction do Visible := not Visible;  pm1.Items.RethinkLines;
    end;修改menus单元(拷贝到项目文件夹下)
    function TMenuItem.RethinkLines: Boolean;
    begin
      Result := InternalRethinkLines(True);
      if Result then
      begin
        RebuildHandle;
        MenuChanged(True);
      end;
    end;
      

  7.   

    楼上真是有心啊, 不过修改Delphi单元这种方式不提倡吧
      

  8.   

    哦怪不得 BORLAND 公司開了10多年,敢情是開發的工具 BUG 太多了以至活不下去了。
      

  9.   

    delphi 太多BUG啦,特别是在继承方面的,只要修改父对象,如果子对象也打开的话,一切换到子对象,马上出错!