http://topic.csdn.net/u/20081125/15/9b815583-0d5d-4512-ba20-107946b1fb23.html
菜单是应用程序中常见的用户界面之一,Delphi具有功能强大的菜单设计器,可以很快地实现标准的菜单。但有时候,应用程序需要实现特定类型的菜单,我
们常用的如金山毒霸的弹出式菜单就是一例,可以在菜单项里显示自己定义的图片,自己设置的文字以及自设置的菜单项大小。这种菜单称为自绘制菜单
(Owner-draw MenuItem)当然,功能不止于此,我们还可以实现更好的菜单。下面就一起来做一个显示大图片和大文字的菜单吧!
一、程序思路
Delphi在绘制每个菜单时,采用一个比较独特的方法。首先,Delphi会通过菜单的OwnerDraw属性来判定在菜单中是否允许自绘制菜单。若
OwnerDraw属性为真(TRUE),则Delphi首先会触发每个菜单项的OnMeasureItem事件来获取自绘制菜单项的大小
(Width,Height);然后触发OnDrawItem事件,允许用户在这里绘制自己的菜单。
二、实现菜单
第一步:创建一个新的项目,并添加相应的组件
启动Delphi。新建一个应用。此时出现一个窗体,将其Name属性改为frmSample。添加一个弹出式菜单到窗体frmSample,并将此菜单Name属性设置为mnuOwnerDraw。
设置窗体frmSample的PopupMenu属性为mnuOwnerDraw。这时运行程序,你会发现除了弹出式菜单仍然显示为空的菜单。继续往窗体
上添加一个TactionList对象,双击以设计这一ActionList对象,往其中增加一个Action对象,并设置其Name属性
为:actSample。往窗体上放置一个Label对象,其Name属性为:Label1,调整Label的字体大小,以便在利用Label显示数据
时,可以清楚地观察到。
现在,往程序的变量声明部分(VAR)添加要用到的声明:
ePic:TPicture; //用于装载程序要用到的图像
miSample:TMenuItem; //菜单项的声明,用于动态生成菜单项
I:integer; //当多次右击键时,记录右单击次数,从而生成不同的菜单项。
首先在程序的初始化部分初始化击键次数为0:
initialization
i:=0;
第二步:实现OnMeasureItem和OnDrawItem
往窗体frmSample的实现(Implementation)部分添加如下过程声明。
AMeasureItem (Sender: TObject; ACanvas: TCanvas; var Width, Height: Integer);
ADrawItem (Sender: TObject; ACanvas: TCanvas; ARect: TRect;Selected: Boolean);
往往手工输入比较麻烦,比较现实的做法是利用菜单设计器添加一个菜单项,设置其Name属性为A;然后选择OnMeasureItem和 OnDrawItem事件,双击即可,Delphi会为你自动输入如上代码。
往AMeasureItem中添加如下代码:
Begin
Width: =128; //设置菜单项的宽度;
Height: =64; //设置菜单项的高度;
End;
往ADrawItem中添加如下代码:
Begin
If I=1 then
begin
ePic:=TPicture.Create;//创建一个用于装载图片的Tpicture对象
ePic.LoadFromFile('a.bmp');//从项目所在目录装载图片
acanvas.Draw(arect.Left,arect.Top,ePic.Graphic); //将图片在菜单项中绘制出来
acanvas.Font.Size:=24;//设置菜单项的字体大小
acanvas.Font.Color:=clPurple; //设置菜单项字体颜色
acanvas.TextOut(arect.Left+60,arect.Top+20,'A' ); //在菜单项中输出文字A
end;
if i=2 then
begin
ePic:=TPicture.Create; //创建一个用于装载图片的Tpicture对象
ePic.LoadFromFile('b.bmp'); //从项目所在目录装载图片
acanvas.Draw(arect.Left,arect.Top,ePic.Graphic); //将图片在菜单项中绘制出来
acanvas.Font.Size:=24; //设置菜单项的字体大小
acanvas.Font.Color:=clblue; //设置菜单项字体颜色
acanvas.TextOut(arect.Left+60,arect.Top+20,'B'); //在菜单项中输出文字A
end;
if i=3 then
begin
ePic:=TPicture.Create;
ePic.LoadFromFile('c.bmp');
acanvas.Draw(arect.Left,arect.Top,ePic.Graphic);
acanvas.Font.Size:=24;
acanvas.Font.Color:=clred;
acanvas.TextOut(arect.Left+60,arect.Top+20,'C');
end;
End;
下面我们实现菜单项的在被单击时的行为,即实现actSample对象的OnExcute事件。如下所示:
actSampleExecute(Sender: TObject);
begin
label1.Caption:=inttostr(i);
end;
第三步:将菜单项动态添加到菜单中
I:=I+1;//计算程序中的击键次数
miSample:=TMenuItem.Create(form1); //动态创建菜单项
miSample.OnClick :=actSample.OnExecute; //为菜单项添加动作
miSample.OnDrawItem := ADrawItem; //为菜单项设置显示方式
miSample.OnMeasureItem := aMeasureItem; //为菜单项设置大小
mnuOwnerDraw.Items.Insert(0,miSample); //将菜单项添加到菜单中
三、程序效果
现在可以应用程序了,你会发现,只要你在窗体上单击右键,窗体会有一个弹出式菜单显示出来。而且每一个菜单项都随着右键单击次数的不同而不同,当次数大于
3时,菜单显示为一系列的空菜单项。但是,不论何时你单击任何一个菜单项,Label的都会显示你当前的右键在窗体上单击的次数值。
四、程序加强
如果我们在程序中为我们所动态创建的每一个菜单项都实现不同的OnMeasureItem和OnDrawItem事件的话,那么,每一个菜单项都有自己的
大小处理与显示处理,那我们就可以实现一些更好的功能。例如:可以实现大小不同的菜单项,第一个菜单项可以比较小,以后的菜单项可以比较大。同样还可以在
一些菜单中实现更好的功能,如:每个菜单显示自己图标和特定字体的文字。
但是,利用这种方法制作自定义菜单的功能还是受到了一定的限制。我们只能对OnAdvancedDrawItem、OnClick、
OnDrawItem、OnMeasureItem等有限几个事件作出反应并对菜单项进行定制,我们没有办法对鼠标事件作出反应。利用鼠标事件,当鼠标滑
过菜单项时,我们可以实现诸如加亮、渐变或其他的菜单项显示技术。显然这是十分有意义的。
要实现上述技术,我们需要从TcustomMenuItem中继承并定义一个新类并重新声明OnMouseMove事件,并给出实现诸如加亮或渐变等技术的代码即可。
关于动态创建PopupMenu的问题
http://topic.csdn.net/t/20040825/09/3306672.html
动态创建菜单
var
mmiTemp:TMenuItem;
begin
mmiTemp:=TMenuItem.Create();
mmiTemp.Caption:= '标题 ';//
mmiTemp.OnClick:= actLoadExecute;//设定action
PopupMenu2.Add(mmiTemp);//加入到上层的菜单
end;