是这样的,我开发一个小程序,根据用户权限动态生成功能菜单。但我发现在一个奇怪的问题。如果我在一个静态的菜单里的OnClick里写 FrmMain.Caption := '你好'; 也就是说点击这个菜单,把主窗体的标题栏文字改变成 你好 二个字。执行以后,主窗体标题确实变成了 你好 二个字。但是如果我把动态生成的菜单的OnClick事件指向一个我自定义的过程时,也就是说点击动态生成的菜单的时候去执行我写的一个过程。这个过程里也只有一句句语 FrmMain.Caption := '你好'; 代码确实执行了,但窗体标题栏一点没变。我继续实验,把过程里的代码改成 FrmMain.Panel1.Visible := false; 希望执行后,窗体里的一个panel变为不可见。但代码确实执行了,可是那个Panel依然可见。不知道为什么。在静态菜单里执行这个代码全都好用,动态的就不行。谁知道是什么问题呢?代码如下://动态生成菜单
sMenuItem:= TMenuItem.Create(FrmMain);
sMenuItem.Name := 'MyMenu';
sMenuItem.Caption := '动态菜单';
sMenuItem.Tag := 1;
sMenuItem.OnClick := MyClick; //设置菜单的OnClick事件
MainMenu.Items.Add(sMenuItem);//MyClick过程
procedure TFrmMain.MyClick(Sender: Tobject); 
begin
    self.Caption := '你好';
end;

解决方案 »

  1.   


    MainMenu.Items.Add(sMenuItem); 
    sMenuItem.OnClick := MyClick; //设置菜单的OnClick事件 两句调一下位置看看
      

  2.   

    那再调回来看看 或者用 actionlist吧,指向它
      

  3.   

    不是代码顺序问题。都试了,不行。最奇怪的是,点击菜单的代码已经正确执行了,但caption就是不变。
      

  4.   

    用了actionList,还是不行啊。是我用的不对吗?procedure TFrmMain.ActionFunctionMenuClickExecute(Sender: TObject);
    begin
        self.Caption := '你好';
    end;//动态生成菜单 
    sMenuItem:= TMenuItem.Create(FrmMain); 
    sMenuItem.Name := 'MyMenu'; 
    sMenuItem.Caption := '动态菜单'; 
    sMenuItem.Tag := 1; 
    sMenuItem.OnClick := ActionFunctionMenuClickExecute; //设置菜单的OnClick事件 
    MainMenu.Items.Add(sMenuItem); 
      

  5.   

    sMenuItem.Action := ActionFunctionMenuClick;
    这样写也不行。ActionFunctionMenuClick 是我建立的一个action
      

  6.   

    我在要执行的代码处设了断点,一条条跟下去的,确实执行了。  
    而且我在 self.caption := '你好'; 后面又加了一句 showMessage(self.Caption); 弹出的Message竟然是 你好。
    说明caption确实是改变了。但标题栏的文字就是没变化。
    我用的是delphi7,你的是多少?
      

  7.   

    顺便说一下,我动态生成菜单的代码是写一个unit里的,不是直接写在主窗体的unit里的,能是这个关系吗?
      

  8.   

    我的也是7啊!
    你在self.caption := '你好';后加一句FrmMain.Repaint;试试
      

  9.   

    sMenuItem.OnClick := TFrmMain.MyClick;  这样再试试
      

  10.   

    我简单的在主窗体里写了一下,确实好使。我看我还是把我的原始代码贴出来吧,各位大侠帮我看看。//生成动态菜单的代码 是写在一个单独的unit里的。//参数 MainMenu 传的是主窗体的MainMenu
    //参数 MenuItem 指在哪个菜单上新增子菜单,如果是在MainMenu上新增,则传nil
    function setUserFunctionMenuFromCache(MainMenu:TMainMenu; MenuItem: TMenuItem): Integer;
    var
        pMenuCaption : String; //当前父菜单名称
        sMenuCaption : String; //当前子菜单名称
        pMenuItem : TMenuItem;  //当前父结点
        sMenuItem : TMenuItem;  //当前子结点
        recordCount : Integer; //子结点个数
        i: Integer;    //临时循环变量
        recordList:TList; //存放子结点的LIST
    begin
        recordList := TList.Create;
        pMenuItem := MenuItem;
        //判断是否指定了树根,如果没指定则取权限树的最底层根结点
        if(pMenuItem = nil) then
        begin
            pMenuCaption := '-';  //没有指定树根
        end
        else
        begin
            pMenuCaption := pMenuItem.caption;  //指定了树根
        end;    try
            //取当前父结点的所有子结点,并存放到recordList里
            For i:=0 To FrameConst.C_SYSFUNCTION_LIST_OF_CURRENT_USER.Count-1 do //FrameConst.C_SYSFUNCTION_LIST_OF_CURRENT_USER 这是一个List里面存放的是当前用户拥有的功能编号
            begin
                if(TSysFunctionVO(FrameConst.C_SYSFUNCTION_LIST_OF_CURRENT_USER[i]).getPFunctionName = pMenuCaption) then
                begin
                    recordList.Add(FrameConst.C_SYSFUNCTION_LIST_OF_CURRENT_USER[i]);
                end;
            end;
            recordCount := recordList.Count;
            //把所有子结点添加到父结点上
            if(recordCount > 0) then
            begin
                If(MenuItem <> nil) then  //如果存在子菜单,则去掉父菜单的onclick事件
                begin
                    MenuItem.OnClick := nil;
                end;            for i:=0 to recordCount-1 do
                begin
                    sMenuCaption := TSysFunctionVO(recordList[i]).getFunctionName; //取子结点的名称
                    sMenuItem:= TMenuItem.Create(FrmMain);
                    sMenuItem.Name := TSysFunctionVO(recordList[i]).getFunctionCode;// DbKeyGenerator.getGuidString;
                    sMenuItem.Caption := sMenuCaption;
                    sMenuItem.Tag := 1;
                    If(MenuItem = nil) then
                    begin
                        MainMenu.Items.Add(sMenuItem);
                    end else begin
                        sMenuItem.ImageIndex := TSysFunctionVO(recordList[i]).getImgIndex16; //设置子结点的图标
                        sMenuItem.OnClick := FrmMain.FunctionMenuClick;//设置OnClick事件
                        MenuItem.Add(sMenuItem);
                    end;
                    //继续查找新添加上的子结点的再下一级的子结点 此处递归调用
                    setUserFunctionMenuFromCache(MainMenu, sMenuItem);
                end;
            end;
            recordList.Free;
            recordList := nil;
            result := recordCount;
        Except
            on e:Exception do
            Begin
                TLogManager.saveToLog('function setUserMenuFunctionFromCache(MainMenu:TMainMenu; MenuItem: TMenuItem): Integer;',
                                        TLogManager.LOG_LEVEL_DEBUG,
                                        '从缓存中读取用户权限生成动态菜单时发生异常',
                                        e.Message);            raise Exception.Create(e.Message);
            End;
        End;
    end;
    //动态菜单OnClick调用的过程
    procedure TFrmMain.FunctionMenuClick(Sender: Tobject);
    begin
        self.caption := '你好';
    end;//在主窗体里调用动态生成菜单的方法
    setUserFunctionMenuFromCache(self.MainMenu, nil);
      

  11.   

    sMenuItem.OnClick := FrmMain.MyClick;  这样再试试
      

  12.   

    自己调用自己?? setUserFunctionMenuFromCache(MainMenu, sMenuItem); 拆开来试试
      

  13.   

    把self都换成FrmMain,然后
    FrmMain.Repaint试试
    如果确定了,FrmMain.Caption 已经是 '你好' 
    Repaint一下应该就可以的
      

  14.   

    又有新发现代码如下: //动态生成菜单 
    sMenuItem:= TMenuItem.Create(FrmMain); 
    sMenuItem.Name := 'MyMenu'; 
    sMenuItem.Caption := '动态菜单'; 
    sMenuItem.Tag := 1; 
    sMenuItem.OnClick := MyClick; //设置菜单的OnClick事件 
    self.MainMenu.Items.Add(sMenuItem);  <-- 这里如果写成 FrmMain.MainMenu.Items.Add(sMenuItem); 就不会出现动态创建的菜单//MyClick过程 
    procedure TFrmMain.MyClick(Sender: Tobject); 
    begin 
        self.Caption := '你好'; 
    end; 
      

  15.   

    看来我在另一个unit里调用主窗体必需写成 FrmMain.  所以不好使。
      

  16.   

    有时候相互调用的时候Self来Self去,稍不注意都不知道Self到底是哪个了,容易乱,还是写窗体名比较好看,虽然有人不建议这么写!
      

  17.   

    to:jiangfx2001 通过这个问题,我发现 写self 和 写self所代表的对象的名是不同的。比如:下面的这段代码是写在主窗体FrmMain里的。//动态生成菜单 
    sMenuItem:= TMenuItem.Create(FrmMain); 
    sMenuItem.Name := 'MyMenu'; 
    sMenuItem.Caption := '动态菜单'; 
    sMenuItem.Tag := 1; 
    self.MainMenu.Items.Add(sMenuItem);  <-- 这里如果写成 FrmMain.MainMenu.Items.Add(sMenuItem); 就不会出现动态创建的菜单 这里的self应该就是FrmMain,但是写 self.MainMenu.Items.Add(sMenuItem); 就可以显示出来动态创建的菜单,写成
    FrmMain.MainMenu.Items.Add(sMenuItem); 就显示不出来。到底有什么不同呢?
      

  18.   

    我又试了一下,我这里self.MainMenu.Items.Add(sMenuItem);FrmMain.MainMenu.Items.Add(sMenuItem); MainMenu.Items.Add(sMenuItem); 三者的结果是一样的。。
      

  19.   


    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, Menus, StdCtrls;type
      TForm1 = class(TForm)
        MainMenu1: TMainMenu;
        Button1: TButton;
        procedure ss(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementationuses unit2;{$R *.dfm}procedure TForm1.ss(Sender: TObject);
    begin
      showmessage('³É¹¦');
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      AddNewSM(self,MainMenu1,'adsf','fds',0);
    end;end.unit Unit2;interfaceuses Windows, Forms, Menus, unit1;  procedure AddNewSM(F: TForm1; P: TMainMenu; Mname: ShortString;MStr: ShortString; Mindex: SmallInt);implementation  procedure AddNewSM(F: TForm1; P: TMainMenu; Mname: ShortString;MStr: ShortString; Mindex: SmallInt);
      var
        NMI: TMenuItem;
      begin
        NMI:= TMenuItem.Create(nil);
        NMI.Name:= Mname;
        NMI.Caption:= MStr;
        NMI.OnClick:= F.ss;
        P.Items.Add(NMI);
      end;end.
      

  20.   


    我的试验:
    procedure TFrmMain.test;
    var
        sMenuItem, sMenuItem2: TMenuItem;
    begin
        //动态生成菜单
        sMenuItem:= TMenuItem.Create(FrmMain);
        sMenuItem.Name := 'MyMenu';
        sMenuItem.Caption := '动态菜单';
        sMenuItem.Tag := 1;
        frmMain.MainMenuMain.Items.Add(sMenuItem);  //1
        self.MainMenuMain.Items.Add(sMenuItem);     //2
        frmMain.MainMenuMain.Items.Add(sMenuItem);  //3
    end;procedure TFrmMain.FormShow(Sender: TObject);
    begin
        test;
    end;
    在我这里,注释1 不显示, 注释2和3都正常显示。到底怎么回事呢?
      

  21.   

    注释3 处是MainMenuMain.Items.Add(sMenuItem);  
      

  22.   

    是我的不对,我有罪。
    是我的不好,我检讨。我这句 Application.CreateForm(TFrmMain, FrmMain); 竟然写了二次。晕了。不好意思。
      

  23.   

    兄弟,我再问你个问题。你那个表情是怎么发上去的?[tx][/tx]