[转贴]如何把设计时代码从运行时代码中分离出去

来源:互联网 发布:阿里云申请幕布流程 编辑:程序博客网 时间:2024/05/06 23:16
你应该养成一个把组件分开成两个包的习惯,即使是你只在程序中静态地进行链接,因为混合运行时和设计时代码将使你的代码膨胀。你的设计时代码在运行时不会被执行,但是链接器不会知道,所以把它也一起链接进去了。(这就是为什么DsgnIntf要设法链接进去的原因。)

  让我们看一个简单的例子,了解如何把设计时代码从运行时代码中分离出去:

{ TMixedComponent }
TMixedComponent = class(TComponent)
  private
    FFileName: String;
  published
    property  FileName : String read FFileName write FFileName;
    { Published declarations }
  end;
  { TMixedFileNameProperty }
  TMixedFileNameProperty = class(TPropertyEditor)
    function    AllEqual: boolean; override;
    procedure   Edit; override;
    function    GetAttributes: TPropertyAttributes; override;
    function    GetValue: string; override;
    procedure   SetValue (const  Value: string); override;
  end;
procedure  Register;

implementation

procedure  Register;
begin
  RegisterPropertyEditor(TypeInfo(string), TMixedComponent, ’FileName’,

TMixedFileNameProperty);
  RegisterComponents(’Samples’, [TMixedComponent]);
end;

function  TMixedFileNameProperty.AllEqual: boolean;
var
  FirstVal: string;
  i: Integer;
begin
  FirstVal := GetStrValue;
  Result := True;
  i := 1;
  while  Result and  (i < PropCount) do
  begin
    Result := Result and  (GetStrValueAt(i) = FirstVal);
    Inc(i);
  end;
end;

procedure  TMixedFileNameProperty.Edit;
var
  Dlg: TOpenDialog;
begin
  Dlg := TOpenDialog.Create(Application);
  try
    with  Dlg do
    begin
      Title := ’File for ’ + TComponent(GetComponent(0)).Name;
      FileName:= Value;
      if  Execute then  Value := FileName;
    end;
  finally
    FreeAndNil(Dlg);
  end
end;

function  TMixedFileNameProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paDialog]
end;

function  TMixedFileNameProperty.GetValue: string;
begin
  Result := GetStrValue;
end;

procedure  TMixedFileNameProperty.SetValue(const  Value: string);
begin
  SetStrValue(Value);
end;

end.

  把设计时代码从运行时代码中分离出去的最简单方法是,把所有需要DesignIntf 和DesignEditors 代码放入它们自己的单元中去,那个单元将要添加使用组件单元的声明。组件自己不需要知道那个自己运作的IDE编辑器。首先,把DesignIntf 和 DesignEditors 单元从组件单元的Uses部分删除掉,然后让编译/链接器告诉你哪些类需要移到它们自己的单元中去:

[Error] MixedComponent.pas(23): Undeclared identifier: ’TPropertyEditor’
[Error] MixedComponent.pas(23): Class type required
[Error] MixedComponent.pas(24): Method ’AllEqual’ not found in base class
[Error] MixedComponent.pas(25): Method ’Edit’ not found in base class
[Error] MixedComponent.pas(26): Undeclared identifier: ’TPropertyAttributes’
[Error] MixedComponent.pas(27): Method ’GetValue’ not found in base class
[Error] MixedComponent.pas(28): Method ’SetValue’ not found in base class
[Error] MixedComponent.pas(35): Undeclared identifier: ’RegisterPropertyEditor’
[Error] MixedComponent.pas(35): Undeclared identifier: ’TMixedFile’
[Error] MixedComponent.pas(46): Undeclared identifier: ’GetStrValue’
[Error] MixedComponent.pas(49): Undeclared identifier: ’PropCount’
[Error] MixedComponent.pas(51): Undeclared identifier: ’GetStrValueAt’
[Error] MixedComponent.pas(51): Operator not applicable to this operand type
[Error] MixedComponent.pas(64): Undeclared identifier: ’GetComponent’
[Error] MixedComponent.pas(65): Undeclared identifier: ’Value’
[Error] MixedComponent.pas(75): Undeclared identifier: ’paDialog’
[Error] MixedComponent.pas(80): Undeclared identifier: ’GetStrValue’
[Error] MixedComponent.pas(85): Undeclared identifier: ’SetStrValue’
[Fatal Error] JOComponents.dpk(33): Could not compile used unit

’MixedComponent.pas’

  下一步是创建一个新的单元存放这些代码。可以命名为类似MixedComponentReg的名子。把Register函数也移到那个单元中去。下面我们可以从错误信息中得知哪些需要移走。第一个错误信息是[Error] MixedComponent.pas(23): Undeclared identifier: ’TPropertyEditor’,这个信息指出了一个继承自那个设计时单元的类。这是个很清楚的指示,它指明了它是设计时代码和这个类要被移到一个新创建的单元。

  到此,运行时包将会被成功编译(如果还不行,继续把设计时代码从单元中移去,直到没有错误产生)。现在组件在你的应用程序运行时已不再需要Proxies.pas和其它设计时单元了。这个运行时组件非常简单,如下:

unit MixedComponent;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  { TMixedComponent }
  TMixedComponent = class(TComponent)
  private
    FFileName: String;
  published
    property FileName : String read FFileName write FFileName;
    { Published declarations }
  end;

implementation

end.

  这最后一步就是把你的组件和它的属性编辑器编译到一个设计时包中,然后安装到IDE中去。

  通过File | New | Other 选择 package创建一个新的包。调出包选项,选择design-time only,给Description 项填一个描述文字。选择Requires folder,点击Add按钮。在Requires Package 编辑对话框填写Designide.dcp,点击OK。同样,为你的组件运行时包添加dcp。在这种情况下,它放在了JOComponents.dpk,因此JOComponents.dcp被添加到requires项。在requires里有:JOComponents, designide 和 rtl。最后,选择包含目录,添加MixedComponentReg.pas 到包里。

  到现在我们已经基本完成了!打开MixedComponentReg.pas 添加一对单元到uses部分,这要看你的组件或属性编辑器是否要在声明中使用这个组件(一些复杂的编辑器有时需要知道这个组件的存在)。如果是这样,把它加到Interface的uses部分。否则,加到implementation的uses部分。DesignIntf和DesignEditors就放到Interface的uses里。SysUtils, Forms, Dialogs, 和 Classes 在内部的属性编辑器的不同地方使用,因此就放到implementation部分。最后的MixedComponentReg应该象下面这样:

unit MixedComponentReg;

interface

uses DesignIntf, DesignEditors;

type
  { TMixedFileNameProperty }
  TMixedFileNameProperty = class(TPropertyEditor)
    function  AllEqual: boolean; override;
    procedure Edit; override;
    function  GetAttributes: TPropertyAttributes; override;
    function  GetValue: string; override;
    procedure SetValue (const Value: string); override;
  end;

procedure Register;

implementation

uses MixedComponent, SysUtils, Forms, Dialogs, Classes;

procedure Register;
begin
  RegisterPropertyEditor(TypeInfo(string), TMixedComponent, ’FileName’,

TMixedFileNameProperty);
  RegisterComponents(’Samples’, [TMixedComponent]);
end;

function TMixedFileNameProperty.AllEqual: boolean;
var
  FirstVal: string;
  i: Integer;
begin
  FirstVal := GetStrValue;
  Result := True;
  i := 1;
  while Result and (i < PropCount) do
  begin
    Result := Result and (GetStrValueAt(i) = FirstVal);
    Inc(i);
  end;
end;

procedure TMixedFileNameProperty.Edit;
var
  Dlg: TOpenDialog;
begin
  Dlg := TOpenDialog.Create(Application);
  try
    with Dlg do
    begin
      Title := ’File for ’ + TComponent(GetComponent(0)).Name;
      FileName:= Value;
      if Execute then Value := FileName;
    end;
  finally
    FreeAndNil(Dlg);
  end
end;

function TMixedFileNameProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paDialog]
end;

function TMixedFileNameProperty.GetValue: string;
begin
  Result := GetStrValue;
end;

procedure TMixedFileNameProperty.SetValue(const Value: string);
begin
  SetStrValue(Value);
end;

end.

  剩下的就是编译和安装设计时包了。现在运行时代码已经完全从设计时代码中分了出来。这是一个简单的例子,它唯一有点复杂的是属性编辑器使用一个窗体获得数据,而且那个窗体在运行时也可以利用。在这种情况下,窗体被保留在运行时包里,设计时属性编辑器会从运行时包里调用这个窗体。
 
原创粉丝点击