15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Компонент DirectoryTree.

Автор: Maarten de Haan

Данный компонент действует и выглядит аналогично левой части окна Проводника в Windows. Компонент позволяет выбирать диск (дисковод) и / или директорию и реагировать на событие
OnChange. Компонент правильно работает даже во время прорисовки, то есть не даст открыть диск во время прорисовки.

Скачать компонент - 14 Kb

Совместимость: Delphi 5.x (или выше)

Компонент тестировался под Windows 95A (SP1) и Windows NT (4.0 SP5).

Компонент будет зарегистрирован как 'Samples'.
---------------------------------------------------------------------}

Unit DirectoryTree;

{$R-,T-,H+,X+}

Interface

Uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
   Dialogs, ComCtrls, ImgList, StdCtrls, FileCtrl;

Const
   Rootname : String = 'My Computer';

Type
   TDirectoryTree = class(TCustomTreeView)
   private
   { Private declarations }
      fImageList                 : TCustomImageList;
      fDirectory                 : String;
      fOnChange                  : TNotifyEvent;
      fDirLabel                  : TLabel;
      fDirLabelSet               : Boolean;
      fFileList                  : TFileListbox;
      fDirList                   : TDirectoryTree;
      fTreenodes                 : TTreenodes;
      fCurDrive                  : String;

      //Procedure SetDirLabel(Value : TLabel);
      //Procedure SetDirLabelCaption;
      Procedure FindDirs(S : String; T : TTreenode);
      Procedure GetNodeInfo(T : TTreenode);
      Procedure fChanges; dynamic;
      //Procedure SetFileListBox(Value : TFileListBox);
      //Function MinimizeName(const Filename : TFileName;
      //   Canvas : TCanvas; MaxLen : Integer): TFileName;
      //procedure CutFirstDirectory(var S : TFileName);

   Protected
   { Protected declarations }
      Procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
         X, Y: Integer); override;

   Public
   { Public declarations }
      Constructor Create(AOwner : TComponent); override;
      Destructor Destroy; override;
      Procedure UpDate; reintroduce;
      Procedure FindDrives; dynamic;
      Procedure CreateWnd; override;

   Published
   { Published declarations }
      {--- свойства ---}
      Property Align;
      Property Anchors;
      //Property AutoExpand;
      //Property BiDiMode;
      //Property BorderStyle;
      //Property BorderWidth;
      //Property ChangeDelay;
      Property Color;
      Property Constraints;
      Property Cursor;
      //Property DirLabel : TLabel
      //   read fDirLabel write SetDirLabel;
      Property Directory : String
         read fDirectory write fDirectory;
      Property DragCursor;
      Property DragKind;
      Property DragMode;
      Property Enabled;
      //Property FileList : TFileListbox
      //   read fFileList write SetFileListbox;
      Property Font;
      Property Height;
      Property HelpContext;
      //Property HideSelection;
      Property Hint;
      //Property HotTrack;
      //Property Images;
      //Property Indent;
      //Property Items;
      Property Left;
      Property Name;
      //Property ParentBiDiMode;
      Property ParentColor;
      Property ParentFont;
      Property ParentShowHint;
      Property PopupMenu;
      //Property ReadOnly;
      //Property RightClickSelect;
      //Property RowSelect;
      //Property ShowButtons;
      Property ShowHint;
      //Property ShowLines;
      //Property ShowRoot;
      //Property SortType;
      //Property StateImages;
      Property TabOrder;
      Property TabStop;
      Property Tag;
      //Property ToolTips;
      Property Top;
      Property Visible;
      Property Width;
      {--- События ---}
      //Property OnAdvancedCustomDraw;
      //Property OnAdvancedCustomDrawItem;
      Property OnChange : TNotifyEvent
         read fOnChange write fOnChange;
      //Property OnChanging;
      Property OnClick;
      //Property OnCollapsed;
      //Property OnCollapsing;
      //Property OnCompare;
      //Property OnContextPopup;
      //Property OnCustomDraw;
      //Property OnCustomDrawItem;
      Property OnDblClick;
      //Property OnDeletion;
      Property OnDragDrop;
      Property OnDragOver;
      //Property OnEdited;
      //Property OnEditing;
      //Property OnEndDock;
      Property OnEndDrag;
      Property OnEnter;
      Property OnExit;
      //Property OnExpanded;
      //Property OnExpanding;
      //Property OnGetImageIndex;
      //Property OnGetSelectedIndex;
      Property OnKeyDown;
      Property OnKeyPress;
      Property OnKeyUp;
      Property OnMouseDown;
      Property OnMouseMove;
      Property OnMouseUp;
      //Property OnStartDock;
      Property OnStartDrag;
      End;

Procedure Register;

// Загружаем bitmap-ы, 16 x 16 бит, 256 цветов
{$R IMAGES.RES}

Implementation

{--------------------------------------------------------------------}
(* Из исходников Delphi 5:
   c:\program files\borland\delphi5\source\vcl\filectrl.pas

Procedure TDirectoryTree.SetFileListBox(Value: TFileListBox);

Begin
If fFileList <> nil then
   fFileList.DirList := nil;
fFileList := Value;
If fFileList <> nil then
   Begin
   fFileList.DirList := Self;
   fFileList.FreeNotification(Self);
   End;
End; *)
{--------------------------------------------------------------------}
(* Из исходников Delphi 5:
   c:\program files\borland\delphi5\source\vcl\filectrl.pas

Procedure CutFirstDirectory(var S: TFileName);

Var
  Root  : Boolean;
  P     : Integer;

Begin
If S = '\' then
   S := ''
else
   Begin
   If S[1] = '\' then
      Begin
      Root := True;
      Delete(S, 1, 1);
      End
   else
      Root := False;
   If S[1] = '.' then
      Delete(S, 1, 4);
   P := AnsiPos('\',S);
   If P <> 0 then
      Begin
      Delete(S, 1, P);
      S := '...\' + S;
      End
   else
      S := '';
   If Root then
      S := '\' + S;
   End;
End; *)
{--------------------------------------------------------------------}
(* Из исходников Delphi 5:
   c:\program files\borland\delphi5\source\vcl\filectrl.pas

Function MinimizeName(const Filename: TFileName; Canvas: TCanvas;
  MaxLen: Integer): TFileName;

Var
   Drive        : TFileName;
   Dir          : TFileName;
   Name         : TFileName;

Begin
Result := FileName;
Dir := ExtractFilePath(Result);
Name := ExtractFileName(Result);

If (Length(Dir) >= 2) and (Dir[2] = ':') then
   begin
   Drive := Copy(Dir, 1, 2);
   Delete(Dir, 1, 2);
   end
else
   Drive := '';
While ((Dir <> '') or (Drive <> '')) and
     (Canvas.TextWidth(Result) > MaxLen) do
   Begin
   If Dir = '\...\' then
      Begin
      Drive := '';
      Dir := '...\';
      End
   else
      If Dir = '' then
         Drive := ''
      else
         CutFirstDirectory(Dir);
   Result := Drive + Dir + Name;
   End;
End; *)
{--------------------------------------------------------------------}
(* Из исходников Delphi 5:
   c:\program files\borland\delphi5\source\vcl\filectrl.pas

Procedure TDirectoryTree.SetDirLabel (Value: TLabel);

Begin
fDirLabel := Value;
if Value <> nil then
   Value.FreeNotification(Self);
SetDirLabelCaption;
End;
*)
{--------------------------------------------------------------------}
(* Из Delphi:
   c:\program files\borland\delphi5\source\vcl\filectrl.pas

Procedure TDirectoryTree.SetDirLabelCaption;

Var
   DirWidth: Integer;

Begin
If fDirLabel <> nil then
   Begin
   DirWidth := Width;
   If not fDirLabel.AutoSize then
      DirWidth := fDirLabel.Width;
   fDirLabel.Caption := MinimizeName(Directory, fDirLabel.Canvas,
      DirWidth);
   End;
End; *)
{--------------------------------------------------------------------}
Procedure TDirectoryTree.fChanges;

Begin
If Assigned(fOnChange) then
   fOnChange(Self);
End;
{--------------------------------------------------------------------}
Procedure TDirectoryTree.FindDirs(S : String; T : TTreenode);

Var
   Res         : Integer;
   SR          : TSearchRec;
   T1          : TTreenode;
   S1          : String;

Begin
S1 := S;
If S[Length(S)] <> '\' then
   S1 := S1 + '\';
Res := FindFirst(S1 + '*.*',faAnyFile,SR);

If Res = 0 then
   Repeat
      If ((SR.Attr and faDirectory) = faDirectory) then
         If (SR.Name <> '.') and (SR.Name <> '..') then
            Begin
            T1 := Items.AddChild(T,SR.Name);
            T1.SelectedIndex := 1;  // Diropen.bmp when selected
            T1.HasChildren := True; // Creates a '+' sign
            End;
      Res := FindNext(SR);
   Until Res <> 0;

FindClose(SR);
End;
{--------------------------------------------------------------------}
Procedure TDirectoryTree.GetNodeInfo(T : TTreenode);

Var
   S      : String;
   T1     : TTreenode;

Begin
S := T.Text;
If S = Rootname then
   Exit;
T1 := T;
Repeat
   T1 := T1.Parent;
   If S[2] <> ':' then
      S := T1.Text + '\' + S;
Until S[2] = ':';

If T.Count = 0 then
   FindDirs(S,T);

fDirectory := S;
fChanges;
End;
{--------------------------------------------------------------------}
Procedure TDirectoryTree.FindDrives;

Var
   Tr,T1                : TTreenode;
   ld                   : DWord;
   I                    : Integer;
   Drive                : String;

Begin
Items.Clear;
ld := GetLogicalDrives;
Tr := Items.Add(nil,Rootname);
Tr.ImageIndex := 2;
Tr.SelectedIndex := 2;
For I := 0 to 25 do
   Begin
   If (ld and (1 shl I)) > 0 then
      Begin
      Drive := Chr(65 + I) + ':';

      T1 := Items.AddChild(Tr,Drive);
      T1.HasChildren := True;
      // Корректируем иконку диска
      Case GetDriveType(PChar(Drive[1] + ':\')) of
          0,DRIVE_FIXED :      Begin
                               T1.ImageIndex := 3;
                               T1.SelectedIndex := 3;
                               End;

          DRIVE_CDROM :        Begin
                               T1.ImageIndex := 4;
                               T1.SelectedIndex := 4;
                               End;

          DRIVE_REMOVABLE :    Begin
                               T1.ImageIndex := 5;
                               T1.SelectedIndex := 5;
                               End;

          DRIVE_RAMDISK:       Begin
                               T1.ImageIndex := 6;
                               T1.SelectedIndex := 6;
                               End;

          DRIVE_REMOTE :       Begin
                               T1.ImageIndex := 7;
                               T1.SelectedIndex := 7;
                               End;
         End; // конец Case
      If fCurDrive = Drive then
         T1.Selected := True; // Выбираем текущий диск
      End;
   End;

End;
{--------------------------------------------------------------------}
Constructor TDirectoryTree.Create(AOwner : TComponent);

Var
   bDirClose,bDirOpen         : TBitmap;
   bFloppy,bComputer          : TBitmap;
   bHardDisk,bCDRom           : TBitmap;
   bRemoteDrive,bRamdisk      : TBitmap;

Begin
inherited Create(AOwner);
ShowRoot := True;
ReadOnly := True;
SortType := stBoth;
fDirLabelSet := False;
fDirectory := '';
fImageList := TCustomImageList.Create(Self);
fImageList.Clear;
fImageList.BkColor := clWhite;
fImageList.BlendColor := clWhite;
fImageList.Masked := True;
fImageList.Height := 16;
fImageList.Width := 16;
fImageList.AllocBy := 7;

// Загружаем картинку DIRCLOSE
bDirClose := TBitmap.Create;
bDirClose.Handle := LoadBitmap(hInstance,'DIRCLOSE');
// Добавляем в ImageList
fImageList.Add(bDirClose,nil);     // 0
bDirClose.Free;

// Загружаем картинку DIROPEN
bDirOpen := TBitmap.Create;
bDirOpen.Handle := LoadBitmap(hInstance,'DIROPEN');
// Добавляем в ImageList
fImageList.Add(bDirOpen,nil);      // 1
bDirOpen.Free;

// Загружаем картинку COMPUTER
bComputer := TBitmap.Create;
bComputer.Handle := LoadBitmap(hInstance,'COMPUTER');
// Добавляем в ImageList
fImageList.Add(bComputer,nil);     // 2
bComputer.Free;

// Загружаем картинку HARDDISK
bHardDisk := TBitmap.Create;
bHardDisk.Handle := LoadBitmap(hInstance,'HARDDISK');
// Добавляем в ImageList
fImageList.Add(bHardDisk,nil);     // 3
bHardDisk.Free;

// Загружаем картинку CDROMDISK
bCDRom := TBitmap.Create;
bCDRom.Handle := LoadBitmap(hInstance,'CDROMDISK');
                                   // Со словом 'CDROM' возникают проблемы
// Добавляем в ImageList
fImageList.Add(bCDRom,nil);        // 4
bCDRom.Free;

// Загружаем картинку FLOPPYDISK
bFloppy := TBitmap.Create;
bFloppy.Handle := LoadBitmap(hInstance,'FLOPPYDISK');
                                   // bitmap с именем 'FLOPPY'
                                   // уже существует
// Добавляем в ImageList
fImageList.Add(bFloppy,nil);       // 5
bFloppy.Free;

// Загружаем картинку RAMDISK
bRamDisk := TBitmap.Create;
bRamDisk.Handle := LoadBitmap(hInstance,'RAMDISK');
// Добавляем в ImageList
fImageList.Add(bRamDisk,nil);      // 6
bRamDisk.Free;

// Загружаем картинку REMOTEDISK
bRemoteDrive := TBitmap.Create;
bRemoteDrive.Handle := LoadBitmap(hInstance,'REMOTEDISK');
// Добавляем в ImageList
fImageList.Add(bRemoteDrive,nil);  // 7
bRemoteDrive.Free;

Images := fImageList; // Assign the imagelist to TreeView.Images
// CustomTreeView не имеет никаких treenodes, поэтому мы должны создать их..
fTreenodes := TTreenodes.Create(Self);
End;
{--------------------------------------------------------------------}
Procedure TDirectoryTree.CreateWnd;

Var
   P : String;

Begin
inherited CreateWnd;
GetDir(0,P);
fCurDrive := UpCase(P[1]) + ':';
FindDrives; //Является динамическим!!
End;
{--------------------------------------------------------------------}
Procedure TDirectoryTree.MouseDown(Button: TMouseButton;
   Shift : TShiftState; X, Y: Integer);

Var
   T,T1           : TTreenode;
   S              : String;
   HT             : THitTests;
   I              : Integer;

Begin
inherited MouseDown(Button,Shift,X,Y);
HT := GetHitTestInfoAt(X,Y);
If (htOnItem in HT) or (htOnIcon in HT) or (htOnButton in HT) then
   Begin
   T := GetNodeAt(X,Y);
   S := T.Text;
   If S = Rootname then
      Exit;
   T1 := T;
   Repeat
      T1 := T1.Parent;
      If S[2] <> ':' then
         S := T1.Text + '\' + S;
   Until S[2] = ':';
   fDirectory := S;
   fChanges;
   I := T.Count;
   GetNodeInfo(T);
   T.Selected := True;
   If T.Count > 0 then
      Begin
      If I = 0 then
         T.Expanded := True;
      End
   else
      T.HasChildren := False; // удаляем знаки '-' или '+'
   End;
End;
{--------------------------------------------------------------------}
Procedure TDirectoryTree.Update;

Var
   P : String;

Begin
GetDir(0,P);
fCurDrive := UpCase(P[1]) + ':';
ChDir(fCurDrive);
FindDrives;
fChanges;
End;
{--------------------------------------------------------------------}
Destructor TDirectoryTree.Destroy;

Begin
fImageList.Free; // Удаляем ImageList
fTreenodes.Free; // Удаляем Treenodes
inherited Destroy;
End;
{--------------------------------------------------------------------}
Procedure Register;

Begin
RegisterComponents('Samples', [TDirectoryTree]);
End;
{--------------------------------------------------------------------}
End.
{====================================================================}