Практика
Работа с TreeView - создание дерева каталогов

:: Меню ::
:: На главную ::
:: FAQ ::
:: Заметки ::
:: Практика ::
:: Win API ::
:: Проекты ::
:: Скачать ::
:: Секреты ::
:: Ссылки ::

:: Сервис ::
:: Написать ::

:: MVP ::

:: RSS ::

Яндекс.Метрика


Сегодня нам предстоит знакомство с одним очень интересным компонентом Delphi - TreeView. TreeView служит для показа ветвящихся иерархических структур, например - файловой структуры диска. TreeView содержит основные узлы, каждый из которых может содержать пиктограмму, текст и произвольный объект, и в свою очередь может иметь собственный список подузлов.

Для ввода списка в режиме прогона программы можно использовать свойство Item типа TTreeNodes, открывающее индексированный доступ ко всем узлам списка. Ниже приведен простой пример на использование этого свойства.

procedure TForm1.FormCreate(Sender: TObject);
var
  i: integer;
begin
   with TreeView1 do
   begin
      // Добавляем корневой узел
      Items.Add( nil, 'Корень' );
      // Добавляем 10 вложенных узлов
      for i := 1 to 10 do
         Items.AddChild( Items[i-1], IntToStr( i ) );
   end;
end;

Рассмотрим некоторые полезные свойства этого компонента:
  • TreeView1.Items.BeginUpdate - блокирует обновление экрана до тех пор, пока не будет выполнен метод EndUpdate. Используется при одновременной вставке нескольких элементов списка для предотвращения мерцания экрана.
  • TreeView1.Items.EndUpdate - отменяет действие метода BeginUpdate.
  • TreeView1.FullExpand - показывает все узлы дерева иерархии.
  • TreeView1.FullCollapse - прячет все узлы, кроме узлов самого верхнего уровня иерархии.
Вернемся к дереву каталогов. Первое, что мы сделаем при запуске программы, выведем в TreeView список всех дисков, имеющихся на компьютере. На этом этапе мы не станем проверять наличие каталогов на дисках, так как такая проверка на дисководе займет много времени. Проверять наличие каталогов будем в момент раскрытия узла. В свою очередь, в найденный каталогах мы попытаемся найти хоть одну папку. От результата поиска зависит, появится в данном узле знак "+", говорящий о наличии подкаталогов, или нет. Иконки для TreeView будем брать из файла FileCtrl.res, находящемся в каталоге "Delphi6\lib".

implementation

{$R *.dfm}
{$R FileCtrl}

procedure TForm1.FormCreate(Sender: TObject);
const
  IconNames: array [0..6] of string = ( 'CLOSEDFOLDER',
                                        'OPENFOLDER',
                                        'FLOPPY',
                                        'HARD',
                                        'NETWORK',
                                        'CDROM',
                                        'RAM' );
var
  node: TTreeNode;
  DriveType: integer;
  bm, mask: TBitmap;
  i: integer;
begin
   // Запрещаем обновление TreeView
   TreeView1.Items.BeginUpdate;
   // Создаем список иконок
   TreeView1.Images := TImageList.CreateSize( 16, 16 );
   bm := TBitmap.Create;
   mask := TBitmap.Create;
   for i := 0 to 6 do
   begin
      bm.Handle := LoadBitmap( HInstance, PChar( IconNames[i] ) );
      bm.Width := 16;
      bm.Height := 16;
      mask.Assign( bm );
      mask.Mask( clBlue );
      TreeView1.Images.Add( bm, mask );
   end;
   bm.Free;
   mask.Free;
   // Находим диски и выводим их в TreeView
   for i := 0 to 25 do
   begin
      DriveType := GetDriveType( PChar( Chr( i + 65 ) + ':\' ) );
      if DriveType = 1 then continue;
      node := Form1.TreeView1.Items.AddChild( nil, Chr( i+65 ) + ':' );
      case DriveType of
         DRIVE_REMOVABLE: node.ImageIndex := 2;
         DRIVE_FIXED: node.ImageIndex := 3;
         DRIVE_REMOTE: node.ImageIndex := 4;
         DRIVE_CDROM: node.ImageIndex := 5;
         else
            node.ImageIndex := 6;
      end;
      node.SelectedIndex := node.ImageIndex;
      node.HasChildren := true;
   end;
   // Обновляем TreeView
   TreeView1.Items.EndUpdate;
end;

При раскрытии узла возникает событие onExpanding, которое мы и будем обрабатывать. Такой подход лучше, чем загружать всю структуру каталогов сразу. Это связано с тем, что во время работы программы пользователь может изменить структуру каталогов, и чтобы программа адекватно реагировала на подобные изменения, нужно производить поиск каталогов следующего уровня при каждом раскрытии узла.

procedure NextLevel(ParentNode: TTreeNode);
var
  sr, srChild: TSearchRec;
  node: TTreeNode;
  path: string;
begin
   node := ParentNode;
   path := '';
   repeat
      path := node.Text + '\' + path;
      node := node.Parent;
   until node = nil;
   // Находим первую директорию
   if FindFirst( path + '*.*', faDirectory, sr ) = 0 then
   begin
      repeat
         if ( sr.Name <> '.' ) and ( sr.Name <> '..' ) then
            if ( sr.Attr and faDirectory ) = faDirectory then
            begin
               // Добавляем найденную папку в TreeView
               node := Form1.TreeView1.Items.AddChild( ParentNode, sr.Name );
               node.ImageIndex := 0;
               node.SelectedIndex := 1;
               // Утверждаем, что нет подкаталогов
               node.HasChildren := false;
               // Проверяем, так ли это
               if FindFirst( path + sr.Name + '\*.*', faDirectory, srChild ) = 0 then
               begin
                  repeat
                     if ( srChild.Name <> '.' ) and ( srChild.Name <> '..' ) then
                        if ( srChild.Attr and faDirectory ) = faDirectory then
                           node.HasChildren := true;
                  until ( FindNext( srChild ) <> 0 ) or node.HasChildren;
               end;
               FindClose( srChild );
            end;
      until FindNext( sr ) <> 0;
   end
   else
      ParentNode.HasChildren := false;
   FindClose( sr );
end;

procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode;
  var AllowExpansion: Boolean);
begin
   TreeView1.Items.BeginUpdate;
   node.DeleteChildren;
   NextLevel( node );
   TreeView1.Items.EndUpdate;
end;

Теперь, если мы захотим просмотреть все получившееся дерево, то воспользуемся следующим кодом, который полностью раскрывает дерево.

procedure TForm1.Button1Click(Sender: TObject);
begin
   with TreeView1 do
   begin
      Items.BeginUpdate;
      FullExpand;
      Items.EndUpdate;
   end;
end;

Закрыть его вновь тоже не составит проблемы.

procedure TForm1.Button2Click(Sender: TObject);
begin
   with TreeView1 do
   begin
      Items.BeginUpdate;
      FullCollapse;
      Items.EndUpdate;
   end;
end;

Подведем итог. Задача построения структуры каталогов в виде дерева с использованием TreeView оказалась не сложной. Разберитесь получше с этим примером, и многие вопросы, связанные с использованием TreeView исчезнут. Удачи.

.: Пример к данной статье :.


При использовании материала - ссылка на сайт обязательна