我在D6下用下面的方法,搞好了一个控件,你可以试一下 维一有点混惑的地方是:属或组件是否使用了一个窗体。假如这个窗体在运行时对于组件是可用的,那么它应该包含在运行时包里。如果它只是在设计时可使用,那它就应该包含在设计时包里。一个常见的错误是误认这个窗体本身是一个编辑器,但事实上它不是。而是组件编辑器调用了这个窗体,它是设计时编辑器。 你应该养成一个把组件分开成两个包的习惯,即使是你只在程序中静态地进行链接,因为混合运行时和设计时代码将使你的代码膨胀。你的设计时代码在运行时不会被执行,但是链接器不会知道,所以把它也一起链接进去了。(这就是为什么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;implementationprocedure 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;interfaceuses 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;implementationend. 这最后一步就是把你的组件和它的属性编辑器编译到一个设计时包中,然后安装到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;interfaceuses 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;implementationuses 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. 剩下的就是编译和安装设计时包了。现在运行时代码已经完全从设计时代码中分了出来。这是一个简单的例子,它唯一有点复杂的是属性编辑器使用一个窗体获得数据,而且那个窗体在运行时也可以利用。在这种情况下,窗体被保留在运行时包里,设计时属性编辑器会从运行时包里调用这个窗体。
to: wolf2005() 多谢你的回答,可是我水平太低,没太明白你的具体做法。我提供组件下载地址,麻烦你试着装一下,好吗? 下载地址http://www.8421.org/download.php?id=146&down=1,是一个可以获取详细的机器信息的组件,其中只有一个pas和dcr文件,没有打包文件。如果你能帮我看看这个组件怎么安装,小弟不胜感激!!
外你还得将designide加入到你的包的Requires的列表中。另外,对dsnide50的引用可能得手动改为DesignIde,如果Delphi没有自动更改的话。 任何引用了IDesigner的运行期包,需要改为IDesignerHook以防止运行期时对于designide单元的引用要求。在运行期代码中,IDesignerHook 功能足够使用,
无需担心。设计期时可以使用IDesigner,如以下代码一样:var RealDesigner: IDesigner;
...SomeDesignerHook.QueryInterface(IDesigner,RealDesigner);...来获得IDesignerHook 提供的IDesigner的接口。IDesinerHook的使用只需要引用Classes和Forms两个单元。但是IDesigner还得加上DesignIntf单元
,由于该单元被包含在许多其它包中,而其中的一些包可能是不能二次分发的。也就是说,它是用于设计阶段的。在D5是用dsgnitf.dcu.D6则有改变。
在delphi5中,用windows的查找功能,查找DsgnIntf.pas ,将这个文件拷入delphi5\lib目录即可,
也可以建一个工程,将DsgnIntf.pas这个单元编译到delphi5\lib目录中在delphi6中,用windows的查找功能,查找DesignIntf.pas (注意:d6将DsgnIntf.pas 改名为
DesignIntf.pas了) ,将这个文件改名为DsgnIntf.pas , 同时打开这个单元将单元名从
unit DesignIntf 改为unit DsgnIntf, 最后拷入delphi6\lib目录即可;
也可以建一个工程,将DsgnIntf.pas这个单元编译到delphi6\lib目录中。不一定,大多数情况下是可行的,但也有例外,也自己试一下。
DesignIntf.pas了) ,将这个文件改名为DsgnIntf.pas , 同时打开这个单元将单元名从
unit DesignIntf 改为unit DsgnIntf, 最后拷入delphi6(7)\lib目录即可;”)
不再报告找不到dsgnintf了。但是却出现了一大堆别的错误:)我是在装一个组件时出现这个问题的,下载地址http://www.8421.org/download.php?id=146&down=1,是一个可以获取详细的机器信息的组件,其中只有一个pas和dcr文件,没有打包文件。如果你能帮我看看这个组件怎么安装,小弟不胜感激!!
对于在D5开发的从TComponentEditor派生的控件,要到D6下使用,需要经过以下
几个步骤:
1、添加 lib\designide.dcp到控件的dpk文件的requires部分
2、在控件的pas源文件中凡是uses DsgnIntf的地方改成uses DesignIntf, DesignEdit
ors
为保证控件可以同时在D5和D6中使用,可以采用条件编译:
uses
{$IFDEF VER140}
DesignIntf, DesignEditors,
{$ELSE}
DsgnIntf,
{$ENDIF}
维一有点混惑的地方是:属或组件是否使用了一个窗体。假如这个窗体在运行时对于组件是可用的,那么它应该包含在运行时包里。如果它只是在设计时可使用,那它就应该包含在设计时包里。一个常见的错误是误认这个窗体本身是一个编辑器,但事实上它不是。而是组件编辑器调用了这个窗体,它是设计时编辑器。 你应该养成一个把组件分开成两个包的习惯,即使是你只在程序中静态地进行链接,因为混合运行时和设计时代码将使你的代码膨胀。你的设计时代码在运行时不会被执行,但是链接器不会知道,所以把它也一起链接进去了。(这就是为什么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;implementationprocedure 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;interfaceuses
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;implementationend. 这最后一步就是把你的组件和它的属性编辑器编译到一个设计时包中,然后安装到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;interfaceuses 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;implementationuses 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. 剩下的就是编译和安装设计时包了。现在运行时代码已经完全从设计时代码中分了出来。这是一个简单的例子,它唯一有点复杂的是属性编辑器使用一个窗体获得数据,而且那个窗体在运行时也可以利用。在这种情况下,窗体被保留在运行时包里,设计时属性编辑器会从运行时包里调用这个窗体。
多谢你的回答,可是我水平太低,没太明白你的具体做法。我提供组件下载地址,麻烦你试着装一下,好吗?
下载地址http://www.8421.org/download.php?id=146&down=1,是一个可以获取详细的机器信息的组件,其中只有一个pas和dcr文件,没有打包文件。如果你能帮我看看这个组件怎么安装,小弟不胜感激!!