Работа с TreeView — создание дерева каталогов
Работа с TreeView — создание дерева каталогов
Работа с TreeView - создание дерева каталогов Источник: http://decoding.narod.ru/practic/treeview/treeview.html Сегодня нам предстоит знакомство с одним очень интересным компонентом 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; Рассмотрим некоторые полезные свойства этого компонента: ° TreeView1.Items.BeginUpdate - блокирует обновление экрана до тех пор, пока не будет выполнен метод EndUpdate. Используется при одновременной вставке нескольких элементов списка для предотвращения мерцания экрана. ° TreeView1.Items.EndUpdate - отменяет действие метода BeginUpdate. ° TreeView1.FullExpand - показывает все узлы дерева иерархии. ° TreeView1.FullCollapse - прячет все узлы, кроме узлов самого верхнего уровня иерархии. Вернемся к дереву каталогов. Первое, что мы сделаем при запуске программы, выведем в TreeView список всех дисков, имеющихся на компьютере. На этом этапе мы не станем проверять наличие каталогов на дисках, так как такая проверка на дисководе займет много времени. Проверять наличие каталогов будем в момент раскрытия узла. В свою очередь, в найденный каталогах мы попытаемся найти хоть одну папку. От результата поиска зависит, появится в данном узле знак "+", говорящий о наличии подкаталогов, или нет. Иконки для TreeView будем брать из файла FileCtrl.res, находящемся в каталоге "Delphi6lib". 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 ) ); 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; Закрыть его вновь тоже не составит проблемы. procedure TForm1.Button2Click(Sender: TObject); begin with TreeView1 do begin Items.BeginUpdate; FullCollapse; Items.EndUpdate; end;