我正在向TComboBox添加带有对象(也是字符串)的字符串,但是在稍后尝试检索时会收到损坏的字符串。
这就是我添加它们的方式:
var
i: Integer;
sl: TStringList;
c: Integer;
s: PChar;
begin
for i := 1 to tblCalls.FieldCount do
if tblCalls.Fields[i - 1].Tag = 1 then
ListBox1.Items.Append(tblCalls.Fields[i - 1].FieldName);
sl := TStringList.Create;
try
LoadStyles(TStrings(sl));
for c := 0 to sl.Count - 1 do
begin
s := PChar(sl.Values[sl.Names[c]]);
ComboBox1.Items.AddObject(sl.Names[c], TObject(s));
end;
finally
sl.Free;
end;
end;
procedure LoadStyles(var AStylesList: TStrings);
var
f, n: String;
filelist: TStringDynArray;
begin
f := ExtractFilePath(ParamStr(0)) + 'Styles';
if (not DirectoryExists(f)) then
Exit;
filelist := TDirectory.GetFiles(f);
for f in filelist do
begin
n := ChangeFileExt(ExtractFileName(f), EmptyStr);
AStylesList.Add(n + '=' + f);
end;
end;
..这就是我正在尝试检索字符串对象的地方:
procedure TfrmOptions.ComboBox1Change(Sender: TObject);
var
si: TStyleInfo;
i: Integer;
s: String;
begin
i := TComboBox(Sender).ItemIndex;
s := PChar(TComboBox(Sender).Items.Objects[i]);
Showmessage(s); // --> Mostly shows a corrupted string (gibberish chars)
if (TStyleManager.IsValidStyle(s, si)) then
begin
if (not MatchStr(s, TStyleManager.StyleNames)) then
TStyleManager.LoadFromFile(s);
TStyleManager.TrySetStyle(si.Name);
end;
end;
我怀疑它与我添加它们的方式有关。也许我需要在以下位置分配内存:
s := PChar(sl.Values[sl.Names[c]]);
不确定。看看StrNew,NewStr和StrAlloc的帮助,它说这些函数已被弃用。你能帮忙指出什么是错的吗?
答案 0 :(得分:2)
没有什么可以保持弦乐活着。当你写:
s := PChar(sl.Values[sl.Names[c]]);
创建一个类型为string
的隐式局部变量,用于保存sl.Values[sl.Names[c]]
求值的任何内容。该局部变量超出范围,只要编译器知道,没有任何引用它,并且字符串对象被销毁。
事实上,情况甚至更糟。因为上面的赋值发生在循环中,所以只有一个隐式局部变量。每次循环时,您要求组合框记住的字符串都会被销毁。
您需要找到一种方法来延长字符串的生命周期。你可以这样做:
var
StrPtr: ^string;
....
for c := 0 to sl.Count - 1 do
begin
New(StrPtr);
StrPtr^ := sl.Values[sl.Names[c]];
ComboBox1.Items.AddObject(sl.Names[c], TObject(StrPtr));
end;
然后当你需要访问字符串时,你可以这样做:
var
StrPtr: ^string;
....
TObject(StrPtr) := TComboBox(Sender).Items.Objects[i];
// do something with StrPtr^
当您清除组合框时,您还必须浏览每个项目并在指针上调用Dispose
。
话虽如此,不这样做也会容易得多。停止尝试将字符串强制转换为与每个项目关联的TObject
数据。而是保留包含这些字符串的并行字符串列表。当您需要查找名称时,请在该列表中查找,而不是在组合框中查找。
答案 1 :(得分:0)
我知道这是一个老问题,但是我又遇到了这个问题,而不是使用单独的字符串列表,而是使用了一个带有字符串值的对象(我认为有人在注释中建议了它),如下所示:
使用字符串值将类型声明为TObject:
TStringObject = class(TObject)
StringValue : string;
end;
然后在添加项目时,声明TStringObject的本地变量并为每个项目创建一个新实例:
var
strObj : TStringObject
begin
...
for c := 0 to sl.Count - 1 do
begin
strObj := TStringObject.Create;
strObj.StringValue := sl.Values[sl.Names[c]];
ComboBox1.Items.AddObject(sl.Names[c], strObj);
end;
在检索值时:
s := TStringObject(TComboBox(Sender).Items.Objects[i]).StringValue;