创建自定义 TSetProperty 属性编辑器

2023-11-27

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

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

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

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() 执行了。尽管如此,我在重写方法中的自定义代码永远不会执行。
  4. 我见过其他 3rd 方组件使用此类属性编辑器(TSetProperty 后代)在较旧的 Delphi IDE 中运行,但我在代码中找不到任何相关差异。也许 Delphi XE2+ 还需要其他东西?

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

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


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

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.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建自定义 TSetProperty 属性编辑器 的相关文章

  • Delphi XE 和 OmniXML:使用 SelectNode()?

    我将以下 XML 片段作为一个更大的 XML 文件的一部分 我正在使用最新的 OmniXML 快照进行处理
  • 在 Delphi 中,我的 DLL 中是否必须分配函数的返回 pchar

    我有一个 DLL 其中有一个返回 pchar 的函数 以避免必须使用 borlndmm 我最初所做的是将字符串转换为 pchar 并返回 Result pChar SomeFuncThatReturnsString 但 90 的情况下我都能
  • 以高效的方式将字符串转换为十六进制

    我开发了以下函数将字符串转换为十六进制值 function StrToHex const S String String const HexDigits array 0 15 of Char 0123456789ABCDEF var I I
  • delphi检查ini文件是否存在

    如何检查 INI 文件是否存在 在特定路径和特定名称下 比如这样 if FileExists c yourinifile ini then ShowMessage c yourinifile ini exists
  • 在 Inno Setup 中使用 StringToColor

    我想为表单上的标签 TNewStaticText 属性颜色 TColor 读写 分配一些颜色 我将颜色存储为 RRGGBB 字符串 我想使用 Delphi 函数 StringToColor 将其转换为 TColor 但如果我在脚本中使用此函
  • delphi定时器比定时器服务中断例程更快

    大家好 我被要求为某人维护一个基于 Delphi 5 的程序 该程序使用一个计时器对象每 50 毫秒计时一次 并且在每次计时结束时运行单线程代码块 我只是想知道 如果执行这段代码所花费的时间比计时器滴答间隔长 会发生什么 这会很糟糕吗 例如
  • 如何更改 Chromium 组件的默认背景颜色?

    I use TChromium http code google com p delphichromiumembedded 我分配AWebPageAsString这是一个带有灰色背景颜色的静态 HTML 页面 FBrowser TChrom
  • 如何更新Delphi对象检查器?

    继我最近发布的这个问题之后 组件编辑器可以在多个组件上执行吗 https stackoverflow com questions 14802371 can a component editor be executed on multiple
  • Delphi (Indy) TIdTCPClient 在线程中

    在互联网上 我看到通常将 TIdTCPClient 放置在自定义 TThread 后代中 为什么要这样做 有时我也在这样的线程中看到服务器 为什么 干杯 阿德里安 Indy 使用阻塞 I O 最好在线程中处理 这是 Indy 整体设计的核心
  • 在运行时创建 TQReport 元素

    在运行时创建 TQReport 元素 嗯 至少尝试一下 我不知道这份报告中应出现哪些标题或数据 我得到一个代表数据行和列的 TString 的 TList 我在组的带打印事件中植入 创建 指令 并在主数据行带的 OnNeedData 事件中
  • 如何确保 FormClose 程序运行,无论程序如何退出?

    在 Delphi 7 中 我有一个 TMainForm FormClose 过程 旨在在程序退出时写出一些状态 这在手动关闭程序时效果很好 但是 我发现如果程序被 Windows 强制 退出 例如在 Windows 更新后需要重新启动 则不
  • 加载 Jpg/Gif/Bitmap 并转换为 Bitmap

    我必须从 XML 文件加载图像 XML 文件中没有关于图像是否为 JPG GIF BMP 的信息 加载图像后 我需要将其转换为位图 有谁知道如何在不知道实际文件格式的情况下将图像转换为位图 我正在使用 Delphi 2007 2009 谢谢
  • 在运行时按需更改组件类

    我的问题与这里的想法类似 替换delphi中的组件类 https stackoverflow com q 4685863 937125 但我需要改变一个specific按需组件类 这是一些伪演示代码 unit Unit1 TForm1 cl
  • Delphi - 自XE8以来如何正确注册图形类?

    我正在编写一个 Delphi 包 它提供了一个新的自定义 TGraphic 对象 允许读取 VCL 组件 如 TImage 中的新图像格式 我最初使用 RAD Studio XE7 开发了这个包 并且运行良好 然而 我最近迁移到了较新的 R
  • Delphi - 在修复 VCL 错误时,单元 x 是用不同版本的 x 编译的

    我正在使用 Delphi XE6 并在我的项目中使用 Datasnap 和 JSON 我想纠正 VCL 单元 System JSON pas 在 TJSONString ToString 函数中 中的一个错误 它应该转义反斜杠字符和引号 为
  • 如何将 REST API 与 FireMonkey 结合使用?

    我需要在 FireMonkey 中实现 REST API 来获取一些信息 但我不确定如何做到这一点 REST API使用OAuth2 我可以访问两个代码 Consumer Key和Consumer Secret 之后 我需要获得一个临时的
  • 我如何在Delphi中处理事件?

    例如 我有一个程序 在单击 Button1 后执行某些操作 如果没有 Button1Click 中的代码 如何处理按钮的 onclick 事件 我需要为 Button1 动态添加事件 unit Unit1 interface uses Wi
  • 有人用CrossKylix进行真正的跨平台开发吗?

    新版本克罗斯凯利克斯 http crosskylix untergrund net 两周前更新过 即使 Kylix 已经停产很久了 但它似乎仍然被一些 Delphi 开发人员使用 有人在 Windows 和 Linux 的跨平台开发中成功使
  • Delphi 返回 TList 时出错

    我做了一个非常简单的应用程序 但我有一个我真的无法理解的问题 看一下这个基本代码 unit Unit1 interface uses Winapi Windows Winapi Messages System SysUtils System
  • 处理 TShellListView 后代中的文件放置

    我正在尝试创建 TShellListView 的后代 它接受从 Windows 资源管理器中删除的文件 我想在组件定义中处理拖 放操作 而不必在任何使用该组件的应用程序中实现它 我找到了接受从 Windows 资源管理器中拖放的文件的示例

随机推荐