Filtrar una vista de lista de varias columnas

El siguiente fragmento de código filtrará los elementos de un TListView control basado en lo que se escribe en un TEdit control y funciona bien si ListView consta de una sola columna; sin embargo, si tiene más de 1 columna, los elementos en las otras columnas se destruyen cuando se aplica el filtro, por lo que espero que alguien sepa qué se necesita agregar al código a continuación para conservar esas columnas cuando se filtra ListView.

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.

preguntado el 28 de julio de 12 a las 14:07

No parece querer un filtro de fila, ya que obviamente eso incluye o excluye la fila. Parece que desea colocar un valor en blanco en la celda si no coincide. Tal vez no agregue la fila si ninguna de las columnas coincide... -

O tal vez podría probar cada columna, y si alguna de ellas coincide, agregue la fila, dice después de pensar un momento. Mejor aún, pasa los datos en la fila y los filtros a una función booleana, y agrega si es verdadero, sería un enfoque más natural. -

Lo siento, no entiendo muy bien tu respuesta. ¿Podría por favor tratar de reformular eso de nuevo? Gracias por la respuesta por cierto. Todo lo que estoy tratando de hacer es crear un filtro como el que tiene con DBgrid, pero en lugar de una cuadrícula con un conjunto de datos, simplemente estoy usando ListView y un control de edición. -

¿eh? Dijiste "los artículos en otras columnas se destruyen". Por supuesto que lo son, usted filtró la fila, así es como también funcionan los filtros DBGrid. -

1 Respuestas

Está borrando la vista de lista y luego está agregando a su Items sin SubItems - es por eso que las columnas adicionales están vacías.

Para filtrar el contenido de la vista de lista, podría ser más fácil usar la vista de lista en modo virtual donde establece el conteo y proporciona los datos a pedido en una devolución de llamada. He aquí un ejemplo rápido:

La forma:

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

El código:

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.

Respondido 28 Jul 12, 17:07

Gracias, después de jugar un poco pude hacerlo funcionar utilizando la información de mi base de datos. - avuela

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.