动态生成菜单后,怎样把单击事件赋给每一个子菜单。(100分)

Y

yibb

Unregistered / Unconfirmed
GUEST, unregistred user!
已写好一个动态生成菜单的程序。
现在单击某一子菜单,要使其执行某一段代码,怎么实现啊?
比如我要让其中一个子菜单显示一个FORM。。。。
 
我有一个程序,怎给你?
 
我说得具体一点。
现在每个FORM名都已经存在于数据库中,子菜单名和FORM名是一样的。怎样让单击某一菜单就
显示同名的FORM呢
 
创建之后menu1.onclick= 你写的那个func or proc
 
procedure TMainForm.AddWindowsMenu(MenuCap: string; bEnabled: boolean);
//动态生成菜单
var
NewItem : TMenuItem;
begin
NewItem := TMenuItem.Create(Self);
NewItem.Caption := MenuCap;
NewItem.Enabled := bEnabled;
MainForm.FMenu.Add(NewItem);
NewItem.OnClick := AddMenuClick;
end;

procedure TMainForm.AddMenuClick(Sender: TObject);
//动态菜单点击事件
begin
with Sender as TMenuItem do
begin
ShowMessage(Caption);
end;
end;
 
同意WithDraw,
注意,你写的那个Func Or Proc 要是TForm的成员
 
只要是TNotifyEvent类型的变量都行,使用前要赋值如:
NewItem.OnClick := AddMenuClick;

 
用统一的过程来处理,点了哪个菜单项是可以识别的!


Delphi中动态定制菜单
Delphi的标准构件组中提供了Menu标准菜单和PopupMenu弹出式菜单两种组件,为通用的Windows程序编写提供了很大方便。这两种构件,既可以在设计过程中根据需要填写各个菜单项,定制各菜单项的响应事件,也可以在程序运行过程当中,根据使用者的选择,动态确定菜单项的内容与响应事件,即动态定制菜单。前一种方法较为简单,被广大程序员广泛采用;后一种方法较为复杂,但适用性特别好,可移植性强,在实际编程当中,一些特殊的要求下,是解决问题的唯一方法。笔者近期开发山东省教委《多媒体课堂教学系统》时就遇到了这种问题:使用Mediaplay多媒体控制构件播放声音文件、MIDI文件及视频文件时,要求根据用户在对话框中不同的选择,相应改变弹出式菜单的内容。

笔者以PopupMenu弹出式菜单为例,探讨Delphi中菜单的动态定制,下文的程序段都在Delphi3.0环境下调试成功。

原理:
PopupMenu弹出式菜单的各菜单项实际上是一个个TMenuItem类的对象,不同对象的Caption属性就是菜单在屏幕上显示的内容。改变这些Caption属性的内容即可达到动态定制菜单项的目的。弹出时菜单项数目的增减,可以通过TPopupMenu.items.add(TMenuItem)和TPopupMenu.items.delete(Word)两种方法来实现,然后再通过对TmenuItem.OnClick事件的重定向,实现菜单选择的事件响应。

具体实现步骤:
为叙述方便,把弹出式菜单定义给Form1.用‘1?2?3?4’表示定制的菜单项的内容,以按钮Button1实现菜单项变化的激活。这并不影响要说明的问题。1、在Form1上放置PopuMenu1(TPopupMenu)与Button1(Tbutton),设置各种属性如下:

Form1
PopupMenu:popupMenu1
Button1
  Caption:菜单1234

2、为Button1赋以下事件响应:
procedure Tform1.Button1Click(Sender:Tobject);
Var
Menuitem:array[1..4]of Tmenuitem;
I:integer;
begin
While(popupmenu1.items.count > 0)then
popupmenu1.items.delete(0);

for I:=1 to 4 do
begin
Menuitem=TmenuItem.Create(Self);
//---动态创建TMenuItem
MenuItem.Caption=inttostr(I);
//---设置MenuItem的Caption属性
MenuItem.OnClick:=ShowIt;
//----定义menuItem的OnClick事件的处理过程
PopupMenu1.Items.Add(MenuItem);
//----增加到PopMenu中
end;
end;

其中,ShowIt是程序中自制的Procedure。

Procedure Tform1.ShowIt(Sender:Tobject);
begin
With Sender as TmenuItem do
begin
ShowMessage(Caption);
end;
end;

当然,不要忘记在程序中先声明此过程。

说明:
1、删除弹出式菜单PopupMenu1原先的菜单项时,

2、popupmenu1.items.add的参数为TmenuItem类,因此,先开辟一个TmenuItem类的数组,再将此数组的各个元素作为参数传递给Add方法。

3、此程序并没有完全成功,其中隐含着重大的错误:MenuItem数组开辟以后并没有清除,在大型程序设计中,这将逐步耗费掉可用内存,因此应当在合适的时候,及时用Free方法清除。
 
源程序请发到我的信箱:guzhijun21@sohu.com

下面是我要赋给每个菜单OnClick事件的过程
procedure TMainFrm.MyMenuOnClick(Sender: TObject);
var
AComponent: TComponent;
str: string;
i : integer;
begin
with Sender as TMenuItem do
begin
str := Name;
AComponent := application.FindComponent(str);
if Assigned(AComponent) then
TForm(AComponent).Show; //显示与当前菜单名相同的Form
end;
end;

在普通环境下运行是没有问题的,现在我把它用到ActiveForm中就出现了问题。
原因是AComponent的值是nil,于是就显示不了form了,请高手指教。
 
如何执行过程始终是个问题啊,怎么办?

yibb 的方法是打开同名的表单,如果我要执行一个同名的过程怎么办?或是说在items的
tag中来区分,我要调用一个过程,过程名是string+inttostr(tag) 怎么办?


 
对了,还有一个问题就是这样子每次都创建了很多的菜单项,可创建后并不能用Free的方法来把它释放掉,这样内存会不会泄露啊?
如果要释放,在什么时机释放?
 
Mastering delphi6上有现成的例子
 
若要做到真正灵活的动态功能,你需要用
元类!
什么是元类,就是描术类的类结构,它相当于C#中的反射
对于Delphi的元类我不太清楚使用细节,不过,我相信肯定是有的
 
把菜单和TACTION一起使用,动态地把相同CAPTION的TACTION赋值给菜单项;
 
顶部