如何在对象检查器中对我的组件属性进行分组?

7
我希望我的非可视组件的公开属性能够在对象检查器中以类别的形式出现,而不是出现在顶层。
以下是一个例子: enter image description here
type
  TMyComponent = class(TComponent)
  protected
    function GetSomeValue: string;
    function GetSomeValueExt: string;
  published
    property SomeValue: string read GetSomeValue;
    property SomeValueExt: string read GetSomeValueExt;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('My Component', [TMyComponent]);
end;

function TMyComponent.GetSomeValue: string;
begin
  Result := 'test';
end;

function TMyComponent.GetSomeValueExt: string;
begin
  Result := 'extended..';
end;

如何使我的组件在对象检查器中注册,以便在名为类似MyProperties的类别下具有SomeValue和SomeValueExt?
示例如下: enter image description here 我的组件可能会有很多已发布的属性,我宁愿让它们放在对象检查器的自己级别的子类别中,以使其远离常见属性,例如名称和标记。
谢谢 :)

你是在说对象检查器中使用的“类别”术语吗?这是一项功能,您可以右键单击OI并选择“按类别查看”。 - David Heffernan
“Anchors”和“BorderIcons”是集合。你不想要那个。 “Font”属性是一个类。因此,您可以将子属性包装在一个类中,然后免费获得所需的行为。 - David Heffernan
@Blobby 是的,没错。我相信一个已发布的作为类的属性将会按照您所期望的方式在对象浏览器中呈现。 - David Heffernan
@Blobby,是的。同时,RegisterPropertiesInCategory 是另一种解释的答案 :-) - OnTheFly
谢谢@user539484,我会查看RegisterPropertiesInCategory,它可能在帮助文件中 :) - user1175743
显示剩余6条评论
1个回答

17
创建一个具有这些属性的类,并为您的组件提供一个单一的该类类型的属性。该属性类应该是TPersistent的后代类:
type
  TComponentProperties = class(TPersistent)
  private
    function GetSomeValue: string;
    function GetSomeValueExt: string;
  published
    property SomeValue: string read GetSomeValue;
    property SomeValueExt: string read GetSomeValueExt;
  end;

  TMyComponent = class(TComponent)
  private
    FProperties: TComponentProperties;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Properties: TComponentProperties read FProperties;
  end;
组件拥有其属性对象,因此它需要被创建和销毁:
constructor TMyComponent.Create;
begin
  inherited;
  FProperties := TComponentProperties.Create;
end;

destructor TMyComponent.Destroy;
begin
  FProperties.Free;
  inherited;
end;

通过这段代码,该组件的属性应该现在列在“属性”项下。不过这不是一个类别。类别完全是另外一回事。类别不会重新排列组件;它们只是改变了属性在对象检视器中的显示方式。请注意,使用我的代码后,TMyComponent不再具有任何SomeValue属性。相反,它只有一个名为Properties的属性,并且该对象还有其他属性。请考虑一下,消费者需要通过这种方式访问您的组件是否真的合适。


如果Properties属性不是只读的,则需要设置属性设置器;您不能直接写入FProperties。请按照以下方式编写:

procedure TMyComponent.SetProperties(const Value: TProperties);
begin
  FProperties.Assign(Value);
end;

同时这也需要你重写Assign方法以保证正确性:

procedure TComponentProperties.Assign(Other: TPersistent);
begin
  if Other is TComponentProperties then begin
    SomeValue := TComponentProperties(Other).SomeValue;
    SomeValueEx := TComponentProperties(Other).SomeValueEx;
  end else
    inherited;
end;

我们还假设属性对象的属性也不是只读的。当属性对象的属性发生变化时,拥有它的对象可能想要知道这一点,因此它应该拥有一个由组件赋值的事件。当属性发生变化时,它们将触发该事件。


谢谢提供这些信息,我有一种感觉分类可能不是最好的解释方式。我个人使用Delphi,所以不会有其他人使用我的组件,但如果将来有人使用它,考虑这一点总是值得的。谢谢 :) - user1175743
1
当我说“你的组件的使用者”时,这个“你”也是其中之一。你想一直输入 Properties.SomeValue 吗? - Rob Kennedy
如果我没记错,在 constructor TMyComponent.Create; 中的 SetSubcomponent(FProperties); 行也是必需的。 - mjn
1
我怀疑,@Mjn。它不是一个组件。而且,如果需要的话,退休是新的;Delphi 2005 不需要那个。 - Rob Kennedy
@mjn Rob的疑虑是有根据的。正如名称所示,这仅适用于子组件。根据子属性的类型和深度,您可能需要实现GetOwner - NGLN
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接