lunes, 9 de diciembre de 2019

TListView: evitar ítems duplicados.

El componente TListView carece de una propiedad para impedir ítems duplicados, seguramente porque a su vez, los ítems son una clase que además posee subítems.
Una forma para evitar esta situación, sería, antes de agregar el ítem, recorrer la lista y comparar el texto (Caption) del ítem con los ya existentes, una función con un ciclo for to alcanza y es una manera correcta, pero si la lista tiene 15.000 ítems ¿que pasa?, para empezar, una lista del tipo TListView no debería contener tal cantidad y para terminar, también.
Pero TListView tiene un método (función) que hereda de TCustomListView: FindCaption.

{------------------------------------------------------------------------------}
{   TListItems FindCaption                                                     }
{------------------------------------------------------------------------------}
function TListItems.FindCaption(StartIndex: Integer; Value: string;
  Partial, Inclusive, Wrap: Boolean; PartStart: Boolean): TListItem;
var
  I: Integer;
  CaptionFound, AllChecked: Boolean;
begin
  result := nil;
  if (Count = 0) or (StartIndex >= Count) or (not Inclusive and (count = 1)) then Exit;
  CaptionFound := False;
  AllChecked := False;
  if Inclusive then
    I := StartIndex
  else begin
    I := succ(StartIndex);
    if I >= Count then I := 0;
  end;
  if Wrap then Wrap := (StartIndex <> 0);
  repeat
    if Partial then begin
      if PartStart then
        CaptionFound := pos(Value, Item[I].Caption) = 1
      else
        CaptionFound := pos(Value, Item[I].Caption) <> 0;
    end else
      CaptionFound := Value = Item[I].Caption;
    if not CaptionFound then begin
      Inc(I);
      if Wrap then begin
        if I = Count then
          I := 0
        else
          if I = StartIndex then
            AllChecked := True;
      end else begin
        if I = Count then AllChecked := True;
      end;
    end;
  until CaptionFound or AllChecked;
  if CaptionFound then result := Item[I];
end; 

Las ventajas son las opciones y que ya está hecha.

¿Cómo utilizarla?

if Assigned(ListView1.FindCaption(0,'eltexto',False,True,False,True)) then Exit;

Este código debe ejecutarse antes de agregar un ítem, si el ítem ya existe, entonces FindCaption devuelve un ítem ("completo"), caso contrario, devuelve nil.

Para probarlo basta con este ejemplo:

unit principal;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  ExtCtrls, ShellCtrls, StdCtrls, Buttons;

type

  { TForm1 }

  TForm1 = class(TForm)
    BAgregar: TBitBtn;
    lPath: TLabel;
    Lista: TListView;
    Panel1: TPanel;
    arbol: TShellTreeView;
    Splitter1: TSplitter;
    procedure arbolClick(Sender: TObject);
    procedure BAgregarClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  lPath.Caption:=arbol.Path;
end;

procedure TForm1.BAgregarClick(Sender: TObject);
var
  li:TListItem;
begin
  if not Assigned(arbol.Selected) then Exit;
  if Assigned(Lista.FindCaption(0,arbol.Path,False,True,False,True)) then Exit;
  li:=Lista.Items.Add;
  li.Caption:=arbol.Path;
end;

procedure TForm1.arbolClick(Sender: TObject);
begin
  if not Assigned(arbol.Selected) then Exit;
  lPath.Caption:=arbol.Path;
end;

end. 

Este programa agrega los nombres de las carpetas mostradas en un TShellTreeView a un TListView nombrada "lista" cada vez que se presiona el botón agregar, evitando duplicados.

No hay comentarios:

Publicar un comentario