Reputation: 129
The following bit of code will filter the items of a TListView
control based upon what is typed in an TEdit
control and it works fine if the ListView consist of a single column, if you have more then 1 column however, then the items in the other columns are destroyed when the filter is applied, so I hoping someone might know what would need to be added to the code below to preserve those columns when the ListView is filtered.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, strutils, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
ListView1: TListView;
Edit1: TEdit;
procedure Edit1Change(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
StrList : TStringList;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
Index : Integer;
begin
StrList := TStringList.Create;
for Index := 0 to ListView1.Items.Count -1 do
StrList.Add(ListView1.Items[Index].Caption);
end;
procedure TForm1.Edit1Change(Sender: TObject);
var
Index : Integer;
begin
ListView1.Clear;
for Index := 0 to StrList.Count - 1 do
if Pos(Edit1.Text, StrList.Strings[Index]) > 0 then
ListView1.AddItem(StrList.Strings[Index], nil);
if Edit1.Text = '' then
for Index := 0 to StrList.Count - 1 do
ListView1.AddItem(StrList.Strings[Index], nil);
end;
end.
Upvotes: 0
Views: 5580
Reputation: 37221
You are clearing the listview and then you're adding to its Items
without SubItems
- that's why additional columns are empty.
To filter the contents of the listview it might be easier to use the listview in virtual mode where you set the count and supply the data on demand in a callback. Here's a quick example:
The form:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 282
ClientWidth = 418
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object ListView1: TListView
Left = 8
Top = 39
Width = 402
Height = 235
Columns = <
item
Caption = 'Name'
Width = 80
end
item
Caption = 'Title'
Width = 160
end
item
Alignment = taRightJustify
Caption = 'Age'
Width = 80
end>
OwnerData = True
SortType = stText
TabOrder = 0
ViewStyle = vsReport
OnData = ListView1Data
end
object Edit1: TEdit
Left = 8
Top = 12
Width = 121
Height = 21
TabOrder = 1
OnChange = Edit1Change
end
end
The code:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, System.Contnrs,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Grids, Vcl.ComCtrls;
type
TDataItem = class
private
FAge: Integer;
FFirstName: string;
FLastName: string;
public
property Age: Integer read FAge;
property FirstName: string read FFirstName;
property LastName: string read FLastName;
end;
TForm1 = class(TForm)
ListView1: TListView;
Edit1: TEdit;
procedure ListView1Data(Sender: TObject; Item: TListItem);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Edit1Change(Sender: TObject);
private
FActiveItems: TList;
FItems: TObjectList;
procedure AddTestData;
procedure ApplyFilter(const S: string = '');
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.AddTestData;
procedure AddDataItem(const FirstName, LastName: string; Age: Integer);
var
DataItem: TDataItem;
begin
DataItem := TDataItem.Create;
try
DataItem.FFirstName := FirstName;
DataItem.FLastName := LastName;
DataItem.FAge := Age;
FItems.Add(DataItem);
except
DataItem.Free;
raise;
end;
end;
begin
AddDataItem('John', 'Doe', 26);
AddDataItem('Jane', 'Warwick', 29);
AddDataItem('Stephen', 'Marley', 33);
AddDataItem('Alice', 'Connoly', 48);
AddDataItem('Adam', 'Spears', 63);
end;
procedure TForm1.ApplyFilter(const S: string);
var
I: Integer;
begin
ListView1.Items.BeginUpdate;
try
ListView1.Clear;
FActiveItems.Clear;
for I := 0 to FItems.Count - 1 do
if (S = '') or (Pos(UpperCase(S), UpperCase(TDataItem(FItems[I]).FirstName)) <> 0) then
FActiveItems.Add(FItems[I]);
ListView1.Items.Count := FActiveItems.Count;
finally
ListView1.Items.EndUpdate;
end;
end;
procedure TForm1.Edit1Change(Sender: TObject);
begin
ApplyFilter((Sender as TEdit).Text);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FItems := TObjectList.Create;
FActiveItems := TList.Create;
AddTestData;
ApplyFilter(Edit1.Text);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FActiveItems.Free;
FItems.Free;
end;
procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
var
DataItem: TDataItem;
begin
DataItem := FActiveItems[Item.Index];
Item.Caption := DataItem.FirstName;
Item.SubItems.Add(DataItem.LastName);
Item.SubItems.Add(IntToStr(DataItem.Age));
end;
end.
Upvotes: 3