Hrajeme si na Explorer - 4. díl - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



Delphi

Hrajeme si na Explorer - 4. díl

3. října 2001, 00.00 | V dnešním dílu seriálu se vrhneme na třídění výpisu
souborů podle jejich názvů, přičemž si mimojiné ukážeme práci s ukazateli.

V dnešním dílu seriálu se vrhneme na třídění výpisu souborů podle jejich názvů, přičemž si mj. ukážeme práci s ukazateli.

Příprava

Než začneme soubory třídit, musíme provést "přípravy". Především je potřeba nastavit komponentě FileView (pro připomenutí: je to ovládací prvek typu TListView, kde se vypisují soubory) vlastnost ColumnClick na hodnotu True. Tím umožníme uživateli, aby klikal na jednotlivá záhlaví ve výpisu (v režimu "Podrobnosti") a tím volil, jak chce soubory setřídit.

Dále si pak potřebujeme v programu pamatovat, podle kterého kritéria jsou soubory právě v této chvíli tříděny, a také zda jsou seřazeny vzestupně či sestupně. Deklarujeme si tedy dva výčtové typy vhodné pro uchovávání těchto informací:

type
  TSortCriteria = (scName, scSize, scType, scDate);
  TSortDirection = (sdAscending, sdDescending);

Všimněte si, že u TSortCriteria je pořadí možností stejné jako pořadí sloupců v FileView - později toho výhodně využijeme.

Pak zavedeme proměnné těchto dvou typů, ve kterých budeme informace o třídění udržovat. Je vcelku jedno, jestli je deklarujeme jako součást objektu formuláře, nebo jako obyčejné proměnné pomocí klíčového slova var. Já jsem zvolil první možnost:

...
private
  { Private declarations }
  SortCriteria: TSortCriteria;
  SortDirection: TSortDirection;
...

Obě tyto proměnné nemusíme při startu programu nastavovat na žádné iniciační hodnoty, protože v Delphi budou mít automaticky hodnotu první možnosti z výčtu. Po spuštění programu se tedy soubory budou třídit vzestupně podle jména.

Abychom měli všechna data o souborech, která budeme při třídění potřebovat, hezky pohromadě, upravíme proceduru TForm1.ShowBtnClick. Pro každý soubor si zapamatujeme jemu odpovídající strukturu TSearchRec, abychom pak mohli snadno přistupovat k potřebným datům o něm. Do vlastnosti Data každé položky seznamu FileView.Items pak zapíšeme příslušný ukazatel na alokovanou strukturu. Samozřejmě musíme zajistit i opětovné uvolnění zabrané paměti při změně adresáře a ukončení programu. Zde jsou potřebné části kódu, ale lépe vše asi pochopíte, když si stáhnete celý kód programu.

type
  PSearchRec = ^TSearchRec; // ukazatel na data o souboru,
                            // deklarovaný předem
...

procedure TForm1.ShowBtnClick(Sender: TObject);
var
  ...
  I: Integer;
  P: PSearchRec;
begin
  // odstraníme všechny položky a data o souborech
  with FileView do
  begin
    for I := 0 to Items.Count -1 do
      Dispose(Items[I].Data);
    Items.Clear;
  end;

  ...

  while Found = 0 do
  begin
    if (SearchRec.name <> '.') and (SearchRec.name <> '..') then
      with FileView.Items.Add do // přidáme položku
      begin
        ...
        // uložení dat o souborech
        New(P);          // alokace paměti
        P^ := SearchRec; // kopírování dat o souboru
        Data := P;       // přiřazení do vlastnosti Data
      end;
    Found := FindNext(SearchRec);
  end;

  ...

end;

...

procedure TForm1.FormDestroy(Sender: TObject);
var
  I: Integer;
begin
  // odstraníme data o souborech
  with FileView do
    for I := 0 to Items.Count - 1 do
      Dispose(Items[I].Data);
end;

Nastavení správného kritéria

Nyní se musíme vypořádat s výběrem kritéria třídění uživatelem. To se odehrává klikáním na záhlaví komponenty FileView, musíme tedy obsloužit její událost OnColumClick. Pokud uživatel kliknul na stejný sloupec, podle kterého třídíme teď, pouze změníme vzestupné třídění na sestupné a naopak. Jinak změníme kritérium třídění podle sloupce, kam kliknul.

procedure TForm1.FileViewColumnClick(Sender: TObject; Column: TListColumn);
begin
  if Column.Index = Integer(SortCriteria) then
    if SortDirection = sdAscending then
      SortDirection := sdDescending
    else
      SortDirection := sdAscending
  else
  begin
    SortCriteria := TSortCriteria(Column.Index);
    SortDirection := sdAscending;
  end;
end;

Všimněte si, že v proceduře je s výhodou použito oboustrnné přetypování mezi typy Integer a TSortCriteria. Podobný postup byl už jednou v programu použit, a to ve druhém dílu seriálu..

Třídění

Nyní musíme implementovat samotné třídění souborů. Pokud teď čekáte popis nějakého rychlého třídicího algoritmu, jste na omylu. Tento algoritmus je už implementován v komponentě TListView (přessněji už v části Win32 API, které tato komponenta zapouzdřuje), na nás je jenom to, abychom vytvořili porovnávací funkci. Ta dostane dvě položky ze seznamu souborů jako parametry a musí určit jejich pořadí pomocí svého výstupního parametru Compare (ten je typu Integer). Pokud má být první položka před druhou, funkce musí nastavit hodnotu menší než 0, pokud je tomu naopak, nastaví hodnotu větší než 0. Jsou-li obě položky stejné, funkce přiřadí parametru Compare hodnotu 0.

Ještě zbývá dodat, že funkci implementujeme jako obsluhu události OnCompare komponenty FileView a aby vše fungovalo, musíme také nastavit vlastnost SortType na stData (tím komponentě říkáme, že porovnávání položek si obstaráme sami).

procedure TForm1.FileViewCompare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
var
  FileName1, FileName2:string;
begin
  // nastavení jmen souborů (z dat u jednotlivých položek)
  FileName1 := DirEdit.Text + '\' + PSearchRec(Item1.Data)^.Name;
  FileName2 := DirEdit.Text + '\' + PSearchRec(Item2.Data)^.Name;

  case SortCriteria of
    scName:
      if DirectoryExists(FileName1)and(FileExists(FileName2)) then
        Compare := -1
      else if FileExists(FileName1)and(DirectoryExists(FileName2)) then
        Compare := 1
      else
        Compare := AnsiCompareText(FileName1, FileName2);
    scSize: ; // zatím neimplementováno
    scType: ; // zatím neimplementováno
    scDate: ; // zatím neimplementováno
  end;

  // pokud třídíme sestupně, "obrátíme" hodnotu Compare
  if SortDirection = sdDescending then
    Compare := Compare * -1;
end;

Výpis si zaslouží rozbor: Na začátku nastavíme jména obou souborů podle aktivního adresáře a uchovaných dat. Pak program rozvětvíme podle jednotlivých kritérií - pro dnešní díl implementujeme jen to první (třídění podle jména). Pak zjistíme (pomocí funkcí FileExists ze SysUtils a DirectoryExists z FileCtrl), zda jsou oba porovnávané položky adresáře či soubory. Pokud je jedna soubor a druhá adresář, platí pravidlo, že adresáře jsou ve výpisu před soubory. Pokud jsou obě stejného typu, o jejich pořadí rozhodne funkce AnsiStrComp, která porovná oba řetězce (bez ohledu na velikost písmen) a vrátí hodnotu podle stejných pravidel (menší než 0, je li první řetězec abecedně před druhým, atd.), jako potřebujeme zapsat do proměnné Compare.

Nakonec ještě z případě sestupného třídění výsledek vynásobíme -1, aby byla inverze vzata v úvahu.

Třídění aktivujeme tím, že na konec procedur TForm1.ShowBtnClick a TForm1.OnColumnClick přidáme volání metody FileView.AlphaSort.

Huh...

Dnešní díl byl trochu delší a náročnější na pochopení (pro začátečníky asi hlavně práce s ukazateli), doporučuji proto prozkoumat důkladně zdrojový kód aplikace.

Příště se podíváme na třídění podle zbylých kritérií.

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Delphi  

 » Rubriky  » Windows  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: