一、创建菜单并添加项目
  在设计程序时,有时需要动态创建菜单, 通常使用以下的语句:

PopupMenu1 := TPopupMenu.Create(Self);
  Item := TMenuItem.Create(PopupMenu1);
  Item.Caption := '菜单一';
  Item.OnClick := MenuItem1Click;
  PopupMenu1.Items.Add(Item);
  Item := TMenuItem.Create(PopupMenu1);
  Item.Caption := '菜单二';
  Item.OnClick := MenuItem2Click;
  PopupMenu1.Items.Add(Item);
  Item := TMenuItem.Create(PopupMenu1);
  Item.Caption := '菜单三';
  Item.OnClick := MenuItem3Click;
  PopupMenu1.Items.Add(Item);

Item := TMenuItem.Create(PopupMenu1);
  Item.Caption := '-';        // 增加一个分割条
  PopupMenu1.Items.Add(Item);
  Item := TMenuItem.Create(PopupMenu1);
  Item.Caption := '菜单四';
  Item.OnClick := MenuItem4Click;
  PopupMenu1.Items.Add(Item);

  还可以使用一种更快捷的方法达到同样的目的, 那就是用NewLine和NewItem, 方法如下:

PopupMenu1 := TPopupMenu.Create(Self);
  with PopUpMenu1.Items do
  begin
    Add(NewItem('菜单一',0,False,True,MenuItem1Click,0,'MenuItem1'));
    Add(NewItem('菜单二',0,False,True,MenuItem2Click,0,'MenuItem2'));
    Add(NewItem('菜单三',0,False,True,MenuItem3Click,0,'MenuItem3'));
    Add(NewLine);             // 增加一个分割条
    Add(NewItem('菜单四',0,False,True,MenuItem4Click,0,'MenuItem4'));
  end;

二、插入菜单项
  上述方法是在创建完菜单后,紧接着为其添加菜单项目。在已经创建了菜单的情况下,可以在菜单的指定层、指定位置插入菜单。方法如下:

var M1:TMenuItem;
    n:Integer;
begin
  M1:=TMenuItem.Create(nil);
  M1.Caption:='菜单名称';
  M1.OnClick:=myMenusClick;     //赋予点击事件
  MainMenu1.Items.Insert(n,M1);  //插入
end;

这是在主菜单的根部插入菜单项,如果要在子菜单中插入,其定位方法为:
  MainMenu1.Items[n1].Insert(n2,M1);  //插入子菜单

如果要为子菜单再插入子项目,则可按下述方法定位:
  MainMenu1.Items[n1].Items[n2].Insert(n3,M1);  //为子菜单插入子项

添加子菜单的定位方法与此相同,只是缺省了最后一个位置参数,因为添加就是追加到尾部,不需要提供位置信息。n的取置最小为0,最大不能超过当前层级菜单的总数。获取菜单项目数量的方法为:

var n1,n2,n3:Integer;
begin
  n1:=MainMenu1.Items.Count;              //根级菜单数
  n2:=MainMenu1.Items[0].Count;           //子级菜单数
  n3:=MainMenu1.Items[0].Items[0].Count;  //孙级菜单数
end;

三、删除菜单项
  删除菜单的操作,是插入菜单项的逆向操作,语法相似,定位方位完全一样。只需将插入菜单语句中的Insert改为Delete即可。如需删除主菜单索引号为1(第二个)的子菜单中索引号为2(第三个)的子菜单中的第1(索引号为0)个菜单项,方法如下:

MainMenu1.Items[1].Items[2].Delete(0);

四、为菜单项指定快捷方式
  Delphi中有一个ShortCut函数,返回值为TShortCut,可以将它赋值给菜单项的ShortCut属性,从而达到设置快捷键的目的。方法如下:

var sState:TShiftState;
begin
  Include(sState, ssCtrl);                  //将Ctrl键加入快捷键组合
  Menu_Left.ShortCut:=ShortCut(37,sState);  //Ctrl+ ←
  Menu_Up.ShortCut:=ShortCut(38,sState);    //Ctrl+ ↑
  Menu_Right.ShortCut:=ShortCut(39,sState); //Ctrl+ →
  Menu_Down.ShortCut:=ShortCut(40,sState);  //Ctrl+ ↓
end;

五、为菜单赋予点击事件
  生成菜单的目的,是为了让它响应相应的点击事件,从而快速地执行某些特定的程序功能。无没事件响应的菜单,其存在是毫无意义的。因此,必须为其赋予相应的点击事件。
  菜单的点击事件,可以在程序中一一为其定义,如:

procedure TForm1.MenuItem1Click(Sender: TObject); //菜单1的点击事件
begin
  //菜单点击事件的响应程序段
end;

procedure TForm1.MenuItem2Click(Sender: TObject); //菜单2的点击事件
begin
  //菜单点击事件的响应程序段
end;

procedure TForm1.MenuItem3Click(Sender: TObject); //菜单3的点击事件
begin
  //菜单点击事件的响应程序段
end;

以此类推。当然也可以共享一个点击事件,但根据触发菜单各自的属性,做出不同的判断,去执行不同的动作。下面的一段代码,可以赋予所有菜单的点击事件,其对菜单的点击事件做出的响应是:显示一句话,并读取当前点击菜单项的名称(Caption属性):

private
    { Private declarations }
  public
    { Public declarations }
    procedure myMenusClick(Sender: TObject); //通用菜单点击事件

implementation

{$R *.dfm}

procedure TForm1.myMenusClick(Sender: TObject); //通用菜单点击事件
var menuCap:string;
begin
  with Sender as TMenuItem do
  begin                                                                       
    menuCap:=TMenuItem(Sender).Caption;
    Application.MessageBox(PChar('你好!'+#13#13'我是菜单“'+menuCap+'”。'
      +#13#13'点击我,有什么吩咐?'),'提醒',MB_Ok+MB_ICONInformation);
  end;     
end;

为菜单项赋予点击事件时,有一点需要注意:当菜单项有子菜单时,则该菜单就不应再有点击事件,因为此时该菜单项的点击事件并不是由点击触发的,而是当鼠标进入时就会触发,这样就会导致该菜单的子菜单无法激活的问题,失去了它们存在的意义。对此,可对通用的点击事件作如下修改:
procedure TForm1.myMenusClick(Sender: TObject); //通用菜单点击事件
var menuCap:string;
    n:Integer;
begin
  with Sender as TMenuItem do
  begin                                                                       
    menuCap:=TMenuItem(Sender).Caption;
    n:=TMenuItem(Sender).Count;     //取该菜单的子菜单数
    if n<1 then      //若无子菜单就赋予点击事件,否则忽略点击事件
    Application.MessageBox(PChar('你好!'+#13#13'我是菜单“'+menuCap+'”。'
      +#13#13'点击我,有什么吩咐?'),'提醒',MB_Ok+MB_ICONInformation);
  end;     
end;

六、注销菜单
  既然菜单可以动态生成,当然也就可以动态销毁它。方法如下:
  MainMenu1.Items.Clear;  //清除菜单的所有项目
  MainMenu1.Free;         //释放菜单
  用下述方法也可销毁菜单:
  MainMenu1.Destroy;
  但是,一般情况下不应直接调用该方法,应当调用Free方法。

七、将右键菜单加入到主菜单
  从主菜单激活的都是弹出菜单,在本质上与右键菜单是一样的。因此,右键菜单也可以作为主菜单的一个项目来进行调用。用如下方法可将右键菜单加入到主菜单中去:

procedure TForm1.btn_toMMClick(Sender: TObject);  //将右键菜单加入到主菜单
begin
  EnableMenuItem(PopupMenu1.Handle,0,MF_ByPosition);
  AppendMenu(MainMenu1.Handle,MF_Popup,PopupMenu1.Handle,'右键菜单');
  Windows.DrawMenuBar(self.Handle);
end;
  用下面的方法也可实现将右键菜单加入到主菜单,但在使用中发现退出时会报错,具体原因还未作进一步的研究。
procedure TForm1.btn_toMMClick(Sender: TObject);  //将右键菜单加入到主菜单
begin
  MainMenu1.Items.Insert(MainMenu1.Items.Count,PopupMenu1.Items);
  MainMenu1.Items[MainMenu1.Items.Count-1].Caption:='右键菜单';
  DrawMenuBar(Self.Handle);
end;

八、菜单的其他属性
  菜单及菜单的项目,不论是动态生成的,还是在设计期部署的,都可以在程序运行期进行改动。对于动态菜单,可以在生成菜单项的同时,对其相关属性、事件一并进行赋值,有两种方法,如下:

第一种方法,使用NewItem函数:

PopUpMenu1.Items.Add(NewItem('菜单一',0,False,True,myMenusClick,0,'MenuItem1'));

使用NewItem函数可以同时为菜单的Caption、ShortCut、HelpContext、Checked、Enabled、Name等六种属性和OnClick

事件赋值。NewItem函数在Menus.pas单元文件中定义如下:

function NewItem(const ACaption: string; AShortCut: TShortCut;
  AChecked, AEnabled: Boolean; AOnClick: TNotifyEvent; hCtx: THelpContext;
  const AName: string): TMenuItem;
begin
  Result := TMenuItem.Create(nil);
  with Result do
  begin
    Caption := ACaption;
    ShortCut := AShortCut;
    OnClick := AOnClick;
    HelpContext := hCtx;
    Checked := AChecked;
    Enabled := AEnabled;
    Name := AName;
  end;
end;

第二种方法,在生成菜单项后,分别为其相应的属性或事件赋值。这种方法比较灵活,可以只对其中某几个属性或事件赋值,也可以为其全部属性和事件赋值。方法如下:

var M1:TMenuItem;
    n:Integer;
    myShortCut:TShortCut;
begin
  M1:=TMenuItem.Create(nil);
  M1.Caption:='菜单名称';      //赋予菜单名称
  M1.AutoHotkeys:=maManual;   //关闭自动热键(人工)
  M1.OnClick:=myMenusClick;    //赋予点事件
  M1.ShortCut:=myShortCut;   //赋予快捷键 
  //为其他属性赋值
  //为其他事件赋值
  MainMenu1.Items.Insert(n,M1);  //插入
end;

Delphi编程中动态菜单要点归纳的更多相关文章

  1. 【转】资源文件在Delphi编程中的应用

    段东宁 计亚南 (郴州职业技术学院, 湖南 郴州  423000) 摘要: 资源文件是一种能有效地组织.管理和使用资源的文件形式,在软件开发中有着广泛的应用.本文详细介绍了在Delphi编程中资源文件 ...

  2. Delphi编程中使用回车键不换行处理方法!!

    我以前遇到过Delphi编程中使用回车键不换行的问题,一直没有找到正确处理方法,以至于每次都重新安装Delphi,今天在XE8中再次遇到这样问题,万幸找到了正确的解决方法: 可能使用过程中不小心按了i ...

  3. Delphi编程中Http协议应用

    Http协议的通信遵循一定的约定.例如,请求一个文件的时候先发送Get请求,然后服务器会返回请求的数据.如果需要进行断点传输,那么先发送'HEAD /'请求,其中返回的'Content-Length: ...

  4. 关于delphi XE7中的动态数组和并行编程(第一部分)

    本文引自:http://www.danieleteti.it/category/embarcadero/delphi-xe7-embarcadero/ 并行编程库是delphi XE7中引进的最受期待 ...

  5. 资源在windows编程中的应用----菜单

    资源在Windows编程中的应用 资源 加速键.位图.光标.对话框.菜单.字符串.工具条 1.菜单的创建 菜单由以下组成部分: (1)窗口主菜单条 (2)下拉式菜单框 (3)菜单项热键标识 (4)菜单 ...

  6. Ajax编程中,经常要能动态的改变界面元素的样式

    在Ajax编程中,经常要能动态的改变界面元素的样式,可以通过对象的style属性来改变,比如要改变背景色为红色,可以这样写:element.style.backgroundColor=”#ff0000 ...

  7. MFC 单文档中动态添加菜单项和响应菜单事件

    新建一个单文档程序 在查看菜单项中增加两个子菜单,分别为隐藏工具栏(ID_HIDE),新建菜单(ID_NEWMENU) 在Resource.h中增加一个ID_NEWMENU宏 #define ID_N ...

  8. delphi创建动态菜单

    1.动态生成菜单项 varFirstItem: TMenuItem;SecondItem: TMenuItem; begin FirstItem := TMenuItem.Create(Self); ...

  9. 用Delphi制作动态菜单 该文章《用Delphi制作动态菜单》

    ---恢复内容开始--- 1.首先,确定动态菜单的数据来源,即要确定动态菜单标题是来自Windows的系统注册表,还是来自一个数据库,或者是来自一个子目录,主要由程序的功能而定.这里假设主窗口名为Ma ...

随机推荐

  1. Qt读取文件时中文乱码问题

    在默认情况下,Qt 以 Unicode 格式处理文本字符,因此,字符本身是不会有问题的.之所以出现乱码,原因在于 Qt 不知道将 Unicode 字符以何种方式显示出来.        文本文件含有简 ...

  2. Winform 基础一 panel

    一 居上.居中.居下 二 添加子控件 三 适应不同分辨率 四 内容超出,显示滚动条 一 .居上.居中.居下 二.添加子页面 Form7 childFrm = new Form7(); childFrm ...

  3. AliOS-Things Visual studio code helloworld 入门

    配置环境的时候别忘了下载:GCC工具链:https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads AliOS Thing ...

  4. SkylineGlobe 从v6.1到v6.5 二次开发方面的变化参考

       2.1关于 TerraExplorer v6.5 API 除了一些新的功能,API v6.5不同于API v6.1的最大改进是其对象ID系统.虽然在以前版本的API中,有两个ID系统,一个用于对 ...

  5. 虚拟机vbox

    https://www.virtualbox.org/wiki/Linux_Downloads 一直在报内核出错的问题,我尝试了各种方法还是无果,猜测是版本的问题,这里推荐各位安装virtualbox ...

  6. C# 深浅复制 MemberwiseClone(转载)

    最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考MSDN:https://docs.microsoft.com/zh-cn/dotnet/api/syst ...

  7. Linux查看特定端口是否被占用并kill掉相关进程

    今天在搭建Zookeeper集群的时候,需要频繁启动zookeeper,但是启动的时候,有时会提示下列错误信息: zookeeper需要的地址已经被占用了,其实是因为上一次的zookeeper没有关闭 ...

  8. C#获取当前堆栈的各调用方法列表

    在使用.NET编写的代码在debug时很容易进行排查和定位问题,一旦项目上线并出现问题的话那么只能依靠系统日志来进行问题排查和定位,但当项目复杂时,即各种方法间相互调用将导致要获取具体的出错方法或调用 ...

  9. Kafka基础系列第1讲:Kafka的诞生背景及应用

    Kafka 是由 LinkedIn 开发的一个分布式的消息系统,使用 Scala 编写,它以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如 Cloudera.Apache Sto ...

  10. 用 Python 分析咪蒙1013篇文章,她凭什么会火?

    咪蒙 文学硕士,驾驭文字能力极强.并且是一个拥有一千多万粉丝,每篇文章阅读量都   100W+,头条发个软文都能赚 80 万,永远都能抓住粉丝G点的那个女人. 1月份因为某篇文章,在网络上被一大批网友 ...