gpt4 book ai didi

delphi - TStream 作为 StringList 内的对象

转载 作者:行者123 更新时间:2023-12-01 17:56:09 25 4
gpt4 key购买 nike

我正在使用 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;

当我双击列表框时,我想将所选项目流对象加载到备忘录中。这是我尝试做的:

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;

我的问题是:

  1. 我在 StringList 中添加和删除(释放)TStream 对象的方式正确吗?也许我需要先释放流,然后释放对象?

  2. 我在 FormDestroy 事件上释放所有对象的方式正确吗?

  3. 当我尝试将流加载回 Memo (Memo.Lines.LoadFromStream(TStream(List.Objects[Idx]))) 时,尽管 Stream.Size 大于零,但它不会加载。我做错了什么?

最佳答案

1.Is correct the way I am adding and removing (freeing) the TStream object inside the StringList?

是的,因为 TStrings.Objects[] 属性返回一个 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 每当您从 TStringList 添加/删除单个项目时。您应该简单地从 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?

在将流加载到备忘录之前,您不会将流返回到位置 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 - TStream 作为 StringList 内的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31526785/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com