[Lazarus] TShellTreeView and TTreeView
cyberpython
cyberpython at gmail.com
Mon Dec 8 19:47:25 CET 2008
Felipe Monteiro de Carvalho wrote:
> Hello,
>
> I am trying to implement TShellTreeView. It is a treeview which shows
> the directory structure in the prefered way of the operating system.
> In Windows that would start with My Computer, etc...
>
> One problem now is with the design. Should it read all existing
> directories (which will cause a delay) or only those visible, or one
> or two levels at once... what do you think? Reading everything may be
> problematic with removable media.
>
> Another problem is using TTreeView. I searched by I can't find how I
> would implement this behavior, for example, having the root and 1
> level visible and then when the user clicks the + symbol the subitems
> for this item are loaded. Should I use the OnExpanding event? In the
> event handler I would create the subitems? A tutorial would be
> great...
>
> thanks,
>
Well, I know it is utter crap as far as performance is concerned (and
design and many other things :) ), but you could take a look at the code
below (I had posted it on the forum too):
{
/***************************************************************************
TDirectoryTreeview.pas
----------
Component For Displaying A Tree Of Directories In A FileSystem
----------
by George "cyberpython" Migdos
***************************************************************************/
*****************************************************************************
*
*
*
* See the Lazarus Distribution
COPYING.modifiedLGPL, *
* for details about the
copyright. *
*
*
* This code is distributed in the hope that it will be
useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty
of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. *
*
*
*****************************************************************************
}
unit DirectoryTreeview;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, ComCtrls, Dialogs;
type
{ TDirectoryTreeview }
TDirectoryTreeview = class(TTreeview)
private
{ Private declarations }
FRootDirs: TStrings;
FShowHidden : Boolean;
FShowSelf : Boolean;
FShowParent : Boolean;
FFolderImageIndex : Integer;
FFolderOpenImageIndex : Integer;
FFolderSelectedImageIndex : Integer;
FFolderOpenSelectedImageIndex : Integer;
FRootDirectories : TStrings;
procedure SetRootDirs(Value : TStrings);
procedure SetFolderImageIndex(const NewIndex: Integer);
procedure SetFolderOpenImageIndex(const NewIndex: Integer);
procedure SetFolderSelectedImageIndex(const NewIndex: Integer);
procedure SetFolderOpenSelectedImageIndex(const NewIndex: Integer);
function searchForFolders(ParentFolder : String; showHidden,
includeSelf, includeParent : boolean) : TStringList;
function getNodePath(Node : TTreeNode) : String;
function getChildNodeByData(NodeParent : TTreeNode; data :
Pointer):TTreeNode;
procedure populateTreeView(root : TTreeNode; CurrentDepth, MaxDepth
: LongInt);
protected
{ Protected declarations }
procedure DoPaintNode(Node: TTreeNode);override;
public
{ Public declarations }
constructor Create(AnOwner: TComponent);override;
destructor Destroy;override;
function getPath : String;
published
{ Published declarations }
property RootDirectories: TStrings read FRootDirs write SetRootDirs;
property ShowHidden: Boolean read FShowHidden write FShowHidden;
property ShowSelf: Boolean read FShowSelf write FShowSelf;
property ShowParent: Boolean read FShowParent write FShowParent;
property FolderImageIndex : Integer read FFolderImageIndex write
SetFolderImageIndex;
property FolderOpenImageIndex : Integer read FFolderOpenImageIndex
write SetFolderOpenImageIndex;
property FolderSelectedImageIndex : Integer read
FFolderSelectedImageIndex write SetFolderSelectedImageIndex;
property FolderOpenSelectedImageIndex : Integer read
FFolderOpenSelectedImageIndex write SetFolderOpenSelectedImageIndex;
end;
procedure Register;
implementation
procedure removeBlankLinesFromTheBottom(Strings : TStrings);
var
i : integer;
reachedLast: boolean;
begin
reachedLast := false;
i:=Strings.Count-1;
while( (i>=0)AND(not reachedLast) )do
begin
if(Strings.Strings[i]='')then
begin
Strings.Delete(i);
end
else
reachedLast:=true;
i:=i-1;
end;
end;
function TDirectoryTreeview.searchForFolders(ParentFolder : String;
showHidden, includeSelf, includeParent : boolean) : TStringList;
var
searchResult : TSearchRec;
res : TStringList;
begin
res:=TStringList.Create;
if(directoryExists(ParentFolder))then
begin
if FindFirst(ParentFolder+PathDelim+'*', faAnyFile, searchResult) = 0
then
begin
repeat
if ( (searchResult.Attr AND faDirectory) > 0 ) then
begin
if ( searchResult.Name = '.') then
begin
if(includeSelf)then
res.Add(searchResult.Name);
end
else if (searchResult.Name = '..')then
begin
if(includeParent)then
res.Add(searchResult.Name);
end
else
begin
if(length(searchResult.Name) > 0)then
begin
{$ifdef Win32}
if ( not showHidden )then
begin
if ( (searchResult.Attr AND faHidden) <= 0 )then
begin
res.Add(searchResult.Name);
end;
end
else
begin
res.Add(searchResult.Name);
end;
{$endif}
{$ifdef Unix}
if(not showHidden)then
begin
if(searchResult.Name[1] <> '.')then
begin
res.Add(searchResult.Name);
end;
end
else
begin
res.Add(searchResult.Name);
end;
{$endif}
end;
end;
end;
until FindNext(searchResult) <> 0;
FindClose(searchResult);
end;
end;
result:=res;
end;
function TDirectoryTreeview.getNodePath(Node : TTreeNode) : String;
var
rootDir : String;
n : TTreeNode;
begin
n:=Node;
rootDir:= PChar(n.Data);
while (n.Parent <> nil)do
begin
n:=n.Parent;
if( pChar(n.Data) <> PathDelim)then
rootDir:=PChar(n.Data)+PathDelim+rootDir
else
rootDir:=PChar(n.Data)+rootDir;
end;
result:=rootDir;
end;
function TDirectoryTreeview.getChildNodeByData(NodeParent : TTreeNode;
data : Pointer): TTreeNode;
var
n : TTreeNode;
found : boolean;
d : String;
res : TTreeNode;
begin
res:=nil;
n:=NodeParent.GetFirstChild;
found := false;
d := PChar(data);
while( (n <> nil) and (found=false) )do
begin
if(PChar(n.Data) = d)then
begin
found:=true;
res:=n;
end;
n:=n.GetNextSibling;
end;
result:=res;
end;
procedure TDirectoryTreeview.populateTreeView(root : TTreeNode;
CurrentDepth, MaxDepth : LongInt);
var
i: integer;
res: TStringList;
dirname : string;
n, ch, tmpNode : TTreeNode;
rootDir : String;
begin
rootDir := getNodePath(root);
if(directoryExists(rootDir))then
begin
if(CurrentDepth=0)then
Items.BeginUpdate;
res := searchForFolders(rootDir, FShowHidden, FShowSelf, FShowParent);
//remove the nodes that represent deleted directories
//
tmpNode:=root.GetFirstChild;
while(tmpNode <> nil)do
begin
n:=tmpNode;
tmpNode:=tmpNode.GetNextSibling;
if(res.IndexOf(pChar(n.Data)) < 0 )then
begin
n.Delete;
end;
end;
//
for i:= 0 to res.Count-1 do
begin
dirname:= res.Strings[i];
if(length(dirname) > 0)then
begin
tmpNode:= getChildNodeByData(root, PChar(dirname));
if( tmpNode = nil )then
begin
n:=Items.AddChild(root, res.Strings[i]);
n.Data:=pChar(res.Strings[i]);
n.ImageIndex:=self.FFolderImageIndex;
n.SelectedIndex:=self.FFolderSelectedImageIndex;
end;
end;
end;
if(CurrentDepth < MaxDepth)then
begin
if(root.Count>0)then
begin
ch:= root.GetFirstChild;
while(ch <> nil)do
begin
populateTreeView(ch, CurrentDepth+1, MaxDepth);
ch:=ch.GetNextSibling;
end;
end;
end;
root.AlphaSort;
if(CurrentDepth=0)then
Items.EndUpdate;
res.Free;
end;
end;
constructor TDirectoryTreeview.Create(AnOwner: TComponent);
begin
inherited;
FRootDirs := TStringList.Create;
FRootDirectories := TStringList.Create;
ShowHidden := false;
ShowSelf:=false;
ShowParent:=false;
FolderImageIndex := -1;
FolderOpenImageIndex := -1;
FolderSelectedImageIndex := -1;
FolderOpenSelectedImageIndex := -1;
end;
destructor TDirectoryTreeview.Destroy;
begin
FRootDirectories.Free;
FRootDirs.Free;
inherited;
end;
procedure TDirectoryTreeview.SetRootDirs(Value : TStrings);
var
i : integer;
n : TTreeNode;
tmp2 : TStringList;
imgIndex, SelImgIndex : integer;
begin
FRootDirs.Assign(Value);
removeBlankLinesFromTheBottom(FRootDirs);
FRootDirectories.Clear;
tmp2:=TStringList.Create;
tmp2.Delimiter:=',';
if((FRootDirs.Count mod 3)=0)then
begin
Items.Clear;
i:=0;
while(i< FRootDirs.Count-1) do
begin
tmp2.Clear;
tmp2.DelimitedText:=FRootDirs.Strings[i+2];
n:=Items.Add(nil,FRootDirs.Strings[i]);
FRootDirectories.Add(FRootDirs.Strings[i+1]);
n.Data:=pChar(FRootDirectories.Strings[FRootDirectories.Count-1]);
if(tmp2.Count = 2)then
begin
Try
imgIndex:=strtoint(tmp2.Strings[0]);
SelImgIndex:=strtoint(tmp2.Strings[1]);
except
on E : Exception do
begin
imgIndex:=self.FFolderImageIndex;
SelImgIndex:=self.FFolderSelectedImageIndex;
end;
end;
end
else
begin
imgIndex:=self.FFolderImageIndex;
SelImgIndex:=self.FFolderSelectedImageIndex;
end;
n.ImageIndex:=imgIndex;
n.SelectedIndex:=SelImgIndex;
populateTreeView(n, 0, 2);
i:=i+3;
end;
n:=Items.GetFirstNode;
if(n <> nil)then
begin
n.Expand(false);//remove this if you activate the while loop
while(n <> nil)do
begin
//n.Expand(false);
self.DoPaintNode(n);
n:= n.GetNextSibling;
end;
end;
end
else
showMessage('Invalid root directories!');
tmp2.Free;
self.DoPaint;
self.Repaint;
end;
function TDirectoryTreeview.getPath : String;
begin
if(Selected <> nil)then
result:= getNodePath(Selected);
end;
procedure TDirectoryTreeview.SetFolderImageIndex(const NewIndex: Integer);
begin
FFolderImageIndex := NewIndex;
end;
procedure TDirectoryTreeview.SetFolderOpenImageIndex(const NewIndex:
Integer);
begin
FFolderOpenImageIndex := NewIndex;
end;
procedure TDirectoryTreeview.SetFolderSelectedImageIndex(const NewIndex:
Integer);
begin
FFolderSelectedImageIndex := NewIndex;
end;
procedure TDirectoryTreeview.SetFolderOpenSelectedImageIndex(const
NewIndex: Integer);
begin
FFolderOpenSelectedImageIndex := NewIndex;
end;
procedure TDirectoryTreeview.DoPaintNode(Node: TTreeNode);
begin
populateTreeView(Node, 0, 2);
if(Node.Parent<>nil)then
begin
if(Node.Expanded)then
begin
Node.ImageIndex:=self.FFolderOpenImageIndex;
Node.SelectedIndex:=self.FFolderOpenSelectedImageIndex;
end
else
begin
Node.ImageIndex:= self.FFolderImageIndex;
Node.SelectedIndex:=self.FFolderSelectedImageIndex;
end;
end;
inherited;
end;
procedure Register;
begin
RegisterComponents('Misc', [TDirectoryTreeview]);
end;
end.
More information about the Lazarus
mailing list