动态添加DevExpress 套件中 dxBar的菜单项目

Written by flexitime

PS: 有鉴于几位热心网友的意见,所以还是决定写一下一些技术相关的BLOG,并希望能有网友不吝赐教 

DevExpress是一个十分有名的Delphi控件套装,这个套件很多时候都是带有原码的,而我这篇文章正如题目所述的问题,是研究在dxBar中动态添加菜单。其实要完成这件事情并不困难,只是几行代码就说明问题了,但为什么要写这篇文章呢,主要的目的在于说明如何在没有其它资料可查的情况下,通过查源代码找到问题的解决方法。

首先,要使用TdxBar,我们要先在Form上添加一个TdxBarManager的控件,双击这个控件会弹出一个对话框,在ToolBar这一页上点击New..,再输入这个这个Bar的名字(例如 dxbMainMenu),这样就可以生成一个TdxBar了,如果要把这个TdxBar设置成为主菜单的话,那么只需要设置一下IsMainMenu属性为true即可。如果要手工在这个TdxBar实例dxbMainMenu上添加一些菜单项的话,那么可以通过在dxbMainmenu的右键菜单中选择对应的Add SubItem, Add Button等选项去完成。这里不再逐一细表了。
现在关键的问题在于如何在这个TdxBar中通过代码动态添加这些菜单项。
按照一般的思路,我们会有以下几种方案去考虑这个问题
第一.在dxBar中寻找有没有对应的方法,这些方法的名字可能是Add,Insert等等,但十分可惜的事,dxBar中并没有提供这些方法。
第二.我们看一下刚才手工生成的那些对像如 TdxBarSubItem有没有Parent或dxBar的对像,因为有可能会这样的方式来产生相应的菜单:
Bar := TdxBar.Create(nil);
Bar.dxBar := dxbmainMenu; 或 Bar.Parent := dxbmainMenu;
等等,但仍然是找不到合适的对像。
既然,以上常规的方式都找不到正确的方法,那么我们换一个角度去考虑,刚才dxBar其实是由dxBarManager生成出来的。因此,有解决的方法可能会通过dxBarManager才能完成。我们可以在dxBarManager找到一些与Add相关的方法
AddButton
AddSubitem
AddItem
AddToolBar
其中AddToolBar肯定不是我们想要的东西,那么我们通过DevExpress提供的源码(dxBar.pas)查一下这几个方法的实现:
 
function TdxBarManager.AddButton: TdxBarButton;
begin
 Result := TdxBarButton(AddItem(TdxBarButton));
end;
 
function TdxBarManager.AddItem(AClass: TdxBarItemClass): TdxBarItem;
var
 ACategoryIndex: Integer;
begin
 Result := AClass.Create(Self);
 ACategoryIndex := Categories.IndexOf(dxSBAR_DEFAULTCATEGORYNAME);
 if ACategoryIndex = -1 then
    ACategoryIndex := 0;
 Result.Category := ACategoryIndex;
end;
 
function TdxBarManager.AddSubItem: TdxBarSubItem;
begin
 Result := TdxBarSubItem(AddItem(TdxBarSubItem));
end;
 
通过代码,可以十分明显地知道,原来AddButton及AddSubItem都是调用AddItem的,而AddItem的作用是通过传入的特定的某些类名来产生相应的对象的,我们可以写以下的代码来试验一下
 
var
 asi : TdxBarSubItem;
begin
 asi := self.dxBarManager1.AddSubItem;
 asi.Caption := '菜单1';
….
很遗憾,这些代码根本不增加一个菜单子项。
线索似乎又断了,但回想一下,在dxBarManager中提供这个AddItem的方法肯定是有用的,要不然不会多此一举,因此,我们利用搜索的功能看一下那些地方调用了这个方法(最好在Delphi的环境中安装GExpert,利用它的Grep功能来搜),我们可以在同一个源文件中找到这样的内容
function TdxBarItemLinks.AddItem(AItemClass: TdxBarItemClass): TdxBarItemLink;
begin
 Result := Add(BarManager.AddItem(AItemClass));
end;
 
function TdxBarItemLinks.AddButton: TdxBarItemLink;
begin
 Result := Add(BarManager.AddButton);
end;
 
function TdxBarItemLinks.AddSubItem: TdxBarItemLink;
begin
 Result := Add(BarManager.AddSubItem);
end;
十分明显,在TdxBarItemLinks中调用了TdxBarMangerger的AddItem方法,但这个TdxBarItemLinks又是何方神圣呢?我们再去查这个TdxBarItemLinks的类,发现很多地方都有这个类的对象成员,其中包括我们想要的TdxBar类。
至此,我们可以测试一下以下的代码了:
 
 
var
 asi : TdxBarSubItem;
 il : TdxBarItemLink;
begin
 asi := self.dxBarManager1.AddSubItem;
 asi.Caption := '菜单1';
 dxbrMainMenu.ItemLinks.Add (asi);
end;
运行看看,这次真的可以在dxbrMainMenu中添加了一个菜单项了,虽然是一个空项,但没有关系,这是个好的开始。
我们再来看,这个新加上去菜单项是在菜单的末尾的,如果我们想把它放在前面的话,那么应该如何办呢?
一般来说在Delphi的习惯都是用Add或Append来进行追加,用Insert来插入,而刚好TdxBarItemLinks也正好符合这种说法,我们来看Insert的实现
function TdxBarItemLinks.Insert(AIndex: Integer): TdxBarItemLink;
begin
 Result := TdxBarItemLink(inherited Insert(AIndex));
end;
原来是调用基类的方法,而TdxBarItemLinks的基类是我们十分熟悉的VCL组件TCollection,而它的Insert代码如下,
function TCollection.Insert(Index: Integer): TCollectionItem;
begin
 Result := Add;
 Result.Index := Index;
end;
看代码就知道原来是调用Add方法,但这个Add方法是不带参数的,与我们刚才提到的方法有所不一样。
我们找回那两个Add方法来看看
function TdxBarItemLinks.Add: TdxBarItemLink;
begin
 Result := TdxBarItemLink(inherited Add);
end;
 
function TdxBarItemLinks.Add(AItem: TdxBarItem): TdxBarItemLink;
begin
 BeginUpdate;
 try
    Result := Add;
    Result.Item := AItem;
 finally
    EndUpdate;
 end;
end;
 
原来有参的Add方法也是调用这个无参的Add方法,而看到有参数的那个Add方法后,是否有些启示呢,我们可以利用TdxBarItemLink.Item来实现某些我们想要的功能,那么代码就变成这样了
 
var
 asi : TdxBarSubItem;
 il : TdxBarItemLink;
 abb : TdxBarButton;
begin
 asi := self.dxBarManager1.AddSubItem;
 asi.Caption := '菜单1';
 il := dxbrMainMenu.ItemLinks.Insert(0);
 il.Item := asi;
 
这样,就可以把生成出来的菜单项放在前面了。
现在我们来看看如何生成子项了,其实我们已经有了前面的基础,要生成子项也是十分容易的了,可以不用再查源程序了,直接就写出以下的代码
 
var
 asi : TdxBarSubItem;
 il, il2 : TdxBarItemLink;
 abb : TdxBarButton;
begin
 asi := self.dxBarManager1.AddSubItem;
 asi.Caption := '菜单1';
 il := dxbrMainMenu.ItemLinks.Insert(0);
 il.Item := asi;
 
 abb := self.dxBarManager1.AddButton;
 abb.Caption := '子项1';
 il2 := asi.ItemLinks.Insert(0);
 il2.Item := abb;
 
end;
至此,我们就完成了这个动态添加菜单的例子了。

 

你可能感兴趣的:(function,delphi,insert,integer,button,blog)