Delphi如何转换ModalResult属性?

3
希望这是一个快速的问题,“如果你知道怎么做,那就很容易”...
我正在编写一些序列化/脚本类来动态生成表单,我尝试在另一天设置TColor并得到了一个错误“clBtnFace不是有效的整数值”或类似的东西,发现属性中使用的常量已注册,因此可以将它们转换为整数,所以我添加了代码来提取转换器并使用它。
现在今天我遇到了一个类似的问题,涉及ModalResult属性,但我不知道DFM反序列化程序如何处理这个属性?有什么办法可以将mrOK转换为整数吗?
编辑
没有太多的例子可以给出:
PropInfo := GetPropInfo(Instance, PropertyName);
SetPropValue(Instance, PropInfo, PropertyValue);

在这种情况下,Instance是一个TButton,PropertyName是'ModalResult',PropertyValue是'mrOK'。

也许提供一些导致问题的示例代码会有所帮助,因为正如Uwe Raabe所回答的那样,这不应该是一个问题。 - Scott W
如果您在表单上创建一个按钮并将ModalResult设置为mrOK,然后以文本形式查看,您会看到:ModalResult = 1。因此,似乎这些名称根本不为序列化程序所知。 - Ville Krumlinde
那就是答案了,有人写下来我会接受它。 - James Barrass
1
James,Ville的评论说Delphi不会将名称转换为整数。你不需要等待任何人写出那个答案;这正是Uwe的答案已经说过的。 - Rob Kennedy
@Rob Ville 指出,mrOk 并没有存储在 DFM 中,而是存储了它的整数表示形式,这就是为什么我在反序列化 'mrOk' 时会出现错误,因为它没有相应的转换方式。 - James Barrass
3个回答

7

它不需要:

const
  { Dialog Box Command IDs }
  {$EXTERNALSYM IDOK}
  IDOK = 1;          ID_OK = IDOK;

const
  mrNone     = 0;
  mrOk       = idOk;

type
  TModalResult = Low(Integer)..High(Integer);

TModalResult在某种程度上是Integer的一个子范围,mrOK只是一个整数常量。


那么TColor是什么?但是需要进行转换吗? - James Barrass
诚然,您并不需要 PropertyInfo 或 GetEnumValue,但我认为 dfm 存储了 mrOK,因此仍然需要某种转换才能从 mrOK 转到 1? - Marjan Venema
1
我想错了... VilleK 检查并报告:dfm 存储整数值。 - Marjan Venema

4

我不太想回答自己的问题,但由于没有其他人回答,所以......

ModalResults没有转换器,Delphi将整数表示存储在DFM中,正如VilleK在评论中所说。 作为解决方案,我已注册了一个新的转换器。

const
  ModalResults: array[0..10] of TIdentMapEntry = (
    (Value: mrNone; Name: 'mrNone'),           
    (Value: mrOk; Name: 'mrOk'),               
    (Value: mrCancel; Name: 'mrCancel'),       
    (Value: mrAbort; Name: 'mrAbort'),         
    (Value: mrRetry; Name: 'mrRetry'),         
    (Value: mrIgnore; Name: 'mrIgnore'),       
    (Value: mrYes; Name: 'mrYes'),             
    (Value: mrNo; Name: 'mrNo'),               
    (Value: mrAll; Name: 'mrAll'),             
    (Value: mrNoToAll; Name: 'mrNoToAll'),     
    (Value: mrYesToAll; Name: 'mrYesToAll'));



function ModalResultToIdent(ModalResult: Longint; var Ident: string): Boolean;
begin
    Result := IntToIdent(ModalResult, Ident, ModalResults);
end;

function IdentToModalResult(const Ident: string; var ModalResult: Longint): Boolean;
begin
    Result := IdentToInt(Ident, ModalResult, ModalResults);
end;
initialization
    RegisterIntegerConsts(TypeInfo(TModalResult), IdentToModalResult, ModalResultToIdent);

我不明白这段代码的目的。我认为你已经确定Delphi不需要将字符串“mrOK”转换为整数,因为它从一开始就没有将该值存储在DFM中。因此,Uwe的答案是正确的。看起来你正在添加代码以使 Delphi存储ModalResult值的文本名称,只是为了使你的问题前提有效。你没有回答你所问的问题。 - Rob Kennedy
3
@Rob - 我之前提到DFM Serializer仅仅是举例,我错误地认为它将ModalResults转换成整数,但实际上它只是将它们存储为整数。而我需要在自己的序列化类中进行转换,因为我更愿意读取mrOk而不是1。 - James Barrass
“Delphi如何实现X”和“我如何实现X”不是同一个问题。Uwe回答了前者,而你回答了后者。这是一个很好的答案,只是不适用于当前的问题。你应该提出另一个问题,然后将这个作为答案发布;我会投票支持两个问题的回答。 - Rob Kennedy
@Rob 我同意它们是不同的问题,我没有成功地问出我真正想知道的。我已经将其发布为新问题。 - James Barrass

1

你提供的两个示例都是数字值的子范围。因此,RTTI只知道底层整数。其他示例包括TCursorTFontCharsetTTabOrder

如果你有这样一种类型:

  TEnum = (exOne,exTwo,exThree);

您可以使用 RTTI 获取和设置 'exOne''exTwo''exThree' 作为字符串。

这可以通过 TypInfo.pas 中的这些方法完成。

function GetEnumName(TypeInfo: PTypeInfo; Value: Integer): string;
function GetEnumValue(TypeInfo: PTypeInfo; const Name: string): Integer;

如果您想使用为颜色或ModalResults定义的常量,您必须构建自己的常量名称到值的字典,然后将其实现到您自己的序列化例程中。

TColor实现了一个名为Colors的静态字典,如果您只使用它支持的52种颜色,则可以使用它。

  Colors: array[0..51] of TIdentMapEntry = (
    (Value: clBlack; Name: 'clBlack'),
    ...
    (Value: clWindowText; Name: 'clWindowText'));

然后,您可以执行以下操作以获取颜色名称。

var
  ColorName : String;
begin
  // Color Value must be between 0 and 51 otherwise index out of bounds
  ColorName := Colors[ColorValue];  
end;

然后,您可以循环遍历颜色数组中的项目,以确定给定名称的值。


这就是混淆的根源,因为ModalResult不以这种方式存储数据。如果您查看DFM,可以看到颜色以文本形式存储,但ModalResult是一个整数。因此,TColor具有内置的IdentToInt转换器,而ModalResult没有。 - James Barrass

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