使用 RTTI 从 tkSet 类型获取可能值和当前值
Get possible and present values from a tkSet type using RTTI
这个问题可能已经有人问过了,但是还没找到,所以问题来了:
我想解析组件的 tkSet 属性(在我们的例子中是 Panel1),但我不知道如何正确地进行。我能够使用 rContext.FindType() 找到集合的基本枚举类型,但我几乎可以肯定还有更多 elegant/simple 方法可以做到这一点。从那时起,我完全迷路了。我应该通过该枚举类型的值并根据组件的当前 属性 值检查每个值。
procedure TForm12.GetProperties2;
var
rContext: TRttiContext;
rType: TRttiType;
rProp: TRttiProperty;
begin
rType := rContext.GetType(Panel1.ClassType);
for rProp in rType.GetProperties do
begin
if (rProp.Visibility in [mvPublished]) and (rProp.PropertyType.TypeKind in [tkSet]) and (rProp.Name = 'Anchors') then
begin
Memo1.Lines.Add('Name: ' + rProp.Name);
Memo1.Lines.Add('PropertyType: ' + rProp.PropertyType.ToString);
Memo1.Lines.Add('Value: ' + rProp.GetValue(Panel1).ToString);
Memo1.Lines.Add('QualifiedName: ' + rProp.PropertyType.QualifiedName);
Memo1.Lines.Add('ElementType: ' + rContext.FindType(rProp.PropertyType.QualifiedName).AsSet.ElementType.ToString);
// here comes the desired results
Memo1.Lines.Add('Possible values:');
Memo1.Lines.Add(' 0 > akLeft');
Memo1.Lines.Add(' 1 > akTop');
Memo1.Lines.Add(' 2 > akRight');
Memo1.Lines.Add(' 3 > akBottom');
Memo1.Lines.Add('Present values:');
Memo1.Lines.Add(' 0 > akLeft');
Memo1.Lines.Add(' 1 > akTop');
Memo1.Lines.Add('');
end;
end;
end;
另一个可能的问题是设置属性没有基本枚举类型,例如,如果您查看 TPanel.StyleElements 属性,您会看到 TStyleElements 的声明如下:
TStyleElements = set of (seFont, seClient, seBorder);
在这种情况下,ElementType 不起作用。
所以问题是我如何解析 tkSet 类型属性以使用 RTTI 上下文获得所需的结果?
使用基本的 TypInfo 非常容易。
procedure PrintSet(const v: TValue); // v contains a value from a set type
var
enumType: PTypeInfo;
enumData: PTypeData;
buffer: set of Byte; // biggest possible set type
i: Integer;
begin
buffer := [];
v.ExtractRawData(@buffer);
enumType := v.TypeInfo.TypeData.CompType^;
enumData := enumType.TypeData;
for i := enumData.MinValue to enumData.MaxValue do
Writeln(GetEnumName(enumType, i) + ' = ' + (i in buffer).ToString(TUseBoolStrs.True));
end;
A set of Byte
是可能的最大集合类型,因此我们可以将其用作缓冲区,所有内容都适合,然后使用 TValue.ExtractRawData
方法将与实际集合一样多的数据写入其中类型有。其他一切都通过之前将其设置为空来归零。
然后我们可以使用枚举类型的类型数据来获取最小值和最大值。由于非连续枚举类型没有类型信息,我们不需要处理它,实际上只处理那些与经典位掩码二进制兼容的类型。
这个问题可能已经有人问过了,但是还没找到,所以问题来了:
我想解析组件的 tkSet 属性(在我们的例子中是 Panel1),但我不知道如何正确地进行。我能够使用 rContext.FindType() 找到集合的基本枚举类型,但我几乎可以肯定还有更多 elegant/simple 方法可以做到这一点。从那时起,我完全迷路了。我应该通过该枚举类型的值并根据组件的当前 属性 值检查每个值。
procedure TForm12.GetProperties2;
var
rContext: TRttiContext;
rType: TRttiType;
rProp: TRttiProperty;
begin
rType := rContext.GetType(Panel1.ClassType);
for rProp in rType.GetProperties do
begin
if (rProp.Visibility in [mvPublished]) and (rProp.PropertyType.TypeKind in [tkSet]) and (rProp.Name = 'Anchors') then
begin
Memo1.Lines.Add('Name: ' + rProp.Name);
Memo1.Lines.Add('PropertyType: ' + rProp.PropertyType.ToString);
Memo1.Lines.Add('Value: ' + rProp.GetValue(Panel1).ToString);
Memo1.Lines.Add('QualifiedName: ' + rProp.PropertyType.QualifiedName);
Memo1.Lines.Add('ElementType: ' + rContext.FindType(rProp.PropertyType.QualifiedName).AsSet.ElementType.ToString);
// here comes the desired results
Memo1.Lines.Add('Possible values:');
Memo1.Lines.Add(' 0 > akLeft');
Memo1.Lines.Add(' 1 > akTop');
Memo1.Lines.Add(' 2 > akRight');
Memo1.Lines.Add(' 3 > akBottom');
Memo1.Lines.Add('Present values:');
Memo1.Lines.Add(' 0 > akLeft');
Memo1.Lines.Add(' 1 > akTop');
Memo1.Lines.Add('');
end;
end;
end;
另一个可能的问题是设置属性没有基本枚举类型,例如,如果您查看 TPanel.StyleElements 属性,您会看到 TStyleElements 的声明如下:
TStyleElements = set of (seFont, seClient, seBorder);
在这种情况下,ElementType 不起作用。
所以问题是我如何解析 tkSet 类型属性以使用 RTTI 上下文获得所需的结果?
使用基本的 TypInfo 非常容易。
procedure PrintSet(const v: TValue); // v contains a value from a set type
var
enumType: PTypeInfo;
enumData: PTypeData;
buffer: set of Byte; // biggest possible set type
i: Integer;
begin
buffer := [];
v.ExtractRawData(@buffer);
enumType := v.TypeInfo.TypeData.CompType^;
enumData := enumType.TypeData;
for i := enumData.MinValue to enumData.MaxValue do
Writeln(GetEnumName(enumType, i) + ' = ' + (i in buffer).ToString(TUseBoolStrs.True));
end;
A set of Byte
是可能的最大集合类型,因此我们可以将其用作缓冲区,所有内容都适合,然后使用 TValue.ExtractRawData
方法将与实际集合一样多的数据写入其中类型有。其他一切都通过之前将其设置为空来归零。
然后我们可以使用枚举类型的类型数据来获取最小值和最大值。由于非连续枚举类型没有类型信息,我们不需要处理它,实际上只处理那些与经典位掩码二进制兼容的类型。