当前位置: 首页 > 工具软件 > VCL > 使用案例 >

VCL (三) 属性编辑器

韩朝斑
2023-12-01

Delphi的属性是一个很有特色的功能,这一特性在C#里得到了很好的继承。
对于一个类来说,属性是对类中的数据进行有效修改和访问的特殊接口。在VCL中,被published
的属性还有一个特性,就是可以在界面设计过程中对属性进行设置.
属性的类型
数字、字符、布尔、枚举、TStrings、集合,类对象或者接口类型等
示例:
TEnumTest=(etNone,etTestInt,etTestString);
TTestcontrol=class(TCustomControl)
 private
   FInt : integer;
   FEnumTest :TEnumTest;
   FCaption :string;

  function GetInt :Integer;
  funtion GetEnumTest:TEnumTest;
  function Caption:String;

  procedure SetCatpion(AValue:String);
  procedure SetInt(AValue:Integer);
  procedure SetEnumTest(AValue:String);
published
   property IntProp :Integer read GetInt write SetInt;
   property EnumTest:TEnumTest read GetEnumTest write SetEnumTest;
   property Caption:String read FCaption write SetCaption;
end;
  
read 和 write 指令指定了访问属性的有效方法,在这些方法里可以实现对属性的访问封装。

写VCL控件最重要的就是属性编写,属性编辑器又是其中的难点。
属性编辑器一般有数字、字符串、集合、类、Color、Font类型编辑器,Delphi内建基本编辑器声明有
TPropertyEditor 所有的属性编辑器都必须继承于此或他的派生类
TOrdinalProperty 这是几个有序属性编辑器的基类,如TIntegerProperty TCharProperty TEnumProperty
TIntegerProperty 适用编辑整型属性
TCharProperty 适用编辑字符型属性
TEnumProperty 适用编辑枚举型属性
TBoolProperty 适用编辑布尔型属性
TFloatProperty 适用编辑浮点型属性
TStringProperty 适用编辑字符串型属性
TClassProperty 适用编辑对象类型
TComponentProperty 使用编辑引用一个组件属性
TSetProperty 适用编辑集合类型
上述可以查看DesignEditors.pas单元(Delphi7)
对于一些基本数据类型有时并不需要创建属性编辑器,因为数据类型本身也会数据进行检查,
在当你有特殊的检查时,你可以从上述基本编辑器派生出自己的属性编辑器

对话框型属性编辑器的编写
定义一个正对字符型属性编辑的对话框界面,在界面上放一个memo, 一个Label, 三个按钮
代码如下
unit uStringEditor;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons,DesignIntf,DesignEditors;

type
  //对话框属窗体类
  TMyStringEditDlg = class(TForm)
    Memo: TMemo;
    OkButton: TBitBtn;
    CancelButton: TBitBtn;
    Label1: TLabel;
    BitBtn1: TBitBtn;
    procedure MemoKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure UpdateStatus(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private declarations }
    FModified: Boolean;

  protected
    function GetLines: TStrings;
    procedure SetLines(const Value: TStrings);
    function GetLinesControl: TWinControl;
  public
    { Public declarations }
    property Lines: TStrings read GetLines write SetLines;
  end;
   
   //对话框属性编辑器
    TMyStringProperty = class(TStringProperty)
    protected
      function EditDialog: TMyStringEditDlg; virtual;
    public
      procedure Edit; override;
      function GetAttributes: TPropertyAttributes; override;
    end;

var
  MyStringEditDlg: TMyStringEditDlg;

implementation
{$R *.dfm}
const                                   //v1.73 19/08/2000)
  CopyRightStr: PChar = 'String Editor v1.0 (12/06/2003)'+#13+#13+
    'Created By Donson Wan '#13+#13+   
    'Compiled in '+
    {$IFDEF VER80}  'Delphi 1.0' {$ENDIF}
    {$IFDEF VER90}  'Delphi 2.0' {$ENDIF}
    {$IFDEF VER100} 'Delphi 3.0' {$ENDIF}
    {$IFDEF VER120} 'Delphi 4.0' {$ENDIF}
    {$IFDEF VER130} 'Delphi 5.0' {$ENDIF}
    {$IFDEF VER140} 'Delphi 6.0' {$ENDIF}
    {$IFDEF VER150} 'Delphi 7.0' {$ENDIF}
    {$IFDEF VER93}  'C++Builder 1.0' {$ENDIF}
    {$IFDEF VER110} 'C++Builder 3.0' {$ENDIF}
    {$IFDEF VER125} 'C++Builder 4.0' {$ENDIF};

var
  StoredWidth, StoredHeight, StoredLeft, StoredTop: Integer;


function TMyStringEditDlg.GetLines: TStrings;
begin
  Result:=Memo.Lines;
end;

function TMyStringEditDlg.GetLinesControl: TWinControl;
begin

end;

procedure TMyStringEditDlg.MemoKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_ESCAPE then CancelButton.Click;
end;

procedure TMyStringEditDlg.SetLines(const Value: TStrings);
begin
  inherited;
  Memo.Lines.Assign(Value);
end;

procedure TMyStringEditDlg.FormDestroy(Sender: TObject);
begin
  StoredWidth := Width;
  StoredHeight := Height;
  StoredLeft := Left;
  StoredTop := Top;
end;

procedure TMyStringEditDlg.FormShow(Sender: TObject);
begin
  if StoredWidth <> 0 then
    Width := StoredWidth;
  if StoredHeight <> 0 then
    Height := StoredHeight;
  if StoredLeft <> 0 then
    Left := StoredLeft
  else
    Left := (Screen.Width - Width) div 2;
  if StoredTop <> 0 then
    Top := StoredTop
  else
    Top := (Screen.Height - Height) div 2;
end;

procedure TMyStringEditDlg.UpdateStatus(Sender: TObject);
begin
  if Sender = Memo then FModified := True;
end;
{ TMyStringProperty }

procedure TMyStringProperty.Edit;
begin
  inherited;
  with EditDialog do
  try
    Lines.Text := GetValue;
    FModified:=False;
    UpdateStatus(nil);
    //ActiveControl := GetLinesControl;
    case ShowModal of
      mrOk: begin
            SetValue(Lines.Text);
            //Designer.Modified;
            end;
    end;
  finally
    Free;
  end;
end;

function TMyStringProperty.EditDialog: TMyStringEditDlg;
begin
  Result := TMyStringEditDlg.Create(Application);
end;

function TMyStringProperty.GetAttributes: TPropertyAttributes;
begin
  Result := inherited GetAttributes + [paDialog] - [paSubProperties];
end;

procedure TMyStringEditDlg.BitBtn1Click(Sender: TObject);
begin
      MessageDlg(StrPas(CopyRightStr), mtInformation, [mbOk], 0);

end;

end.

可以用上述编辑器注册给TTestcontrol.Caption 属性
注册属性编辑器的声明为
RegisterPropertyEditor(PropertyType:PTypeInfo;
ComponentClass: Tclass;Const PropertyName:String;
EditorClass: TPropertyEditorClass);

RegisterPropertyEditor(TypeInfo(string), TTestcontrol, 'Caption',  TMyStringProperty);
如上就注册成功了,
参数1是Typeinfo(string)是取得属性运行时刻属性类型信息,
参数2是指定注册控件对象,如果不指定控件对象就注册给Delphi所有控件了, 这样你往界面上拉一个Label时,
原来不能写多行文本时现在也解决了,现在你可以在弹出属性编辑器里输,可以任意行:)

参数3是指定注册属性名
参数4就是你需要注册的属性编辑器类名了

另外还可以给你注册的属性加一个归类CategoryName,我们把上述Caption属性指定为MyCategory型属性,注册示例如

下:RegisterPropertiesInCategory('MyCategory', TTestcontrol, ['Caption']);

 类似资料: