zoukankan      html  css  js  c++  java
  • 正在开发一个非.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 常数值,但这样显得非常不直观,很容易忘记和混淆。

    图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

    图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属性。

    图1.9

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

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

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

    图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.

    图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

  • 相关阅读:
    [CSP-S模拟测试]:party?(霍尔定理+最小割+树链剖分)
    [CSP-S模拟测试]:marshland(最大费用可行流)
    [CSP-S模拟测试]:Revive(点分治)
    [CSP-S模拟测试]:Lighthouse(哈密顿回路+容斥)
    [CSP-S模拟测试]:Lost My Music(凸包)
    [CSP-S模拟测试]:God Knows(线段树维护单调栈)
    [CSP-S模拟测试]:Star Way To Heaven(最小生成树Prim)
    [CSP-S模拟测试]:gcd(莫比乌斯反演)
    [CSP-S模拟测试]:water(BFS)
    BZOJ3462 DZY Loves Math II 【多重背包 + 组合数】
  • 原文地址:https://www.cnblogs.com/Chinasf/p/140860.html
Copyright © 2011-2022 走看看