TStream 作为 StringList 中的一个对象
TStream as an object inside StringList
我正在使用 Delphi 7 并使用 StringList,以 TStream 作为对象。
我的测试项目有一个列表框、一个备忘录和 2 个按钮(添加和删除)。
这是我目前得到的结果:
var
List: TStringList;
procedure TForm1.FormCreate(Sender: TObject);
begin
List := TStringList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
if (List.Count > 0) then
for I := 0 to Pred(List.Count) do
begin
List.Objects[I].Free;
List.Objects[I] := nil;
end;
FreeAndNil(List);
end;
procedure TForm1.btnAddClick(Sender: TObject);
var
Strm: TStream;
begin
Strm := TMemoryStream.Create;
try
Memo.Lines.SaveToStream(Strm);
List.AddObject(IntToStr(List.Count), TObject(Strm));
Memo.Clear;
ListBox.Items.Assign(List);
finally
// Strm.Free; (line removed)
end;
end;
procedure TForm1.btnDelFirstClick(Sender: TObject);
begin
if (List.Count > 0) then
begin
List.Objects[0].Free;
List.Objects[0] := nil;
List.Delete(0);
ListBox.Items.Assign(List);
end;
end;
当我双击 ListBox 时,我想将所选项目 Stream 对象加载到 Memo。这是我尝试做的:
procedure TForm1.ListBoxDblClick(Sender: TObject);
var
Idx: Integer;
begin
Memo.Clear;
Idx := ListBox.ItemIndex;
if (Idx >= 0) and (TStream(List.Objects[Idx]).Size > 0) then
Memo.Lines.LoadFromStream(TStream(List.Objects[Idx]));
end;
我的问题是:
我在 StringList 中添加和删除(释放)TStream 对象的方式是否正确?也许我需要先释放 Stream,然后再释放 Object??
我在 FormDestroy 事件中释放所有对象的方式是否正确?
当我尝试将流加载回 Memo (Memo.Lines.LoadFromStream(TStream(List.Objects[Idx]))) 时,尽管 Stream.Size 高于零。我做错了什么?
我不明白你关于释放流然后释放对象的建议。据我了解,您正在谈论释放 的对象是 流。你不能先销毁一个,因为只有一个对象,它是一个流。
您在字符串列表中添加和删除流对象的方法没问题。它们并不理想,但我会在这里限制我的评论,因为 Stack Overflow 不是 Code Review.
调用SaveToStream
后,流的位置在流的末尾。如果你想从流中读取,那么你必须再次将位置设置回开始。在调用 LoadFromStream
.
之前为流设置 Position := 0
1.Is correct the way I am adding and removing (freeing) the TStream object inside the StringList?
是的,因为 TStrings.Objects[]
属性 returns 一个 TObject
指针和 TStream
派生自 TObject
,所以你可以调用 Free()
在对象指针上。
Maybe I need to first free the Stream and then the Object??
您需要在释放 TStringList
对象之前释放 TStream
对象。正如您已经在做的那样。
2.Is correct the way I am freeing all objects on FormDestroy event?
是的。尽管从技术上讲,您不需要在进入循环之前检查 TStringList.Count
属性 是否为 > 0
,因为循环会为您处理该情况。在释放 TStringList
:
之前,您不需要 nil
指针
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
for I := 0 to Pred(List.Count) do
List.Objects[I].Free;
List.Free;
end;
你正在做的一件事是矫枉过正,但是,当你 Assign()
将 整个 TStringList
TListBox
TListBox
add/delete 来自 TStringList
的单个项目。您应该改为 add/delete ListBox 中的关联项目,并按原样保留其余项目。
并向 btnAddClick()
添加一些额外的错误检查,以避免出现问题时出现任何内存泄漏。
试试这个:
procedure TForm1.btnAddClick(Sender: TObject);
var
Strm: TStream;
Idx: Integer;
begin
Strm := TMemoryStream.Create;
try
Memo.Lines.SaveToStream(Strm);
Strm.Position := 0;
Idx := List.AddObject(IntToStr(List.Count), Strm);
except
Strm.Free;
raise;
end;
try
ListBox.Items.Add(List.Strings[Idx]);
except
List.Objects[Idx].Free;
List.Delete(Idx);
raise;
end;
Memo.Clear;
end;
procedure TForm1.btnDelFirstClick(Sender: TObject);
begin
if List.Count > 0 then
begin
List.Objects[0].Free;
List.Delete(0);
ListBox.Items.Delete(0);
end;
end;
3.When I try to load the stream back to Memo (Memo.Lines.LoadFromStream(TStream(List.Objects[Idx]))), it doesn't load, despite Stream.Size is higher than zero. What I am doing wrong?
在将流加载到备忘录中之前,您没有将流返回到 Position
0。 SaveToStream()
始终将流定位在流的末尾,并且 LoadFromStream()
将流定位在负载停止读取的位置(如果不在末尾,以防发生故障)。
现在,综上所述,我个人不会以这种方式使用 TListBox
。我会改为将其 Style
属性 设置为 lbVirtual
,然后使用其 OnData
事件显示来自 TStringList
的字符串。无需将它们直接复制到 TListBox
中,或尝试始终保持两个列表同步。让 TListBox
询问您需要什么,然后您可以从 TStringList
提供它(然后我将其更改为 TList
因为您并没有真正存储无法在 OnData
事件处理程序中动态生成的有意义的名称):
var
List: TList;
procedure TForm1.FormCreate(Sender: TObject);
begin
List := TList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
ListBox.Count := 0;
for I := 0 to Pred(List.Count) do
TStream(List[I]).Free;
List.Free;
end;
procedure TForm1.btnAddClick(Sender: TObject);
var
Strm: TStream;
Idx: Integer;
begin
Strm := TMemoryStream.Create;
try
Memo.Lines.SaveToStream(Strm);
Strm.Position := 0;
Idx := List.Add(Strm);
except
Strm.Free;
raise;
end;
try
ListBox.Count := List.Count;
except
TStream(List[Idx]).Free;
List.Delete(Idx);
raise;
end;
Memo.Clear;
end;
procedure TForm1.btnDelFirstClick(Sender: TObject);
begin
if List.Count > 0 then
begin
TStream(List[0]).Free;
List.Delete(0);
ListBox.Count := List.Count;
end;
end;
procedure TForm1.ListBoxDblClick(Sender: TObject);
var
Strm: TStream;
Idx: Integer;
begin
Memo.Clear;
Idx := ListBox.ItemIndex;
if Idx >= 0 then
begin
Strm := TStream(List[Idx]);
if Strm.Size > 0 then
begin
Strm.Position := 0;
Memo.Lines.LoadFromStream(Strm);
end;
end;
end;
procedure TForm1.ListBoxData(Control: TWinControl; Index: Integer; var Data: string);
begin
Data := IntToStr(Index);
end;
我正在使用 Delphi 7 并使用 StringList,以 TStream 作为对象。
我的测试项目有一个列表框、一个备忘录和 2 个按钮(添加和删除)。
这是我目前得到的结果:
var
List: TStringList;
procedure TForm1.FormCreate(Sender: TObject);
begin
List := TStringList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
if (List.Count > 0) then
for I := 0 to Pred(List.Count) do
begin
List.Objects[I].Free;
List.Objects[I] := nil;
end;
FreeAndNil(List);
end;
procedure TForm1.btnAddClick(Sender: TObject);
var
Strm: TStream;
begin
Strm := TMemoryStream.Create;
try
Memo.Lines.SaveToStream(Strm);
List.AddObject(IntToStr(List.Count), TObject(Strm));
Memo.Clear;
ListBox.Items.Assign(List);
finally
// Strm.Free; (line removed)
end;
end;
procedure TForm1.btnDelFirstClick(Sender: TObject);
begin
if (List.Count > 0) then
begin
List.Objects[0].Free;
List.Objects[0] := nil;
List.Delete(0);
ListBox.Items.Assign(List);
end;
end;
当我双击 ListBox 时,我想将所选项目 Stream 对象加载到 Memo。这是我尝试做的:
procedure TForm1.ListBoxDblClick(Sender: TObject);
var
Idx: Integer;
begin
Memo.Clear;
Idx := ListBox.ItemIndex;
if (Idx >= 0) and (TStream(List.Objects[Idx]).Size > 0) then
Memo.Lines.LoadFromStream(TStream(List.Objects[Idx]));
end;
我的问题是:
我在 StringList 中添加和删除(释放)TStream 对象的方式是否正确?也许我需要先释放 Stream,然后再释放 Object??
我在 FormDestroy 事件中释放所有对象的方式是否正确?
当我尝试将流加载回 Memo (Memo.Lines.LoadFromStream(TStream(List.Objects[Idx]))) 时,尽管 Stream.Size 高于零。我做错了什么?
我不明白你关于释放流然后释放对象的建议。据我了解,您正在谈论释放 的对象是 流。你不能先销毁一个,因为只有一个对象,它是一个流。
您在字符串列表中添加和删除流对象的方法没问题。它们并不理想,但我会在这里限制我的评论,因为 Stack Overflow 不是 Code Review.
调用
SaveToStream
后,流的位置在流的末尾。如果你想从流中读取,那么你必须再次将位置设置回开始。在调用LoadFromStream
. 之前为流设置
Position := 0
1.Is correct the way I am adding and removing (freeing) the TStream object inside the StringList?
是的,因为 TStrings.Objects[]
属性 returns 一个 TObject
指针和 TStream
派生自 TObject
,所以你可以调用 Free()
在对象指针上。
Maybe I need to first free the Stream and then the Object??
您需要在释放 TStringList
对象之前释放 TStream
对象。正如您已经在做的那样。
2.Is correct the way I am freeing all objects on FormDestroy event?
是的。尽管从技术上讲,您不需要在进入循环之前检查 TStringList.Count
属性 是否为 > 0
,因为循环会为您处理该情况。在释放 TStringList
:
nil
指针
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
for I := 0 to Pred(List.Count) do
List.Objects[I].Free;
List.Free;
end;
你正在做的一件事是矫枉过正,但是,当你 Assign()
将 整个 TStringList
TListBox
TListBox
add/delete 来自 TStringList
的单个项目。您应该改为 add/delete ListBox 中的关联项目,并按原样保留其余项目。
并向 btnAddClick()
添加一些额外的错误检查,以避免出现问题时出现任何内存泄漏。
试试这个:
procedure TForm1.btnAddClick(Sender: TObject);
var
Strm: TStream;
Idx: Integer;
begin
Strm := TMemoryStream.Create;
try
Memo.Lines.SaveToStream(Strm);
Strm.Position := 0;
Idx := List.AddObject(IntToStr(List.Count), Strm);
except
Strm.Free;
raise;
end;
try
ListBox.Items.Add(List.Strings[Idx]);
except
List.Objects[Idx].Free;
List.Delete(Idx);
raise;
end;
Memo.Clear;
end;
procedure TForm1.btnDelFirstClick(Sender: TObject);
begin
if List.Count > 0 then
begin
List.Objects[0].Free;
List.Delete(0);
ListBox.Items.Delete(0);
end;
end;
3.When I try to load the stream back to Memo (Memo.Lines.LoadFromStream(TStream(List.Objects[Idx]))), it doesn't load, despite Stream.Size is higher than zero. What I am doing wrong?
在将流加载到备忘录中之前,您没有将流返回到 Position
0。 SaveToStream()
始终将流定位在流的末尾,并且 LoadFromStream()
将流定位在负载停止读取的位置(如果不在末尾,以防发生故障)。
现在,综上所述,我个人不会以这种方式使用 TListBox
。我会改为将其 Style
属性 设置为 lbVirtual
,然后使用其 OnData
事件显示来自 TStringList
的字符串。无需将它们直接复制到 TListBox
中,或尝试始终保持两个列表同步。让 TListBox
询问您需要什么,然后您可以从 TStringList
提供它(然后我将其更改为 TList
因为您并没有真正存储无法在 OnData
事件处理程序中动态生成的有意义的名称):
var
List: TList;
procedure TForm1.FormCreate(Sender: TObject);
begin
List := TList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
I: Integer;
begin
ListBox.Count := 0;
for I := 0 to Pred(List.Count) do
TStream(List[I]).Free;
List.Free;
end;
procedure TForm1.btnAddClick(Sender: TObject);
var
Strm: TStream;
Idx: Integer;
begin
Strm := TMemoryStream.Create;
try
Memo.Lines.SaveToStream(Strm);
Strm.Position := 0;
Idx := List.Add(Strm);
except
Strm.Free;
raise;
end;
try
ListBox.Count := List.Count;
except
TStream(List[Idx]).Free;
List.Delete(Idx);
raise;
end;
Memo.Clear;
end;
procedure TForm1.btnDelFirstClick(Sender: TObject);
begin
if List.Count > 0 then
begin
TStream(List[0]).Free;
List.Delete(0);
ListBox.Count := List.Count;
end;
end;
procedure TForm1.ListBoxDblClick(Sender: TObject);
var
Strm: TStream;
Idx: Integer;
begin
Memo.Clear;
Idx := ListBox.ItemIndex;
if Idx >= 0 then
begin
Strm := TStream(List[Idx]);
if Strm.Size > 0 then
begin
Strm.Position := 0;
Memo.Lines.LoadFromStream(Strm);
end;
end;
end;
procedure TForm1.ListBoxData(Control: TWinControl; Index: Integer; var Data: string);
begin
Data := IntToStr(Index);
end;