4.5 创建动态菜单
用户可以在程序运行时动态地创建一个菜单,就像在 Word 中,每打开一个文档,就 会在【窗口】菜单下动态增加一个该文档的菜单项。
在介绍如何创建动态菜单之前,首先分析一下菜单类。
主菜单对应于 Delphi 中的 TMainMenu 类,主菜单项(常简称为菜单)对应于 Delphi 中 的 TMenuItem 类。通常主菜单栏中的各菜单构成一个列表,存储在主菜单(TMainMenu)的 Items 属性中。而每个菜单中的菜单命令数则存储在该菜单(TMenuItem)的 Count 属性中。 这样,就可以利用 TMainMenu 类的 Items 属性,通过 Insert 方法来实现往主菜单栏中 添加一个菜单;而从主菜单栏中删除一个菜单,同样是利用 Items 属性,不过是利用 Remove
方法。
在菜单中添加或删除一个菜单命令,则需利用 TMenuItem 类的 Count 属性,同样也是 利用 Insert 或 Remove 方法。
动态添加菜单时,必须为每个菜单命令指定 OnClick 事件的响应过程名称。在此过程 中,可以为多个菜单命令的 OnClick 事件指定同一个响应过程,而通过 Sender 参数确定具 体执行哪一项命令项。
【例 4.3】 继续前面的例子,在程序运行后,动态地在【选项】菜单后添加一个【内容】 菜单。
首先添加两个菜单项:【增加菜单】(name 属性为 insmenu)和【删除菜单】(name 属性 为 delmenu),用于动态地增加和删除菜单。在【增加菜单】的单击事件中创建【内容】菜 单,并指定菜单命令的 OnClick 事件的响应过程,其代码如下:
procedure TForm1.InsmenuClick(Sender: TObject);
var Content,Item:TMenuItem; Position,i:Integer;
begin
Content:=TMenuItem.Create(self); //创建菜单
Content.Caption:='内容(&C)';
Content.AutoHotkeys:=maManual; //禁止系统自动产生菜单命令
//快捷键
Content.OnClick:=ContentClick; //决定菜单 OnClick 事件的响
//应过程
Position:=MainMenu1.Items.IndexOf(Option); //确定菜单插入的位置
MainMenu1.Items.Insert(Position 1,Content); //插入菜单【内容(C)】
Item:=TMenuItem.Create(self); //创建菜单命令
Item.Caption:='文档 1';
Item.GroupIndex:=1; //决定菜单命令为单选
Item.RadioItem:=true; Item.OnClick:=ContentItemClick;
Content.Insert(0,Item); //插入菜单命令【文档 1】
Item:=TMenuItem.Create(self); //创建菜单命令
Item.Caption:='文档 2';
Item.GroupIndex:=1; //决定菜单命令为单选
Item.RadioItem:=true; Item.OnClick:=Button3Click;
Content.Insert(1,Item); //插入菜单命令【文档 2】
Insmenu.Enabled:=false;
Delmenu.Enabled:=true;
end;
在【删除菜单】的单击事件中删除【内容】菜单,并指定菜单命令的 OnClick 事件的 响应过程,其代码如下:
procedure TForm1.DelmenuClick(Sender: TObject);
var
Position:Integer;
begin
Position:=MainMenu1.Items.IndexOf(Option); //确定删除菜单的位置
MainMenu1.Items.Delete(Position 1);
Insmenu.Enabled:=true;
Delmenu.Enabled:=false;
end;
接下来,手工编写【内容】菜单的 OnClick 事件的响应和【内容】菜单下各菜单命令 的 OnClick 事件的响应。在上面的代码中,已经给【内容】菜单的 OnClick 事件指定了 ContentClick 响应过程,给【内容】菜单下各菜单命令的 OnClick 事件指定了 ContentItemClick 响应过程。因此,先在 Form1 的类定义中添加这两个响应过程的说明。
type
TForm1 = class(TForm)
…
procedure FormCreate(Sender: TObject);
procedure ContentClick(Sender: TObject); //手工添加
procedure ContentItemClick(Sender: TObject); //手工添加
private
{ Private declarations }
public
{ Public declarations }
end;
接着编写 ContentClick 响应过程的代码,该过程的作用是扫描【内容】菜单中选定了 哪一项命令,再让该命令显示单选标记。其代码如下:
procedure TForm1.ContentClick(Sender: TObject);
begin
if memo1.Lines[0]='睡觉'
then
with Sender as TMenuItem do items[0].Checked:=true
else
with Sender as TMenuItem do items[1].Checked:=true;
end;
接着编写 ContentItemClick 响应过程的代码,该过程的作用是扫描对【内容】菜单中 选定命令作出执行反应。其代码如下:
procedure TForm1.ContentItemClick(Sender: TObject);
begin
Memo1.Lines.Text:='睡觉' chr(13) chr(13) //chr(13)为回车符
'大地公公睡觉,' chr(13) '静悄悄。' chr(13)
'月亮婆婆睡觉,' chr(13) '眯眯笑。' chr(13)
'老爷爷睡觉,' chr(13) '胡子翘。' chr(13)
'小娃娃睡觉,' chr(13) '呼噜呼噜,' chr(13) '像只大花猫。';
end;
将单元文件另存为“Unit4_3.pas”,将项目文件另存为“Project4_3.dpr”。 这样,就可以编译并运行程序了。运行时,单击【选项】菜单中的【增加菜单】命令,
可动态增加【内容】菜单,并且可单击【内容】菜单中的【文档 1】和【文档 2】,执行相
应命令,单击【选项】菜单中的【删除菜单】命令,则可动态删除【内容】菜单。