唉,我想编写ACTIVEX控件,在书店找不到有关这方面的书,上网也不知道在那里有买,顶者有分罗,向我推荐一下有关网站和书籍
解决方案 »
- 对象成员.....
- dephi变量初始化的一点疑惑
- *** 高分请教:MySQL的问题,请注意不是SQLServer ***
- 急求DELPHI语法分析程序或相关文件!
- 是不是delphi有问题,怎么这个小地方过不去呢,帮看一下
- 多谢 &風鈴夜思雨
- 恼人的英文版,请狠狠的指点
- 关于sock udp 编程的问题,想不通.
- 为什么执行结果和我想象的不一杨?
- :有一个WebBrowser空间在Pagecontrol控件上,当Pagecontrol控件增加一页时自动生成一个WebBrowser控件,并且显示当前最新链接,而且前一页仍显示原来的链接,这如何实现啊
- 如何将一DBGRID显示的记录写入一个临时表?
- 安装文件
很多的
然后选择ActiveX Control项,显示一个对话框,第一步是选则VCL的类名,VCL类名下拉框中列出了全部TWinControl的子类(不包括使用RegisterNonActiveX函数注册的控件)从列表我们可以看到TListBox,但你找不到TLable,因为TLabel继承于TGraphicControl,当然象那种TTimer的非可视控件更是没有了。如下图所示:
当我们选好了类名,向导会自动给其他编辑框添上缺省值。这里我们使用它的缺省值,同时选中ActiveX Control Options的三个选项,然后点OK 。 ActiveX 控制选项 上图显示了全部可以选的ActiveX控制选项,Include Design-Time License选项表明设计时许可证将被创建,除非用户有许可证,否则它可以防止控件在设计环境中被非法使用,。如果选择了这个选项,向导会产生一个LIC文件,里面包含了许可证信息。用户必须有这个.LIC文件才能在开发环境中使用相应的ActiveX控件。Include Version Information选项使你可以在项目中添加象版权说明、版本号等版本信息。具体版本信息的设定可以在创建好项目后,选Project|Options然后切换到Version-Info页来进行。(注意: 尽管版本信息是一个可选的选项,但如果你打算在Visual Basic 4.0及以上中使用Delphi生成的ActiveX控件,你必须选定它)。Include About Box选项表明你是否为ActiveX控件创建一个关于对话框。关于对话框是一个独立的窗体单元,你可以编辑它来显示你需要的版本信息或其他信息。关于信息是通过在开发环境中点击About 属性来调用的。 生成单元文件 一切设定好后,点OK按钮。向导首先创建一个ActiveX Library 项目。接着创建一个实现单元,来实现原生的Delphi控件的COM封装。封装类是TActiveXControl一个简单的子类,然后是类型库和类型库接口单元(类型库实际上是一个二进制文件里面定义数据类型、接口、方法以及ActiveX Library要公开的对象。类型库接口单元包含了对应于类型库中的信息Pascal的声明)。最后是许可证文件,关于对话框和源码文件。 编译和注册ActiveX控制 现在我们可以编译ActiveX Library 项目来生成包含ActiveX控件的OCX文件。我们可以直接调用Run|Register Sever来注册ActiveX Sever。然而在做之前,我建议保存全部的项目文件。如果你没有先保存项目文件,那么储存在注册表中的路径就是你当前的路径而不一定是你的项目的真正路径。 注册后我们就可以在Visual Basic等程序中使用Delphi生成的ActiveX控件了,如下图示意:
ActiveX 转换过程中的问题 虽然ListBoxX控件使我们能在Visual Basic中使用TListBox很多功能。但ListBoxX控件并没有实现TListBox的全部功能。比如,TListBox的OnDrawItem的事件定义在ListBoxX中是找不到的。回想一下在Delphi里我们经常使用OnDrawItem事件来支持用户自绘画功能。没有了这个事件,ActiveX版本的ListBox就无法支持这一特性即使Style属性设定为lsOwnerDrawFixed。 要理解为什么这个事件没有出现在ActiveX中,我们需要研究一下事件类型,特别是要研究一下传递给事件的参数类型。OnDrawItem声明为TDrawItemEvent类型,定义如下: TDrawItemEvent = procedure( Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState) of object; 我们看到OnDrawItem 事件处理函数接受4个参数。其中第三个参数阻止了事件出现在ActiveX Control中。因为OLE自动化不知道如何整理(marshall)TRect类型的数据。 原因在于ActiveX 控制实际上是小型的OLE自动化服务器。包含 ActiveX控件的ActiveX 容器使用自动化来和控件通讯。因此要想使一个属性、方法或事件出现在ActiveX版本的控制中,全部参数和返回类型必须是自动化兼容的。表1列出了全部的兼容类型。
虽然在这个表中我们没有列出但ActiveX转换向导还可以正确处理TColor, TFont, TPicture, and TStrings属性。Color 属性可以很容易转换因为它实际上就是一个整数类型。然而对于其他属性类型,Delphi提供了一个定制的接口来处理对应的Delphi属性。比如,IStrings 接口提供了处理TStrings属性的途径。 同时,一个属性是自动化兼容的并不意味着它就一定会出现在ActiveX 控件中,向导不会转化对ActiveX无意义的属性、方法或事件。下列属性就没有被转化,比如:Height, HelpContext, Hint, Left, Name, ParentFont, ParentShowHint, PopupMenu, ShowHint, TabOrder, Tag, Top, and Width等。 此外,有两种特殊类型的属性向导也不会转化。对象引用和数据明了属性。对象引用(就是指Delphi的某个属性对应于一个对象,比如TTable的Datasource实际上是引用了另外一个对象TDataSource)在Delphi里是通过指针来实现的因此是自动化不兼容的。此外, ActiveX本身也没有提供一个标准的方式来使一个控件同容器中的其他控件相关联。而数据明了属性DataSource和DataField没有被映射到ActiveX控件中去是因为Delphi实现的数据明了采用了完全不同于ActiveX 的机制。当然如果非常想利用Delphi中好用的数据库控件,这也是可以的,但需要一些额外的工作,这已经超出了本文的范围,将不在这里介绍。必须指出的是ActiveX的数据控件和Delphi的数据控件是不一样的。这也就是为什么没有一个Delphi的数据明了控件出现在ActiveX转换向导的类名列表中的缘故。 正确的转换的关键 到目前为止ListBoxX其他特性都没问题,我们也可以把Style变成lsOwnerDrawFixed, 但是没有OnDrawItem事件我们无法改变它的外观显示。让我们试一种不同的方法,这就是定义一个自动化兼容的接口来实现自绘画的外观(Owner-Draw).例如我们可以创建一个新的事件OnColorItem使我们能改变每一个列表项的颜色。 添加新事件 添加新的事件到ActiveX中需要修改类型库中的信息,可以有两种方法:通过选择 Edit|Add To Interface 菜单或用内置的类型库编辑器都可以,Edit|Add To Interface 菜单只有当当前文件为实现单元时才能使用。如下图所示:
上图显示了OnColorItem 是如何加入到IListBoxXEvents 接口中的。定义一个ActiveX接口的新事件同Delphi中有点不同。不象Delphi中那样给事件声明一个属性类比如TNotifyEvent, 你必须写一个将会传递给事件处理函数的带参数的过程。类似于写一个控件中的事件分配方法。OnColorItem事件定义如下: procedure OnColorItem(Index: Integer; var Color: Integer ); 点OK按钮,Delphi 就把这个声明加入了类型库。这使得我们可以给OnColorItem事件写处理函数了。但是在这之前, 我们还必须实现产生事件的代码,这有点类似于在Delphi控件中定义新的事件。生成事件属性和事件分配方法仅仅是一部分工作。我们还必须在合适的时间调用事件分配方法来产生事件。最好的产生OnColorItem事件的位置就是在Delphi控件的OnDrawItem事件中,实现的方法见源码清单1。 TListBoxX 封装类定义了一个事件处理函数DrawItemEvent 来对嵌入的ListBox的OnDrawIem事件来响应,DrawItemEvent函数在InitializeControl方法中进行初始化。同时DrawItemEvent函数负责产生OnColorItem事件。为了产生事件,要使用FEvents接口来激发OnColorItem事件过程。Index参数来自于DrawItemEvent参数列表,而Color参数是在DrawItemEvent里定义的。当OnColorItem 事件返回时, ItemColor 变量将包括缺省的颜色或用户定义的颜色。然后ItemColor变量就被用来画列表项。如下图所示:
上图显示了ListBoxX控件在VB中的运行状况。虽然ActiveX不可能象在Delphi可以随意引用Canvas来画图,但是这个例子证明了利用ActiveX控件的灵活性,我们还是可以作一些有趣的效果。 正如我们在上面这个例子中看到的,实际上把Delphi控件转化为ActiveX控件并不是很容易,这是由于我们转换的是一个现成的Delphi控件,特别是这个控件使用了某些VCL的高级特性。从这个方面来说,Active控制框架不如VCL灵活,然而ActiveX是一个公认的标准,可以在除了Delphi外的其他环境中使用,牺牲灵活性意味着获得了广泛性。
如果你想从头开始创建一个ActiveX控件,首先你的控件必须从TWincontrol开始继承,如果想要提供自绘画的功能,必须从TCustomControl开始。另外,应该使用自动化兼容的数据类型来定义属性、方法、参数。如果你想转换一个已有的VCL控件变成ActiveX,注意一定要改变参数类型,否则方法,属性等等是不会被转换的。 源码清单1 - ListBoxImpl.pas unit ListBoxImpl; interface uses Windows, ActiveX, Classes, Controls, Graphics, Menus, Forms, StdCtrls, ComServ, StdVCL, AXCtrls, DelphiByDesignXLib_TLB; type TListBoxX = class(TActiveXControl, IListBoxX) private { Private declarations } FDelphiControl: TListBox; FEvents: IListBoxXEvents; procedure ClickEvent(Sender: TObject); procedure DblClickEvent(Sender: TObject); procedure KeyPressEvent(Sender: TObject; var Key: Char); // Add a custom event handler for the OnDrawItem event procedure DrawItemEvent( Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState ); protected { Protected declarations } procedure InitializeControl; override; procedure EventSinkChanged(const EventSink: IUnknown); override; procedure DefinePropertyPages( DefinePropertyPage: TDefinePropertyPage); override; function Get_BorderStyle: TxBorderStyle; safecall; function Get_Color: TColor; safecall; function Get_Columns: Integer; safecall; function Get_Ctl3D: WordBool; safecall; function Get_Cursor: Smallint; safecall; function Get_DragCursor: Smallint; safecall; function Get_DragMode: TxDragMode; safecall; function Get_Enabled: WordBool; safecall; function Get_ExtendedSelect: WordBool; safecall; function Get_Font: Font; safecall; function Get_ImeMode: TxImeMode; safecall; function Get_ImeName: WideString; safecall; function Get_IntegralHeight: WordBool; safecall; function Get_ItemHeight: Integer; safecall; function Get_ItemIndex: Integer; safecall; function Get_Items: IStrings; safecall; function Get_MultiSelect: WordBool; safecall; function Get_ParentColor: WordBool; safecall; function Get_ParentCtl3D: WordBool; safecall; function Get_SelCount: Integer; safecall; function Get_Sorted: WordBool; safecall; function Get_Style: TxListBoxStyle; safecall; function Get_TabWidth: Integer; safecall; function Get_TopIndex: Integer; safecall; function Get_Visible: WordBool; safecall; procedure AboutBox; safecall; procedure Clear; safecall; procedure Set_BorderStyle(Value: TxBorderStyle); safecall; procedure Set_Color(Value: TColor); safecall; procedure Set_Columns(Value: Integer); safecall; procedure Set_Ctl3D(Value: WordBool); safecall; procedure Set_Cursor(Value: Smallint); safecall; procedure Set_DragCursor(Value: Smallint); safecall; procedure Set_DragMode(Value: TxDragMode); safecall; procedure Set_Enabled(Value: WordBool); safecall; procedure Set_ExtendedSelect(Value: WordBool); safecall; procedure Set_Font(const Value: Font); safecall; procedure Set_ImeMode(Value: TxImeMode); safecall; procedure Set_ImeName(const Value: WideString); safecall; procedure Set_IntegralHeight(Value: WordBool); safecall; procedure Set_ItemHeight(Value: Integer); safecall; procedure Set_ItemIndex(Value: Integer); safecall; procedure Set_Items(const Value: IStrings); safecall; procedure Set_MultiSelect(Value: WordBool); safecall; procedure Set_ParentColor(Value: WordBool); safecall; procedure Set_ParentCtl3D(Value: WordBool); safecall; procedure Set_Sorted(Value: WordBool); safecall; procedure Set_Style(Value: TxListBoxStyle); safecall; procedure Set_TabWidth(Value: Integer); safecall; procedure Set_TopIndex(Value: Integer); safecall; procedure Set_Visible(Value: WordBool); safecall; end; implementation uses AboutListBox; { TListBoxX } procedure TListBoxX.InitializeControl; begin FDelphiControl := Control as TListBox; FDelphiControl.OnClick := ClickEvent; FDelphiControl.OnDblClick := DblClickEvent; FDelphiControl.OnKeyPress := KeyPressEvent; //添加一个定制的事件来处理OnDrawItem事件 FDelphiControl.OnDrawItem := DrawItemEvent; end; procedure TListBoxX.EventSinkChanged(const EventSink: IUnknown); begin FEvents := EventSink as IListBoxXEvents; end; function TListBoxX.Get_Enabled: WordBool; begin Result := FDelphiControl.Enabled; end; procedure TListBoxX.Set_Enabled(Value: WordBool); begin FDelphiControl.Enabled := Value; end; procedure TListBoxX.DrawItemEvent( Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState ); var ItemColor: Integer; begin ItemColor := Integer(FDelphiControl.Font.Color); //产生OnColorItem ActiveX事件 if FEvents <> nil then FEvents.OnColorItem( Index, ItemColor ); //用ItemColor画列表项 with FDelphiControl do begin if not ( odSelected in State ) then Canvas.Font.Color := ItemColor; Canvas.TextRect(Rect, Rect.Left + 2, Rect.Top, Items[Index]); Canvas.Font.Color := FDelphiControl.Font.Color; end; end; initialization TActiveXControlFactory.Create( ComServer, TListBoxX, TListBox, Class_ListBoxX, 1, '{B19A64E4-644D-11D1-AE4B-444553540000}', 0); end.