菜单是应用程序中常见的用户界面之一
Delphi具有功能强大的菜单设计器
可以很快地实现标准的菜单
但有时候
应用程序需要实现特定类型的菜单
我们常用的如金山毒霸的弹出式菜单就是一例
可以在菜单项里显示自己定义的图片
自己设置的文字以及自设置的菜单项大小
这种菜单称为自绘制菜单(Owner
draw MenuItem)当然
功能不止于此
我们还可以实现更好的菜单
下面就一起来做一个显示大图片和大文字的菜单吧!
一程序思路
Delphi在绘制每个菜单时采用一个比较独特的方法首先Delphi会通过菜单的OwnerDraw属性来判定在菜单中是否允许自绘制菜单若OwnerDraw属性为真(TRUE)则Delphi首先会触发每个菜单项的OnMeasureItem事件来获取自绘制菜单项的大小(WidthHeight)然后触发OnDrawItem事件允许用户在这里绘制自己的菜单
二实现菜单
第一步创建一个新的项目并添加相应的组件
启动Delphi新建一个应用此时出现一个窗体将其Name属性改为frmSample添加一个弹出式菜单到窗体frmSample并将此菜单Name属性设置为mnuOwnerDraw
设置窗体frmSample的PopupMenu属性为mnuOwnerDraw这时运行程序你会发现除了弹出式菜单仍然显示为空的菜单继续往窗体上添加一个TactionList对象双击以设计这一ActionList对象往其中增加一个Action对象并设置其Name属性为actSample往窗体上放置一个Label对象其Name属性为Label调整Label的字体大小以便在利用Label显示数据时可以清楚地观察到
现在往程序的变量声明部分(VAR)添加要用到的声明
ePic:TPicture;//用于装载程序要用到的图像
miSample:TMenuItem; //菜单项的声明用于动态生成菜单项
I:integer;//当多次右击键时记录右单击次数从而生成不同的菜单项
首先在程序的初始化部分初始化击键次数为
initialization
i:=;
第二步实现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: =; //设置菜单项的宽度
Height: =; //设置菜单项的高度
End;
往ADrawItem中添加如下代码
Begin
If I= then
begin
ePic:=TPictureCreate;//创建一个用于装载图片的Tpicture对象
ePicLoadFromFile(abmp);//从项目所在目录装载图片
acanvasDraw(arectLeftarectTopePicGraphic);//将图片在菜单项中绘制出来
acanvasFontSize:=;//设置菜单项的字体大小
acanvasFontColor:=clPurple; //设置菜单项字体颜色
acanvasTextOut(arectLeft+arectTop+A ); //在菜单项中输出文字A
end;
if i= then
begin
ePic:=TPictureCreate;//创建一个用于装载图片的Tpicture对象
ePicLoadFromFile(bbmp);//从项目所在目录装载图片
acanvasDraw(arectLeftarectTopePicGraphic);//将图片在菜单项中绘制出来
acanvasFontSize:=;//设置菜单项的字体大小
acanvasFontColor:=clblue;//设置菜单项字体颜色
acanvasTextOut(arectLeft+arectTop+B);//在菜单项中输出文字A
end;
if i= then
begin
ePic:=TPictureCreate;
ePicLoadFromFile(cbmp);
acanvasDraw(arectLeftarectTopePicGraphic);
acanvasFontSize:=;
acanvasFontColor:=clred;
acanvasTextOut(arectLeft+arectTop+C);
end;
End;
下面我们实现菜单项的在被单击时的行为即实现actSample对象的OnExcute事件如下所示
actSampleExecute(Sender: TObject);
begin
labelCaption:=inttostr(i);
end;
第三步将菜单项动态添加到菜单中
I:=I+;//计算程序中的击键次数
miSample:=TMenuItemCreate(form);//动态创建菜单项
miSampleOnClick :=actSampleOnExecute; //为菜单项添加动作
miSampleOnDrawItem := ADrawItem; //为菜单项设置显示方式
miSampleOnMeasureItem := aMeasureItem; //为菜单项设置大小
mnuOwnerDrawItemsInsert(miSample);//将菜单项添加到菜单中
三程序效果
现在可以应用程序了你会发现只要你在窗体上单击右键窗体会有一个弹出式菜单显示出来而且每一个菜单项都随着右键单击次数的不同而不同当次数大于时菜单显示为一系列的空菜单项但是不论何时你单击任何一个菜单项Label的都会显示你当前的右键在窗体上单击的次数值
四程序加强
如果我们在程序中为我们所动态创建的每一个菜单项都实现不同的OnMeasureItem和OnDrawItem事件的话那么每一个菜单项都有自己的大小处理与显示处理那我们就可以实现一些更好的功能例如可以实现大小不同的菜单项第一个菜单项可以比较小以后的菜单项可以比较大同样还可以在一些菜单中实现更好的功能如每个菜单显示自己图标和特定字体的文字
但是利用这种方法制作自定义菜单的功能还是受到了一定的限制我们只能对OnAdvancedDrawItemOnClickOnDrawItemOnMeasureItem等有限几个事件作出反应并对菜单项进行定制我们没有办法对鼠标事件作出反应利用鼠标事件当鼠标滑过菜单项时我们可以实现诸如加亮渐变或其他的菜单项显示技术显然这是十分有意义的
要实现上述技术我们需要从TcustomMenuItem中继承并定义一个新类并重新声明OnMouseMove事件并给出实现诸如加亮或渐变等技术的代码即可