gpt4 book ai didi

delphi - 按字符串过滤时隐藏 TListBox 中的项目

转载 作者:行者123 更新时间:2023-12-03 15:03:59 26 4
gpt4 key购买 nike

简短版本:有没有办法单独控制或修改LisBox项目?例如,分别将其 Visible 属性设置为 False。我在搜索时在Fire Monkey中发现了TListBoxItem类,但我不想使用Fire Monkey并希望在VCL中使用它。

详细版本:我尝试使用两个 TStringList 和一个 Edit 来过滤我的 ListBox,一个 StringList 是全局的以保留原始列表 (list_files_global),另一个 StringList 来帮助过滤过程 (list_files_filter) 和我的主要文件列表是我的列表框 (list_files)。当程序开始存储我的原始列表时,我在 onCreate 事件上创建了全局 StringList:

procedure Tfrm_main.FormCreate(Sender: TObject);
Begin
list_files_global := TStringList.Create;
list_files_global.Assign(list_files.Items);
End;

并使用Edit的onChange事件进行过滤:

procedure Tfrm_main.edit_files_filterChange(Sender: TObject);
Var
list_files_filter: TStringList;
i: Integer;
Begin
list_files_filter := TStringList.Create;
list_files_filter.Assign(list_files.Items);

list_files.Clear;

for i := 0 to list_files_filter.Count - 1 do
if pos(edit_files_filter.text, list_files_filter[i]) > 0 then
list_files.Items.Add(list_files_filter[i]);

End;

要关闭过滤器,只需从我最初创建的全局列表中恢复列表:

list_files.Items := list_files_global;

到目前为止,一切正常,但问题是当我尝试从过滤列表中编辑/重命名/删除项目时,例如我更改一个项目:

list_files.Items[i] := '-- Changed Item --';

列表将被编辑,但是当我关闭过滤器时,原始列表将返回并且所有更改都会丢失。所以我想知道有没有什么正确的方法可以解决这个问题?比如单独隐藏项目或更改项目可见性等...所以我可以更改过滤算法并摆脱所有这些制作额外的列表。我在网上查了一天,也查了Delphi的帮助文件,没有找到有用的信息。

最佳答案

这是我经常做的事情,但是使用 ListView 而不是列表框。但基本原理是相同的。

我倾向于将各个项目存储为对象,这些对象是 Delphi 中的引用类型。我将它们全部保存在一个未过滤的主列表中,该列表拥有这些对象,同时我维护一个过滤列表(不拥有这些对象)用于显示目的。像@Sertac一样,我将其与虚拟 ListView 结合起来。

要了解其实际工作原理,请创建一个新的 VCL 应用程序并在主窗体上放置一个 ListView (lvDisplay) 和一个编辑控件 (eFilter):

Screenshot of main form with edit and list view control

注意,我已向 ListView 控件添加了三列:“姓名”、“年龄”和“颜色”。我还将其设为虚拟 (OwnerData = True)。

现在定义各个数据项的类:

type
TDogInfo = class
Name: string;
Age: Integer;
Color: string;
constructor Create(const AName: string; AAge: Integer; const AColor: string);
function Matches(const AText: string): Boolean;
end;

哪里

{ TDogInfo }

constructor TDogInfo.Create(const AName: string; AAge: Integer;
const AColor: string);
begin
Name := AName;
Age := AAge;
Color := AColor;
end;

function TDogInfo.Matches(const AText: string): Boolean;
begin
Result := ContainsText(Name, AText) or ContainsText(Age.ToString, AText) or
ContainsText(Color, AText);
end;

让我们创建未经过滤的狗列表:

TForm1 = class(TForm)
eFilter: TEdit;
lvDisplay: TListView;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FList, FFilteredList: TObjectList<TDogInfo>;
public
end;

哪里

function GetRandomDogName: string;
const
DogNames: array[0..5] of string = ('Buster', 'Fido', 'Pluto', 'Spot', 'Bill', 'Rover');
begin
Result := DogNames[Random(Length(DogNames))];
end;

function GetRandomDogColor: string;
const
DogColors: array[0..2] of string = ('Brown', 'Grey', 'Black');
begin
Result := DogColors[Random(Length(DogColors))];
end;

procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin

FList := TObjectList<TDogInfo>.Create(True); // Owns the objects

// Populate with sample data
for i := 1 to 1000 do
FList.Add(
TDogInfo.Create(GetRandomDogName, Random(15), GetRandomDogColor)
);

FFilteredList := FList;

lvDisplay.Items.Count := FFilteredList.Count;
lvDisplay.Invalidate;

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
if FFilteredList <> FList then
FreeAndNil(FFilteredList);
FreeAndNil(FList);
end;

这个想法是 ListView 控件始终显示FFilteredList,它要么指向与FList相同的对象实例,要么指向过滤(或排序)的对象实例版本:

// The list view's OnData event handler
procedure TForm1.lvDisplayData(Sender: TObject; Item: TListItem);
begin

if FFilteredList = nil then
Exit;

if not InRange(Item.Index, 0, FFilteredList.Count - 1) then
Exit;

Item.Caption := FFilteredList[Item.Index].Name;
Item.SubItems.Add(FFilteredList[Item.Index].Age.ToString);
Item.SubItems.Add(FFilteredList[Item.Index].Color);

end;

// The edit control's OnChange handler
procedure TForm1.eFilterChange(Sender: TObject);
var
i: Integer;
begin

if string(eFilter.Text).IsEmpty then // no filter, display all items
begin
if FFilteredList <> FList then
begin
FreeAndNil(FFilteredList);
FFilteredList := FList;
end;
end
else
begin
if (FFilteredList = nil) or (FFilteredList = FList) then
FFilteredList := TObjectList<TDogInfo>.Create(False); // doesn't own the objects
FFilteredList.Clear;
for i := 0 to FList.Count - 1 do
if FList[i].Matches(eFilter.Text) then
FFilteredList.Add(FList[i]);
end;

lvDisplay.Items.Count := FFilteredList.Count;
lvDisplay.Invalidate;

end;

结果:

Screenshot of populated list, no filtering

Screenshot of filtered list

请注意,每只狗始终只有一个内存中对象,因此如果您重命名一只狗,更改将反射(reflect)在 ListView 中,无论是否经过过滤。 (但不要忘记使其无效!)

关于delphi - 按字符串过滤时隐藏 TListBox 中的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58068080/

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