正在开发一个非.net得数据表格组件,用到.net应用中去……

在家正在开发一个grid COM组件,因为实在用.net Winform提供的DataGrid不爽,功能太少了,搞什么都得自己写大堆代码,连最基本得行选都得自己写datagrid.select(...) ...烦了;还是封装几个COM组件,反正系统也只需要运行到win2k的工控机上;大致确定了一下功能和名称,叫做GridCellPro组件,支持多种功能,比如合计列,合计行,打印,中文金额,过滤,排序,加亮,列排序,固定列,多种CELL;还有一个就是报表,水晶报表很强大,可和我使用习惯不一样,也许是习惯了borland的贴心设计吧,还是做好表格组件再说吧,希望能改善一下开发效率。

目前编写完框架代码,已经把表格框架搞完了,只是属性定制对话框还有点问题,到网上搜来个文章看了看,还不错,关键得地方都讲到了;顺便也收录进来,今后忘了又看。


原始地址:http://hubdog.csdn.net/Hubdog/ActiveX2.htm
转自哈巴狗的小窝

完善ActiveX控件

从VCL出发生成一个基本的ActiveX控件是很容易的,但为了让它更容易使用,比如添加属性页编辑器,还需要做一些额外的工作。接下来我们将继续完善ListX控件,这次不是改进它运行时的功能,而是增强它设计时的编辑功能,为它提供一个属性页和下拉式属性编辑器。

属性列表

如图1.7所示,在Visuabl Basic的窗体上放置一个ListBoxX控件,这时可以注意到在属性察看器中Cursor 和DragCursor 属性,不像通常在Delphi的属性察看器中所看到的ListBox控件的相应属性那样显示crDefault 和其他crDrag 枚举变量,而是显示0和-12的数值。这是因为TCursor 类型在Delphi中是整数类型,所以当ActiveX control wizard转化TListBox 控件时,Cursor属性就按一个整数属性来处理了。这样,在Visual Basic中我们要想设定列表框控件的光标为时钟形状,我们必须设定Cursor 属性为-11, 它等价于定义在Controls单元中的crHourGlass 常数值,但这样显得非常不直观,很容易忘记和混淆。

正在开发一个非.net得数据表格组件,用到.net应用中去……

图1.7

同时,在Delphi中使用TListBox 控件时,除了是显示一个符号名而不是数值外,属性察看器还会显示一个下拉式列表,里面包含了所有可能的光标值,那么我们能不能使我们的ActiveX控件在Visual Basic中有同样的属性列表呢?Nothing is impossible!我们可以重载TActiveXControl类的GetPropertyString、GetPropertyStrings和GetPropertyValue 方法来做到。下面就是修改后的ListBox控件代码:

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;

//省略…

protected

{ Protected declarations }

procedure InitializeControl; override;

procedure EventSinkChanged(const EventSink: IUnknown); override;

procedure DefinePropertyPages( DefinePropertyPage: TDefinePropertyPage); override;

function GetPropertyString( DispID: Integer; var S: string ): Boolean; override;

function GetPropertyStrings( DispID: Integer; Strings: TStrings ): Boolean; override;

procedure GetPropertyValue( DispID, Cookie: Integer; var Value: OleVariant ); override;

{ Methods that support properties }

. . .

end;

implementation

uses

TabWidthPpg, AboutListBox, SysUtils;

function TListBoxX.GetPropertyString( DispID: Integer;var S: string ): Boolean;

begin

case DispID of

5: // 5 =IlistBoxXDisp接口中DragCursor属性的DispID

begin

S := CursorToString( Get_DragCursor );

Result := True;

end;

26: // 26 = IlistBoxXDisp接口中Cursor属性的DispID

begin

S := CursorToString( Get_Cursor );

Result := True;

end;

else

Result := False;

end;

end;

function TListBoxX.GetPropertyStrings( DispID: Integer; Strings: TStrings ): Boolean;

var

I: Integer;

Cookie: Integer;

TempList: TStringList;

begin

case DispID of

5, // 5 =IlistBoxXDisp接口中DragCursor属性的DispID

26: // 26 = IlistBoxXDisp接口中Cursor属性的DispID

begin

TempList := TStringList.Create;

try

GetCursorValues( TempList.Append );

for I := 0 to TempList.Count - 1 do

begin

Cookie := StringToCursor( TempList[ I ] );

Strings.AddObject( TempList[ I ], TObject( Cookie ) );

end;

finally

TempList.Free;

end;

Result := True;

end;

else

Result := False;

end;

end;

procedure TListBoxX.GetPropertyValue( DispID, Cookie: Integer;

var Value: OleVariant );

begin

case DispID of

5, // 5 =IlistBoxXDisp接口中DragCursor属性的DispID

26: // 26 = IlistBoxXDisp接口中Cursor属性的DispID

begin

{ Cookie 代表被选的项目}

Value := Cookie;

end;

end;

end;

{= 省略…}

initialization

TActiveXControlFactory.Create( ComServer, TListBoxX, TListBox,

Class_ListBoxX, 1, '{B19A64E4-644D-11D1-AE4B-444553540000}', 0);

end.

这里TListBoxX 控件由于是继承于TActiveXControl,所以在TListBoxX类中可以重载上面的方法。

GetPropertyString 函数在属性察看器显示一个属性时会被调用,通过重载这个方法,我们可以为一个属性值提供一个字符串表达。它同Delphi的属性编辑器TPropertyEditor类的GetValue方法比较类似。

GetPropertyString 函数会提供两个参数,第一个是被请求字符串表达的属性的dispid。因为所有控件属性的显示都会调用这个方法,所以必须过滤要处理的属性,这通过用Case语句来检验Dispid就可以了。要想确定每个属性对应的Dispid,可以察看类型库接口单元。类型库单元的代码如下:

unit DelphiByDesignXLib_TLB;

{ This file contains pascal declarations imported from a type library.

This file will be written during each import or refresh of the type

library editor. Changes to this file will be discarded during the

refresh process. }

interface

uses Windows, ActiveX, Classes, Graphics, OleCtrls, StdVCL;

const

LIBID_DelphiByDesignXLib: TGUID =

'{B19A64DB-644D-11D1-AE4B-444553540000}';

const

{ Component class GUIDs }

Class_ListBoxX: TGUID = '{B19A64DE-644D-11D1-AE4B-444553540000}';

type

{ Forward declarations: Interfaces }

IListBoxX = interface;

IListBoxXDisp = dispinterface;

IListBoxXEvents = dispinterface;

{ Forward declarations: CoClasses }

ListBoxX = IListBoxX;

{ Forward declarations: Enums }

TxBorderStyle = TOleEnum;

TxDragMode = TOleEnum;

TxImeMode = TOleEnum;

TxListBoxStyle = TOleEnum;

TxMouseButton = TOleEnum;

{ Dispatch interface for ListBoxX Control }

IListBoxX = interface(IDispatch)

['{B19A64DC-644D-11D1-AE4B-444553540000}']

function Get_DragCursor: Smallint; safecall;

procedure Set_DragCursor(Value: Smallint); safecall;

. . .

function Get_Cursor: Smallint; safecall;

procedure Set_Cursor(Value: Smallint); safecall;

. . .

procedure AboutBox; safecall;

. . .

property DragCursor: Smallint

read Get_DragCursor write Set_DragCursor;

. . .

property Cursor: Smallint read Get_Cursor write Set_Cursor;

end;

{ DispInterface declaration for Dual Interface IListBoxX }

IListBoxXDisp = dispinterface

['{B19A64DC-644D-11D1-AE4B-444553540000}']

property BorderStyle: TxBorderStyle dispid 1;

property Color: TColor dispid 2;

property Columns: Integer dispid 3;

property Ctl3D: WordBool dispid 4;

property DragCursor: Smallint dispid 5;

property DragMode: TxDragMode dispid 6;

property Enabled: WordBool dispid 7;

property ExtendedSelect: WordBool dispid 8;

property Font: Font dispid 9;

property ImeMode: TxImeMode dispid 10;

property ImeName: WideString dispid 11;

property IntegralHeight: WordBool dispid 12;

property ItemHeight: Integer dispid 13;

property Items: IStrings dispid 14;

property MultiSelect: WordBool dispid 15;

property ParentColor: WordBool dispid 16;

property ParentCtl3D: WordBool dispid 17;

property Sorted: WordBool dispid 18;

property Style: TxListBoxStyle dispid 19;

property TabWidth: Integer dispid 20;

property Visible: WordBool dispid 21;

procedure Clear; dispid 22;

property ItemIndex: Integer dispid 23;

property SelCount: Integer readonly dispid 24;

property TopIndex: Integer dispid 25;

property Cursor: Smallint dispid 26;

procedure AboutBox; dispid -552;

end;

{ Events interface for ListBoxX Control }

IListBoxXEvents = dispinterface

['{B19A64DD-644D-11D1-AE4B-444553540000}']

procedure OnClick; dispid 1;

procedure OnDblClick; dispid 2;

procedure OnKeyPress(var Key: Smallint); dispid 3;

procedure OnColorItem(Index: Integer;

var Color: TColor); dispid 4;

end;

implementation

end.

从上面可以看到,与控件属性对应的Dispid可以在IListBoxXDisp 声明部分找到。

GetPropertyString 函数的第二个参数是一个字符串变量。这个字符串变量将会被显示为相应的属性值,但要注意的是函数的返回值一定要设为True,返回False 将使属性察看器忽略返回的字符串参数。

在上面的GetPropertyString 方法中,使用了CursorToString 函数来转化当前属性值为一个字符串,同时Get_Cursor和Get_DragCursor方法被用来获得当前的属性值。

实现GetPropertyString 方法可以确保对于每个Cursor数值都会有一个字符串来说明它,但是如何显示所有光标的下拉列表呢?这时就必须重载GetPropertyStrings 和GetPropertyValue 方法了。GetPropertyStrings 负责生成一个将要显示在下拉列表中的字符串列表。当用户从列表中选择了一个列表项后,GetPropertyValue 方法就会被调用来返回真正的数值。

首先让我们来看GetPropertyStrings 函数,这个方法有两个参数:一个是Dispid,一个是字符串列表,Dispid自然还是对应于操作的属性,而字符串列表则是用来容纳将要显示在下拉列表中的字符串,此外,字符串列表还必须为每个列表项保存一个唯一的“cookie”值,当用户选择了一个列表项后,对应的cookie值会传递给GetPropertyValue 方法。

为了把cookie值同列表中的字符串关联起来,调用Strings.AddObject 方法来添加字符串到列表中:

try

GetCursorValues( TempList.Append );

for I := 0 to TempList.Count - 1 do

begin

Cookie := StringToCursor( TempList[ I ] );

Strings.AddObject( TempList[ I ], TObject( Cookie ) );

end;

finally

正在开发一个非.net得数据表格组件,用到.net应用中去……

图1.8

把要显示的字符串作为第一个参数,而第二个参数为Cookie值来调用。Cookie值可以取任意值,这里使用的是Cursor本身对应的整数值。注意AddObject方法的第二个参数需要是TObject类型的参数,所以这里进行了一次类型映射。

GetPropertyValue 方法则有三个参数:第一个参数是属性对应的Dispid,第二个参数是对应于被选列表项的Cookie值,而第三个是用来返回属性值的参数。这个方法的处理非常简单,对于我们这个例子来说,只要把Cookie值返回就可以了,因为它就是实际的Cursor对应的值。

实现这些方法后,我们要做的就是重新注册控件了,图1.8显示了新界面更加友好的属性下拉列表。

实现属性页支持

仔细看一下Visual Basic中的ListBoxX控件的属性察看器,就会发现Items 属性没有显示在其中,但ListBoxX控件是有Items 属性的,其实这是因为ActiveX Control Wizard把它由published属性声明为public类型的属性了,这使得我们只能在运行时操作Items 属性,而无法在设计时编辑Items 属性。因为Visual Basic没有为Items类型的属性提供缺省的属性编辑器,所以ActiveX Control Wizard就没有published Items属性。

正在开发一个非.net得数据表格组件,用到.net应用中去……

图1.9

但可以通过自定义的属性页编辑器来提供对Items属性设计时的编辑支持。属性页总能在各种支持ActiveX控件程序中看到,它提供了方便的属性编辑功能。Delphi 提供了一些现成的预定义的属性页支持,可以把它同ActiveX控件相关联。每个属性页有一个对应的Class ID,它声明在AxCtrls单元中,图1.9列出了每个ID和对应的属性页的功能:

这些预定义的属性页被设计成可以用于任意的ActiveX控件。每个属性页都使用运行时类型信息 (RTTI)来确定控件中哪个属性可以使用相应的属性页进行编辑,并会把每个属性名添加到一个下拉编辑框中,这样的话,一个属性页就可以编辑所有相同类型的属性了。图1.10显示了用来编辑ListBoxX控件的Items属性的字符串属性页:

要想把预定义的属性页同ActiveX控件相关联,只要在控件的DefinePropertyPages 方法中添加对DefinePropertyPage方法的调用就可以了,下面代码把字符串和字体属性页同ListBoxX控件进行了关联:

正在开发一个非.net得数据表格组件,用到.net应用中去……

图1.10

{ TListBoxX }

procedure TListBoxX.DefinePropertyPages(

DefinePropertyPage: TDefinePropertyPage );

begin

{ 把预定义的属性页同控件关联 }

DefinePropertyPage( Class_DStringPropPage );

DefinePropertyPage( Class_DFontPropPage );

//省略…

end;

用户定制的属性页

除了使用预定义的属性页外,还可以创建自定义的属性页。选菜单File|New,切换到ActiveX页,然后选择Property Page项,Delphi将生成一个属性页的窗体文件和单元文件。下面就是生成的TabWidthPpg属性页的代码:

unit TabWidthPpg;

interface

uses

SysUtils, Windows, Messages, Classes, Graphics, Controls, StdCtrls, ExtCtrls, Forms,

ComServ, ComObj, StdVcl, AxCtrls,

ComCtrls;

type

TPpgTabWidth = class(TPropertyPage)

GrpPreview: TGroupBox;

GrpTabWidth: TGroupBox;

LstPreview: TListBox;

ChkUseTabs: TCheckBox;

TrkTabWidth: TTrackBar;

procedure ChkUseTabsClick(Sender: TObject);

procedure TrkTabWidthChange(Sender: TObject);

private

{ Private declarations }

protected

procedure UpdatePropertyPage; override;

procedure UpdateObject; override;

public

{ Public declarations }

end;

const

Class_PpgTabWidth: TGUID =

'{8BE91420-9070-11D1-AE4B-44455354616F}';

implementation

{$R *.DFM}

procedure TPpgTabWidth.UpdatePropertyPage;

var

I: Integer;

begin

{ 使用OleObject更新对象}

{ 从对象中复制字符串到预览列表框 }

for I := 0 to OleObject.Items.Count - 1 do

LstPreview.Items.Add(OleObject.Items[I]);

ChkUseTabs.Checked := OleObject.TabWidth > 0;

TrkTabWidth.Position := OleObject.TabWidth div 4;

LstPreview.TabWidth := OleObject.TabWidth;

end;

procedure TPpgTabWidth.UpdateObject;

begin

{ 使用OleObject更新控件TabWidth属性}

OleObject.TabWidth := LstPreview.TabWidth;

end;

procedure TPpgTabWidth.ChkUseTabsClick(Sender: TObject);

begin

TrkTabWidth.Enabled := ChkUseTabs.Checked;

if ChkUseTabs.Checked then

LstPreview.TabWidth := TrkTabWidth.Position * 4

else

LstPreview.TabWidth := 0;

end;

procedure TPpgTabWidth.TrkTabWidthChange(Sender: TObject);

begin

Modified;

LstPreview.TabWidth := TrkTabWidth.Position * 4;

end;

initialization

TActiveXPropertyPageFactory.Create(

ComServer, TPpgTabWidth, Class_PpgTabWidth);

end.

正在开发一个非.net得数据表格组件,用到.net应用中去……

图1.11

注意上面TPpgTabWidth 类是从TPropertyPage继承来的,它的上层父类是TCustomForm。因此我们可以像普通的Delphi窗体一样定制属性页。这个属性页允许用户可视化的调整ActiveX控件的TabWidth 属性。图1.11就是属性页示意图。

属性页显示时应该能够根据存储在ActiveX控件中的数据更新相应属性页页面的显示,这一切都可以在UpdatePropertyPage方法中来加以实现。上面代码中的TPpgTabWidth. UpdatePropertyPage 方法就是先从ActiveX控件中获得字符串,接着设定ListPreview 列表框,然后是checkbox状态和TabWidth 属性被初始化。一旦激活属性页后,必须能够根据用户输入更新ActiveX控件的属性,这是通过实现UpdateObject 方法来完成的。上面代码中TPpgTabWidth.UpdateObject 方法就是简单的根据预览列表的TabWidth设定更新ActiveX控件的。要注意的是方法中用到的OleObject 就代表ActiveX控件,因此可以使用它来设定数据。

同预定义的属性页一样,我们也要把自定义的属性页同ActiveX控件相关联。同前面一样,通过在DefinePropertyPages 方法中添加对DefinePropertyPage的调用就可以了,这回参数就是新建立的属性页的GUID ,下面就是实现代码:

{ 把用户定制的属性页同控件相关联 }

DefinePropertyPage( Class_PpgTabWidth );

分发ActiveX控件

显然分发包中必须包括编译生成的*.ocx 文件,如果ActiveX项目中用到了其他运行时包,我们还需要分发相应的文件。

如果创建ActiveX控件时选择生成设计时的许可文件,还需要分发相应的*.lic文件。

另外,如果创建的ActiveX项目用到了IStrings 接口或预定义的字体、颜色、字符串或图像属性页的话,我们还必须分发标准的VCL类型库,它包括StdVcl32.dll和StdVcl32.tlb类型库文件。这两个文件是被Delphi安装到了Windows的系统目录下(比如,C:\WinNT\System32)。凡是使用了预定义的属性页的控件必须分发StdVcl32.dll,然而如果只使用了IStrings接口的话,可以只分发StdVcl32.tlb类型库。

注册ActiveX的工具Turbo Register Server

要想使ActiveX控件生效,必须更新注册表信息,这可以使用Turbo Register Server (TRegSvr)程序来完成,这个程序是Borland作为一个演示程序提供的。例子源代码位于Demos\ActiveX\TRegSvr目录下。

TRegSvr 是一个简单的命令行程序,它支持一些开关来控制ActiveX控件的注册,除了要注册的文件名外不加任何参数的话就会注册指定文件。加了-u开关的话就会注销ActiveX控件,-t开关是用来表明ActiveX控件的类型库也应该被注册,如果要注册的文件名为*.tlb,则这个开关可以不设定。-q开关表示TRegSvr不显示任何输出信息,这使得它比较适用于嵌入于安装程序中。

下面是使用TRegSvr程序注册TListBoxX 控件的例子示意:

TRegSvr -q XXX.ocx

TRegSvr -q StdVcl32.dll




本文转自suifei博客园博客,原文链接:http://www.cnblogs.com/Chinasf/archive/2005/04/19/140860.html,如需转载请自行联系原作者

上一篇:在一款D-Link消费级路由器上,我发现了10个严重漏洞


下一篇:android读取sd卡图片并进行缩放操作