创建自定义TSetProperty属性编辑器 [英] Creating custom TSetProperty property editor

查看:95
本文介绍了创建自定义TSetProperty属性编辑器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为某些自定义组件创建自定义属性编辑器。自定义属性编辑器旨在编辑某些集合属性,例如

I'm trying to create a custom property editor for some custom component. The custom property editor is intended to edit some set property, like

type
  TButtonOption = (boOption1, boOption2, boOption3);
  TButtonOptions = set of TButtonOption;

我的属性编辑器来自TSetProperty类。问题是:我的自定义属性编辑器未注册,Delphi IDE似乎使用了它自己的默认集合属性编辑器,因为属性编辑器方法内部的ShowMessage()调用永远不会执行!我已经从头开始创建了一个示例程序包/组件,它尽可能简单,以显示此问题。这是代码:

my property editor descends from TSetProperty class. The problem is: my custom property editor doesn't get registered and Delphi IDE seems to use its own default set property editor, because ShowMessage() calls inside property editor methods never executes! I've created a sample package/component from scratch, as simple as possible, showing this issue. Here is the code:

unit Button1;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls, DesignIntf, DesignEditors;

type
  TButtonOption = (boOption1, boOption2, boOption3);

  TButtonOptions = set of TButtonOption;

  TButtonEx = class(TButton)
  private
    FOptions: TButtonOptions;
    function GetOptions: TButtonOptions;
    procedure SetOptions(Value: TButtonOptions);
  published
    property Options: TButtonOptions read GetOptions write SetOptions default [];
  end;

  TMySetProperty = class(TSetProperty)
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetProperties(Proc: TGetPropProc); override;
    function GetValue: string; override;
  end;

procedure Register;

implementation

uses
  Dialogs;

// TButtonEx - sample component

function TButtonEx.GetOptions: TButtonOptions;
begin
  Result := FOptions;
end;

procedure TButtonEx.SetOptions(Value: TButtonOptions);
begin
  if FOptions <> Value then
  begin
    FOptions := Value;
  end;
end;

// register stuff

procedure Register;
begin
  RegisterComponents('Samples', [TButtonEx]);
  RegisterPropertyEditor(TypeInfo(TButtonOptions), nil, '', TMySetProperty);
end;

function TMySetProperty.GetAttributes: TPropertyAttributes;
begin
  ShowMessage('GetAttributes');
  Result := inherited GetAttributes;
end;

procedure TMySetProperty.GetProperties(Proc: TGetPropProc);
begin
  ShowMessage('GetProperties');
  inherited;
end;

function TMySetProperty.GetValue: string;
begin
  ShowMessage('GetValue');
  Result := inherited GetValue;
end;

end.

请注意:


  1. 我正在为具有TButtonOptions属性的所有组件注册新的属性编辑器(TMySetProperty)。我也尝试只对TButtonEx这样做,但是结果是一样的。

  2. 我已经在自定义属性编辑器的所有重写方法中添加了ShowMessage()调用,而这些方法从未获得

  3. 我已经调试了程序包并执行RegisterPropertyEditor()。尽管如此,我在覆盖方法中的自定义代码却永远不会执行。代码差异。

所以问题是:
为什么我的自定义属性编辑器无法注册/工作?

So the question is: Why my custom property editor does not register/work?

注意:至少在Delphi XE2,XE3,XE4和XE5中会发生此问题。其他IDE尚未经过测试,但可能具有相同的行为。

Note: This issue happens in Delphi XE2, XE3, XE4 and also XE5 at least. Other IDEs were not tested but probably have the same behavior.

推荐答案

最后,我得到了一个解决方案...经过测试,我可以想象-没有成功-我开始在DesignEditors.pas和DesignIntf​​.pas单元中搜索新内容。通过阅读GetEditorClass()函数,我发现它首先检查了PropertyMapper。可以使用RegisterPropertyMapper()函数注册属性映射器。使用它代替RegisterPropertyEditor()可以按预期工作。这是我修改后的有效代码,还显示了一些有趣的应用程序:根据一些条件显示或隐藏基于集合的属性的一些选项:

Finally I got a solution... After testing everything I could imagine - without success - I started searching for something "new" in DesignEditors.pas and DesignIntf.pas units. Reading GetEditorClass() function, I discovered that it first checks for a PropertyMapper. A property mapper can be registered using RegisterPropertyMapper() function. Using it instead of RegisterPropertyEditor() works just as expected. Here is my modified, working code, also showing some interesting application for this: show or hide some options of my set-based property, based on some criteria:

unit Button1;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls,
  DesignIntf, DesignEditors;

type
  TButtonOption = (boOptionA, boOptionB, boOptionC);
  TButtonOptions = set of TButtonOption;

type
  TButtonEx = class(TButton)
  private
    FOptions: TButtonOptions;
    function GetOptions: TButtonOptions;
    procedure SetOptions(Value: TButtonOptions);
  published
    property Options: TButtonOptions read GetOptions write SetOptions default [];
  end;

  TMySetProperty = class(TSetProperty)
  private
    FProc: TGetPropProc;
    procedure InternalGetProperty(const Prop: IProperty);
  public
    procedure GetProperties(Proc: TGetPropProc); override;
  end;

procedure Register;

implementation

uses
  TypInfo;

// TButtonEx - sample component

function TButtonEx.GetOptions: TButtonOptions;
begin
  Result := FOptions;
end;

procedure TButtonEx.SetOptions(Value: TButtonOptions);
begin
  if FOptions <> Value then
  begin
    FOptions := Value;
  end;
end;

// Returns TMySetProperty as the property editor used for Options in TButtonEx class
function MyCustomPropMapper(Obj: TPersistent; PropInfo: PPropInfo): TPropertyEditorClass;
begin
  Result := nil;
  if Assigned(Obj) and (Obj is TButtonEx) and SameText(String(PropInfo.Name), 'Options') then begin
    Result := TMySetProperty;
  end;
end;

procedure Register;
begin
  RegisterComponents('Samples', [TButtonEx]);
  // RegisterPropertyEditor does not work for set-based properties.
  // We use RegisterPropertyMapper instead
  RegisterPropertyMapper(MyCustomPropMapper);
end;

procedure TMySetProperty.GetProperties(Proc: TGetPropProc);
begin
  // Save the original method received
  FProc := Proc;
  // Call inherited, but passing our internal method as parameter
  inherited GetProperties(InternalGetProperty);
end;

procedure TMySetProperty.InternalGetProperty(const Prop: IProperty);
var
  i: Integer;
begin
  if not Assigned(FProc) then begin   // just in case
    Exit;
  end;

  // Now the interesting stuff. I just want to show boOptionA and boOptionB in Object inspector
  // So I call the original Proc in those cases only
  // boOptionC still exists, but won't be visible in object inspector
  for i := 0 to PropCount - 1 do begin
    if SameText(Prop.GetName, 'boOptionA') or SameText(Prop.GetName, 'boOptionB') then begin
      FProc(Prop);       // call original method
    end;
  end;
end;

end.

这篇关于创建自定义TSetProperty属性编辑器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆