如何为具有最小/最大值的整数编写属性编辑器?

发布于 2024-09-15 04:53:07 字数 6159 浏览 1 评论 0原文

编辑:下面是原始问题,但我现在修改了它,因为我有一些代码要发布......

我创建了一个编辑框,它只接受整数作为输入。我没有使用 TMaskEDit,因为我想从中派生出许多其他类型(仅接受浮点数,以及具有最小/最大属性的浮点数和整数)。

这是我的代码。我认为问题是我的属性编辑器 SetValue() 从未被调用,所以也许我没有正确注册它?

unit IntegerEditBoxMinMax;
  // An edit box which only accepts integer values between the stated mix/max values

interface

uses
  SysUtils, Classes, Controls, StdCtrls, DesignEditors;

type

  TMinimumProperty = class(TIntegerProperty)
    procedure SetValue(const newValue: string); override;
  end;  

  TMaximumProperty = class(TIntegerProperty)
    procedure SetValue(const newValue: string); override;
  end;  

  TValueProperty = class(TIntegerProperty)
    procedure SetValue(const newValue: string); override;
  end; 


  TIntegerEditBoxMinMax = class(TCustomEdit)
    private
      FMinimum : Integer;
      FMaximum : Integer;
      FValue   : Integer;

    published  { Published declarations - available in the Object Inspector at design-time }
      property Minimum  : Integer read FMinimum write FMinimum;
      property Maximum  : Integer read FMaximum write FMaximum;
      property Value    : Integer read FValue   write FValue;

  end;  // of class TIntegerEditBoxMinMax()

procedure Register;

implementation

Uses TypInfo, Consts, DesignIntf, Dialogs;

  procedure Register;
  begin
    RegisterComponents('Standard', [TIntegerEditBoxMinMax]);
    RegisterPropertyEditor(TypeInfo(Integer), TIntegerEditBoxMinMax, 'Minumim', TMinimumProperty);
    RegisterPropertyEditor(TypeInfo(Integer), TIntegerEditBoxMinMax, 'Maximum', TMaximumProperty);
    RegisterPropertyEditor(TypeInfo(Integer), TIntegerEditBoxMinMax, 'Value',   TValueProperty);
  end;

  procedure TMinimumProperty.SetValue(const newValue: string);
    var L: Longint;
        min, max : Integer;
        propInfo: PPropInfo;
        exceptionString : String;
  begin
MessageDlg('editor !!', mtWarning, [mbOK], 0);   // This is never seen !!
    L := StrToInt(newValue);                { convert string to number }
    with GetTypeData(GetPropType())^ do     { this uses compiler data for type Integer }
      min  := GetOrdProp(GetComponent(0), 'Minimum');
      max  := GetOrdProp(GetComponent(0), 'Maximum');

      if min > max then
      begin
        exceptionString := 'Minimum value (%l) cannot be greater than maximum (%l)';
        raise Exception.CreateResFmt(@exceptionString, [min, max]);
      end;

      if L < min then
      begin
        PropInfo := GetPropInfo();
        SetOrdProp(Nil , propInfo, Int64(min));
        exceptionString := 'Value (%l) less than new minimum (%l); value set to minimum';
        raise Exception.CreateResFmt(@exceptionString, [L, min]);
      end;

    SetOrdValue(L);                                { if in range, go ahead and set value }
  end;  // of TMinimumProperty.SetValue()


  procedure TMaximumProperty.SetValue(const newValue: string);
    var L: Longint;
        min, max : Integer;
        propInfo: PPropInfo;
        exceptionString : String;
  begin
    L := StrToInt(newValue);                { convert string to number }
    with GetTypeData(GetPropType())^ do     { this uses compiler data for type Integer }
      min  := GetOrdProp(Nil, 'Minimum');
      max  := GetOrdProp(Nil, 'Maximum');

      if max < min then
      begin
        exceptionString := 'Maximum value (%l) cannot be less than minimum (%l)';
        raise Exception.CreateResFmt(@exceptionString, [max, min]);
      end;

      if L > max then
      begin
        PropInfo := GetPropInfo();
        SetOrdProp(Nil , propInfo, Int64(max));
        exceptionString := 'Value (%l) more than new maximum (%l); value set to maximum';
        raise Exception.CreateResFmt(@exceptionString, [L, max]);
      end;

    SetOrdValue(L);      { if in range, go ahead and set value }
  end;  // of TMaximumProperty.SetValue()


  procedure TValueProperty.SetValue(const newValue: string);
    var L: Longint;
        min, max: Integer;
  begin
    L := StrToInt(newValue);             { convert string to number }
    // see also http://www.freepascal.org/docs-html/rtl/typinfo/getobjectprop.html
    // for other useful functions
    with GetTypeData(GetPropType())^ do  { this uses compiler data for type Integer }
    begin
      min := GetOrdProp(Nil, 'Minimum');
      max := GetOrdProp(Nil, 'Maximum');
      // for Float, etc, see http://www.blong.com/Conferences/BorConUK98/DelphiRTTI/CB140.htm

      if (L < min) or (L > max) then              { make sure it's in range... }
        raise Exception.CreateResFmt(@SOutOfRange, [min, max]);   { ...otherwise, raise exception }

      SetOrdValue(L);    { if in range, go ahead and set value }
    end;
  end;  // of TMinimumProperty.SetValue()


end.

原始问题:

此链接给出了一个很好的例子整数属性的属性编辑器。

我怎样才能改变这个方法......

procedure TIntegerProperty.SetValue(const Value: string);
var
  L: Longint;
begin
  L := StrToInt(Value);                      { convert string to number }
  with GetTypeData(GetPropType)^ do  { this uses compiler data for type Integer }
    if (L < MinValue) or (L > MaxValue) then { make sure it is in range }
      { otherwise, raise exception }
      raise EPropertyError.Create(FmtLoadStr(SOutOfRange, [MinValue, MaxValue]));
  SetOrdValue(L);                       { if in range, go ahead and set value }
end;

我想要的是男性一个新的属性,比如TIntegerMinMaxProperty,派生自TIntegerProperty,其中组件编辑器还显示最小值和整数的最大允许值。

我正在考虑添加两个新的整数属性,称为“最小值”和“最小值”。最大值,但看起来我可以使用现有的 MinValue & MaxValue 如果我只能发布它们,但我不知道如何...这些都不能编译

published  { available in the Object Inspector at design-time }
  property Minimum : Longint read  MinValue write  MinValue;
  property Minimum : Longint read FMinValue write FMinValue;

所以看起来我有两个选择并且都陷入了困境:-/

1)找到一种方法来发布那些 MinValue 和 MaxValue 。 MaxValue 属性(可能更清晰) 2)发布2个新属性,Minimujm &最大并计算如何在 TIntegerProperty.SetValu() 中引用它们

,并感谢您的帮助,因为这是我第一次涉足属性编辑器(如果它有助于影响这个问题的答案,我的下一个属性将是接受十进制输入的属性, aa点)

Edit: original question below, but I revise it now that I have some code to post....

I am created an editbox which only accepts an integer as input. I didn't use a TMaskEDit because I want to derive a bunch of others from it (only accepts float, and both float & integer with min/max properties).

Here's my code. I think the problem is that my property editor SetValue() is never being called, so maybe I haven't registered it correctly?

unit IntegerEditBoxMinMax;
  // An edit box which only accepts integer values between the stated mix/max values

interface

uses
  SysUtils, Classes, Controls, StdCtrls, DesignEditors;

type

  TMinimumProperty = class(TIntegerProperty)
    procedure SetValue(const newValue: string); override;
  end;  

  TMaximumProperty = class(TIntegerProperty)
    procedure SetValue(const newValue: string); override;
  end;  

  TValueProperty = class(TIntegerProperty)
    procedure SetValue(const newValue: string); override;
  end; 


  TIntegerEditBoxMinMax = class(TCustomEdit)
    private
      FMinimum : Integer;
      FMaximum : Integer;
      FValue   : Integer;

    published  { Published declarations - available in the Object Inspector at design-time }
      property Minimum  : Integer read FMinimum write FMinimum;
      property Maximum  : Integer read FMaximum write FMaximum;
      property Value    : Integer read FValue   write FValue;

  end;  // of class TIntegerEditBoxMinMax()

procedure Register;

implementation

Uses TypInfo, Consts, DesignIntf, Dialogs;

  procedure Register;
  begin
    RegisterComponents('Standard', [TIntegerEditBoxMinMax]);
    RegisterPropertyEditor(TypeInfo(Integer), TIntegerEditBoxMinMax, 'Minumim', TMinimumProperty);
    RegisterPropertyEditor(TypeInfo(Integer), TIntegerEditBoxMinMax, 'Maximum', TMaximumProperty);
    RegisterPropertyEditor(TypeInfo(Integer), TIntegerEditBoxMinMax, 'Value',   TValueProperty);
  end;

  procedure TMinimumProperty.SetValue(const newValue: string);
    var L: Longint;
        min, max : Integer;
        propInfo: PPropInfo;
        exceptionString : String;
  begin
MessageDlg('editor !!', mtWarning, [mbOK], 0);   // This is never seen !!
    L := StrToInt(newValue);                { convert string to number }
    with GetTypeData(GetPropType())^ do     { this uses compiler data for type Integer }
      min  := GetOrdProp(GetComponent(0), 'Minimum');
      max  := GetOrdProp(GetComponent(0), 'Maximum');

      if min > max then
      begin
        exceptionString := 'Minimum value (%l) cannot be greater than maximum (%l)';
        raise Exception.CreateResFmt(@exceptionString, [min, max]);
      end;

      if L < min then
      begin
        PropInfo := GetPropInfo();
        SetOrdProp(Nil , propInfo, Int64(min));
        exceptionString := 'Value (%l) less than new minimum (%l); value set to minimum';
        raise Exception.CreateResFmt(@exceptionString, [L, min]);
      end;

    SetOrdValue(L);                                { if in range, go ahead and set value }
  end;  // of TMinimumProperty.SetValue()


  procedure TMaximumProperty.SetValue(const newValue: string);
    var L: Longint;
        min, max : Integer;
        propInfo: PPropInfo;
        exceptionString : String;
  begin
    L := StrToInt(newValue);                { convert string to number }
    with GetTypeData(GetPropType())^ do     { this uses compiler data for type Integer }
      min  := GetOrdProp(Nil, 'Minimum');
      max  := GetOrdProp(Nil, 'Maximum');

      if max < min then
      begin
        exceptionString := 'Maximum value (%l) cannot be less than minimum (%l)';
        raise Exception.CreateResFmt(@exceptionString, [max, min]);
      end;

      if L > max then
      begin
        PropInfo := GetPropInfo();
        SetOrdProp(Nil , propInfo, Int64(max));
        exceptionString := 'Value (%l) more than new maximum (%l); value set to maximum';
        raise Exception.CreateResFmt(@exceptionString, [L, max]);
      end;

    SetOrdValue(L);      { if in range, go ahead and set value }
  end;  // of TMaximumProperty.SetValue()


  procedure TValueProperty.SetValue(const newValue: string);
    var L: Longint;
        min, max: Integer;
  begin
    L := StrToInt(newValue);             { convert string to number }
    // see also http://www.freepascal.org/docs-html/rtl/typinfo/getobjectprop.html
    // for other useful functions
    with GetTypeData(GetPropType())^ do  { this uses compiler data for type Integer }
    begin
      min := GetOrdProp(Nil, 'Minimum');
      max := GetOrdProp(Nil, 'Maximum');
      // for Float, etc, see http://www.blong.com/Conferences/BorConUK98/DelphiRTTI/CB140.htm

      if (L < min) or (L > max) then              { make sure it's in range... }
        raise Exception.CreateResFmt(@SOutOfRange, [min, max]);   { ...otherwise, raise exception }

      SetOrdValue(L);    { if in range, go ahead and set value }
    end;
  end;  // of TMinimumProperty.SetValue()


end.

Original question:

This link gives a pretty good example of a property editor for an integer property.

How can I change this method ...

procedure TIntegerProperty.SetValue(const Value: string);
var
  L: Longint;
begin
  L := StrToInt(Value);                      { convert string to number }
  with GetTypeData(GetPropType)^ do  { this uses compiler data for type Integer }
    if (L < MinValue) or (L > MaxValue) then { make sure it is in range }
      { otherwise, raise exception }
      raise EPropertyError.Create(FmtLoadStr(SOutOfRange, [MinValue, MaxValue]));
  SetOrdValue(L);                       { if in range, go ahead and set value }
end;

... what I want is to male a new property, say TIntegerMinMaxProperty, derived from TIntegerProperty where the component editor also shows minimum and maximum permitted values for the integer.

I was thinking of adding two new Integer properties, called Minimum & Maximum, but it looks like I could maybe use the existing MinValue & MaxValue if I could only publish them, but I don't see how ... neither of these compile

published  { available in the Object Inspector at design-time }
  property Minimum : Longint read  MinValue write  MinValue;
  property Minimum : Longint read FMinValue write FMinValue;

So it looks like I have two options and am stuck at both :-/

1) find a way to publish those MinValue & MaxValue properties (which is probably cleaner)
2) publish 2 new properties, Minimujm & Maximum and figure how to refer to them in TIntegerProperty.SetValu()

And help gratefully appreciated as this is my first sortie into property editors (in case it helps influence the answer to this, my next property will be one that accepts decimal input, with a a point)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

在巴黎塔顶看东京樱花 2024-09-22 04:53:07

如果 MinValue 和 MaxValue 已经是组件/控件的属性,但当前是公共的且未发布,您所需要做的就是在已发布部分中重新声明它们,但仅按名称声明:

published
  property MinValue;
  property MaxValue;

这只会更改这些属性的可见性属性,并且如果支持它们的类型,应该使它们显示在对象检查器中。看一下许多 T... 与 TCustom... 类对,其中 T... 类通常仅重新声明已发布的属性,以使它们显示在对象检查器中。

编辑(回应评论)

好的,等等,如果你想要一些控制,比如说一个 TMyEdit 和一个 SomeFactor Integer 属性,对象检查器中的条目不仅会显示值的 SomeFactor 的值,以及 SomeFactor 允许的最小值和最大值,您将需要一个显示其自己形式的代码属性编辑器。

当然,您可以将 MinValue 和 MaxValue 添加到 TIntegerProperty 的后代,并在 GetValue 和 SetValue 方法的重写中使用它们(这就是它们毕竟是虚拟的原因),然后注册此 TMinMaxIntegerProperty 供 SomeFactor 属性使用。但是,这不会使 MinValue 和 MaxValue 显示在对象检查器中,因为 TIntegerProperty 基本上只编辑/显示 SomeFactor 的实际值。为了实现您想要的目的,您必须编写自定义属性编辑器的后代,例如显示用于编辑和格式化字符串的表单的编辑器。我使用的组件中有很多示例,但我当然不能在这里发布它们的代码。

如果您想要的只是一个带有 SomeFactor 整数属性的 TMyEdit,并且想要将 SomeFactorMinValue 和 SomeFactorMaxValue 添加到 TMyEdit 控件,那么您可以通过 FPropList 条目的 Instance 引用在 GetValue/SetValue 方法中访问这些内容。有关信息,请参阅 TIntegerProperty 编辑器中使用的 SetOrdValue 实现。它使用 SetOrdProp(来自 TypInfo)来设置 Instance 的值,该值应该是对持有 SomeFactor 属性的 TMyEdit 控件的引用。通过一些转换,您应该能够获得 SomeFactorMinValue 和 SomeFactorMaxValue 属性。

注意:不确定 FPropList 如何获取其条目。但它通过构造函数获取其计数。您可能需要自己在这里做一些进一步的调查。 (出于某种原因,Ctrl 键单击和代码洞察决定在我的 D2009 中罢工。)

If the MinValue and MaxValue are already properties of your component/control, but are currently public and not published all you need to do is re-declare them in the published section, but only by name:

published
  property MinValue;
  property MaxValue;

That'll change only the visibility of those properties and should make them show up in the object inspector if their types are supported. Have a look at many of the T... versus TCustom... class pairs where the T... class often only redeclares properties as published to make them show up in the Object Inspector.

Edit (In response to comments)

Ok, hang on, if you want to have some control, say a TMyEdit with say a SomeFactor Integer property for which the entry in the Object Inspector would not only show the value of SomeFactor, but also the min and max values allowed for SomeFactor, you'll need a to code property editor that shows its own form.

You can of course add the MinValue and MaxValue to a descendant of TIntegerProperty and use those in the overrides for the GetValue and SetValue methods (that's why they are virtual after all), then register this TMinMaxIntegerProperty for use by the SomeFactor property. However, that won't make the MinValue and MaxValue show up in the Object Inspector as the TIntegerProperty basically only edits/shows the actual value for SomeFactor. To achieve what you want, you would have to code a descendant of a custom property editor, for example one that shows a form to edit and format a string. There are plenty of examples in the components I use, but I can't post their code here of course.

If what you want is simply a TMyEdit with a SomeFactor integer property and want to add a SomeFactorMinValue and a SomeFactorMaxValue to your TMyEdit control, then you can access those in the GetValue/SetValue methods through the Instance reference of the FPropList entry. See SetOrdValue implementation that is used in the TIntegerProperty editor for info. It employs SetOrdProp (from TypInfo) to set the value for on Instance which should be a reference to the TMyEdit control holding the SomeFactor property. With some casting you should then be able to the SomeFactorMinValue and SomeFactorMaxValue properties.

Note: Not sure how the FPropList gets its entries. It gets its count through the constructor though. You may have to do some further investigation here yourself. (For some reason Ctrl-click and code-insight have decided to go on strike in my D2009.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文