Einzelnen Beitrag anzeigen

taaktaak

Registriert seit: 25. Okt 2007
Ort: Radbruch
1.990 Beiträge
 
Delphi 7 Professional
 
#9

Re: TreeView mit Find und Filter

  Alt 13. Mär 2008, 18:46
Moin, Moin xX0815Xx,
hier mal der relevante Ausschnitt der Suchprozedur...

Delphi-Quellcode:
.
..
SetHourglass(true);

SetLength(FindList,0);

for i:=0 to pred(TreeView~~.Items.Count) do
  if MatchStr(TreeView~~.Items[i].Text,Pattern,CaseSensitive) then begin
    SetLength(FindList,High(FindList)+2);
    FindList[High(FindList)]:=i
    end;

SetHourglass(false);

N:=High(FindList)+1;
if N=0 then Dialog(1,-1,-1,1,-1,
                  'No matching tree item found ...',
                  'Ok','','','')

       else ...
Der Prozedur wird das Suchmuster in "Pattern" und der Status der Checkbox in "CaseSensitive" übergeben. Wesentlich ist lediglich die Schleife, für jedes gefundene Item wird dessen TreeIndex in ein dynamisches Array abgelegt, damit dann mittels der beiden Buttons FindPrev FindNext alle Fundstellen angezeigt werden können. Dialog() ist eine spezielle Anzeigefunktion, also so was ähnliches wie ShowMessage(). Obwohl die Verwendung von TreeView.Items ziemlich langsam ist, ist die Geschwindigkeit auch bei mehreren tausend TreeItems noch akzeptabel.


Die Funktion MatchStr() ist für den Zeichenkettenvergleich (incl. WildCards) zuständig.

Delphi-Quellcode:
function MatchStr(Source,Pattern:String;CaseSensitive:Boolean):Boolean;

  function Match(Source,Pattern:PChar):Boolean;
  begin
    if StrComp(Pattern,'*')=0 then Result:=true
                              else
      if (Source^=Chr(0)) and
         (Pattern^<>Chr(0)) then Result:=false
                            else
        if Source^=Chr(0) then Result:=true
                          else
          case Pattern^ of
          '*': if Match(Source,@Pattern[1]) then Result:=true
                                            else Result:=Match(@Source[1],Pattern);
          '?': Result:=Match(@Source[1],@Pattern[1]);
  
          else if Source^=Pattern^ then Result:=Match(@Source[1],@Pattern[1])
                                   else Result:=false;
          end;
  end;

begin
  if not(CaseSensitive) then begin
    Source :=AnsiLowerCase(Source);
    Pattern:=AnsiLowerCase(Pattern);
    end;

  Result:=Match(PChar(Source),PChar(Pattern))
end;
An der Filterfunktion bastle ich übrigens noch. Da die TreeViewNodes keine Visible-Eigenschaft haben, müssen für die gefilterte Anzeige alle "nicht passenden" Nodes aus dem Tree entfernt werden. Das kann mit Item.Delete natürlich innerhalb einer Schleife ohne Aufwand realisiert werden - ist aber inakzeptabel langsam.

Zuerst hatte ich das Filtern dann mit einem Stream und einer Stringlist realisiert: Die Geschwindigkeit war daraufhin etwa 50-60 mal schneller. Das Vorgehen hatte aber den Nachteil, dass die "übrigen" Node-Informationen wie .ImageIndex, .SelectedIndex, .StateIndex und .Data verloren gingen. Ist natürlich ebenfalls nicht praktikabel.

Derzeit werden diese Daten in einem zusätzlichen Record-Array "gerettet" und wiederhergestellt. Dadurch ist es wieder etwas langesamer, aber immer noch ausreichend schnell.

Da das Ganze jetzt aber sehr "aufgebläht" ist, bastle ich derzeit an einer Lösung mit dem ObjectStream - der diese Informationen ja beinhaltet. Da es mir nicht gelungen ist, den Source der Speicherung gänzlich nachzuvollziehen, versuche ich derzeit das Schema der Binärdaten im Stream aufzuschlüsseln. Wenn das gelungen ist und das alles mit dem ObjectStream realisiert werden kann, werde ich den Source -sofern Interesse besteht- auch zur Verfügung stellen.
Ralph
  Mit Zitat antworten Zitat