我有一个简单的Delphi记录:
type
TCustomer = record
name : string[30];
age : byte;
end;
我知道我可以通过在代码中对字段名称进行硬编码来设置此记录的字段:
var
customer : TCustomer;
begin
// Set up our customer record
customer.name := 'Fred Bloggs';
customer.age := 23;
end;
但我有一个TEdit
,旁边有一个TComboBox
,还有一个TButton
。组合框是固定的,有两个项目,"名称"和"年龄"。它将首先设置为" Name"。用户在编辑框中键入其名称值。这是一个Save类型的按钮,它有一个OnClick事件,如:
procedure TMainForm.SaveButtonClick(Sender: TObject);
begin
if(MyComboBox.Text = 'Name') then
begin
customer.name := MyEditBox.Text;
end
else
begin
customer.age := MyEditBox.Text;
end;
end;
该记录已在其他地方初始化。我在这里得到的是在我的情况下有101种可能的组合框项目。我应该制作一个大规模的case语句来处理这个问题,还是可以通过将重新排序的字段名称与另一个控件(在这种情况下是组合框)设置的动态信息相匹配来合并代码?
答案 0 :(得分:2)
如果您的Delphi版本具有增强的RTTI(Delphi 2010及更高版本),您可以这样做。
然而,有一些陷阱:
1.Short字符串必须定义为编译器的类型,以便为这些字段创建typeinfo(就像我对String30
所做的那样)
2. TValue
这是在增强型RTTI中携带事物的类型,不会自动进行类型转换(就像编辑到Age字段的Integer中的字符串一样)。这就是为什么我走进Variant
并将其转换为字段的正确类型(仅适用于ShortString
和Integer
,其余部分留给读者练习)
3. TValue
不喜欢来自不同ShortString
类型的转化(String30
与ShortString
不同),这就是我使用TValue.Make
的原因。缺少的是检查提供的值是否与类型匹配(就像它超过30个字符)。它当然也不兼容unicode。
uses
Rtti,
TypInfo;
type
String30 = string[30];
TCustomer = record
name: String30;
age: byte;
end;
var
c: TCustomer;
function CastFromVariant(ATypeInfo: PTypeInfo; const AValue: Variant): TValue;
var
asShort: ShortString;
begin
case ATypeInfo.Kind of
tkInteger: Result := TValue.From<Integer>(AValue);
tkString:
begin
asShort := AValue;
TValue.Make(@asShort, ATypeInfo, Result);
end;
end;
end;
procedure TForm5.Button1Click(Sender: TObject);
var
ctx: TRttiContext;
t: TRttiType;
f: TRttiField;
v: TValue;
begin
t := ctx.GetType(TypeInfo(TCustomer));
f := t.GetField(ComboBox1.Text);
v := CastFromVariant(f.FieldType.Handle, Edit1.Text);
f.SetValue(@c, v);
end;
procedure TForm5.ComboBox1Change(Sender: TObject);
var
ctx: TRttiContext;
t: TRttiType;
f: TRttiField;
v: TValue;
begin
t := ctx.GetType(TypeInfo(TCustomer));
f := t.GetField(ComboBox1.Text);
v := f.GetValue(@c);
Edit1.Text := v.ToString;
end;
答案 1 :(得分:0)
屏幕上的组件是它们自己的变量。它们的存在与您的记录无关。
您需要根据需要从一个副本复制到另一个。
(使用我的代码作为指导 - 在语法上可能不完全正确。)
// UI component declarations within the form
TForm1 = class(TForm)
. . .
cbo : TComboBox;
edt : TEdit;
. . .
end;
. . .
var
Form1 : TForm1;
. . .
// to copy values from customer to UI components:
cbo.ItemIndex := customer.age; // assuming this is what the combobox is used for,
// and it starts at zero
edt := customer.name;
// to copy from UI components into customer, you'll need to do it inside of one
// of the event handlers.
TForm1.cboCloseUp( sender : TObject ); // the onCloseUp handler, when the combo drop-down closes
begin
customer.age := cbo.ItemIndex; // or StrToInt(cbo.Text)
end;
TForm1.edtChange( sender : TObject ); // the onChange handler whenever the edit changes
begin
customer.name := edt.Text;
end;
这是它的要点。如果组合框中的年龄从零开始,那么当您复制客户记录和组合框时,您将要相应地调整偏移量。如果值是线性的,您可以设置ItemIndex + offset,或者只是将值写入cbo.Text。