На этом шаге мы рассмотрим компонент TTreeView.
Компонент TTreeView (Дерево) используется для отображения сложных структур данных. Например таких, как структура каталогов в проводнике: слева иерархическая структура диска в виде раскрывающихся значков с символами "-" (развернут) и "+" (свернут), а справа - содержимое выбранного каталога в виде списка. Ниже перечислены свойства, управляющие формированием и отображением узлов дерева при проектировании.
Свойства компонента TTreeView.
Свойство | Описание |
---|---|
type TBorderStyle = (bsNone, bsSingle, bsDouble, bsRaisedPanel, bsSunkenPanel, bsRaised3d,
bsSunken3d, bsEtched, bsEmbossed); property BorderStyle: TBorderStyle; |
Определяет стиль рамки, охватывающей компонент (поэкспериментируйте) |
property DropTarget: TTreeNode; | Определяет узел, который может служить приемником для операций перетаскивания (Drag&Drop) |
property HideSelection: Boolean; | При значении True с элемента, теряющего фокус, снимается выделение |
property Images: TImageList; | Содержит набор изображений, которые будут использоваться при прорисовке узлов |
property Indent: Integer; | Определяет число пикселей для визуального разделения по горизонтали узлов дерева |
property Items: TTreeNodes; | Открывает доступ к любому узлу по его индексу. Индексация начинается с 0 и соответствует просмотру всех узлов полностью развернутого дерева |
property ReadOnly: Boolean; | Запрещает/разрешает редактирование надписей в узлах |
property ShowLines: Boolean; | Определяет наличие соединительных линий в иерархической последовательности (только VCL) |
property ShowButtons: Boolean; | Определяет наличие символов "+" или "-" |
property ShowRoot: Boolean; | Определяет отображение элементов верхнего уровня (только VCL) |
property SortType: TSortType; | Определяет вид сортировки:
|
property RightClickSelect: Boolean; | При значении True разрешается выделять узлы дерева с помощью правой кнопки мыши |
property ChangeDelay: Integer; | Пауза в миллисекундах между выделением узла дерева и генерацией сообщения OnChange. Обработка этого сообщения позволяет, например, отобразить содержимое данного узла в другой части формы |
property AutoExpand: Boolean; | При значении True выбранные узлы дерева будут автоматически разворачиваться, при этом ранее развернутые узлы будут свернуты |
Для создания подобных деревьев, отображающих иерархические структуры данных, в системе Delphi реализован компонент TTreeView. Начальная структура формируется на этапе проектирования в редакторе TreeView Items (Элементы дерева). Для каждого узла дерева можно указать изображение . Его номер указывается в поле редактора Imagelndex (Номер картинки), а сам список картинок задается в свойстве Images (для этого в форме должен находиться компонент TImageList). Дополнительно для каждого узла можно указать номер картинки, отражающей его выделенное состояние (свойство SelectedIndex), и номер картинки, дополнительно размещаемой слева от основной картинки (свойство Slatelndex, для которого определяется свой список изображений в свойстве StateImages). Значение -1, присвоенное этим свойствам по умолчанию, подавляет вывод изображений.
Доступ к узлам по номеру и особенно формирование новых элементов дерева во время работы программы требует значительных вычислительных ресурсов. Поэтому желательно выполнять основную часть работы по формированию структуры дерева на этапе проектирования.
Имена узлов можно редактировать как обычные названия объектов Windows. Узлы хранятся в свойстве Items, которое представляет класс TTreeNodes, содержащий свойство Item - массив объектов типа TTreeNode. Основные свойства класса TTreeNode приведены ниже.
Свойство | Описание |
---|---|
property AbsoluteIndex: Integer; | Абсолютный номер узла в дереве. Самый первый узел имеет номер 0, далее нумеруются все потомки этого узла. При этом, если у потомка есть подчиненные узлы, то нумерация продолжается с первого потомка |
property Count: Integer; | Число потомков узла |
property Cut: Boolean; | При значении True изображение для соответствующего узла отображается блекло, как при операциях Cut, Paste |
property Date: Pointer; | Свойство имеет тип Pointer, и указывает на связанный с узлом объект |
property Deleting: Boolean; | При значении True данный узел находится в состоянии удаления. Этот процесс может быть длительным, если удаляется узел с большим числом потомков |
property DropTarget: Boolean; | Содержит значение True, если узел может служить приемником операции перетаскивания (Drag&Drop) |
property Expanded: Boolean; | При значении True узел развернут, т.е. кнопка находится в состоянии "-" |
property Focused: Boolean; | При значении True узел получил фокус ввода |
property HasChildren: Boolean; | При значении True узел имеет потомков |
property ImageIndex: TImageIndex; | Номер изображения в компоненте TImageList |
property Index: Longint; | Номер узла в списке потомков вышестоящего родителя. Первый узел-потомок имеет номер 0, второй - 1 и т.д. |
property IsVisible: Boolean; | При значении True узел виден |
property Item [Index: Integer]: TTreeNode; | Массив узлов, являющихся потомками данного |
property ItemId: HTreeItem; | Содержит уникальный Windows-дескриптор узла |
property Level: Integer; | Глубина узла. Верхний уровень имеет номер 0, следующий уровень - 1 и т.д. |
property OverlayIndex: Integer; | Содержит индекс оверлейного значка. Оверлейный значок вычеркивается поверх основного, чтобы, например, указать, что узел стал недоступен |
property Parent: TTreeNode; | Содержит ссылку на родительский узел |
property Selected: Boolean; | При значении True узел выделен |
property SelectedIndex: Integer; | Номер изображения, показываемого при выделении узла |
property Text: String; | Текст, выводимый в узле |
property TreeView: TCustomTreeView; | Ссылка на родительский объект |
property Owner: TTreeNodes; | Содержит ссылку на владельца данного узла |
Напишем небольшое приложение, позволяющее создавать дерево во время выполнения программы. Для этого в форме разместим пустой объект TreeView, надпись и две кнопки с заголовками Узел и Потомок. После ввода имени и щелчка на кнопке Узел в дерево добавляется новый узел на текущем уровне. При щелчке на кнопке Потомок новый узел добавляется в число потомков текущего узла. Для добавления нового узла можно использовать метод AddNode, объявление которого выглядит следующим образом.
function AddNode (Node, Relative: TTreeNode; const S: string; Ptr: Pointer; Method: TNodeAttachMode): TTreeNode;
Метод добавляет новый узел в коллекцию. При этом возвращается вновь добавленный узел и используются следующие параметры.
Память, распределяемая для параметра Ptr, не освобождается при освобождении объектов, связанных с узлами.
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Label1: TLabel; TreeView1: TTreeView; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure TreeView1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} var Nodes : TTreeNodes; Node : TTreeNode; procedure TForm1.FormCreate(Sender: TObject); begin Nodes := TTreeNodes.Create (TreeView1); Node := TTreeNode.Create (Nodes); Node := nil; end; procedure TForm1.Button1Click(Sender: TObject); var NewNode : TTreeNode; i : Integer; begin NewNode := TTreeNode.Create(Nodes); i := Nodes.Count; NewNode := Nodes.AddNode (NewNode, Node, 'Узел '+ IntToStr(i), nil, naAdd); end; procedure TForm1.Button2Click(Sender: TObject); var NewNode : TTreeNode; begin NewNode := TTreeNode.Create(Nodes); NewNode := Nodes.AddNode (NewNode, Node, 'Потомок '+ IntToStr (TreeView1.Items.Count), nil, naAddChild); end; procedure TForm1.TreeView1Click(Sender: TObject); begin Node := TreeView1.Selected; Label1.Caption := Node.Text; end; end.
Щелчки на кнопках будут добавлять новые узлы и их потомков, в зависимости от выбранного узла, который выбирается щелчком мыши на дереве, как показано на рис.1.
Рис.1. Создание дерева
Когда дерево создано во время работы программы, его структуру можно сохранить на жестком диске до следующего сеанса. Это можно сделать с помощью следующего метода.
TreeView1.SaveToFile ('TREE.TXT');
Дерево сохраняется в текстовом формате в наглядном виде - с отступами. Загрузить дерево из файла можно с помощью следующего метода:
procedure LoadFromFile (const FileName: String);
Узлы в дереве можно сортировать. Момент сортировки задается в свойстве SortType: stNone, stData, stText, stBoth, т.е. при изменении или свойства Data или свойства Text, или в обоих случаях.
Способ сортировки определяется обработчиком события OnCompare. Например, чтобы отсортировать все элементы дерева в убывающем порядке их названий, установите значение свойства SortType равным stText и напишите следующий текст обработчика.
procedure TForm1.TreeView1Compare (Sender: TObject; Node1, Node2: TTreeNode; Data: Integer; var Compare: Integer); begin if Node1.Text > Node2.Text then Compare := -1 else if Node1.Text < Node2.Text then Compare := +1 else Compare := 0 end;
Реально процедура сортировки выполняется, когда происходит редактирование и названия узла или связанных с ним данных, а также при изменении значения свойства SortType.
Основные методы класса TTreeView.
function AlphaSort: Boolean;
procedure ClearSelection (KeepPrimary: Boolean = False); virtual;
function CustomSort (SortProc: TTVCompare; Data: Longint;
ARecurse: Boolean = True): Boolean;
procedure Deselect (Node: TTreeNode); virtual;
function FindNextToSelect: TTreeNode; virtual;
procedure FullCollapse;
procedure FullExpand;
function GetHitTestInfoAt (X, Y: Integer): THitTests;
function GetNodeAt(X, Y: Integer): TTreeNode;
function GetSelections (AList: TList): TTreeNode;
function IsEditing: Boolean;
procedure Select (const Nodes: array of TTreeNode); overload; virtual; procedure Select (Nodes: TList); overload; virtual;, procedure Select (Node: TTreeNode; ShiftState: TShiftState = []); overload; virtual;
В первых двух вариантах процедуры все узлы, передаваемые через параметр Nodes, выделяются, а для остальных выделенных узлов выделение отменяется. В третьем варианте узлы выделяются как при щелчке на них мышью. Достигается эффект использования клавиш <Ctrl>, <Shift> и правой кнопки мыши при значении параметра ShiftState равном ssCtrl, ssShift или ssRight.
procedure Subselect (Node: TTreeNode; Validate: Boolean = False); virtual;
Необходимо отметить, что обращение к узлам дерева по номеру - операция очень неэффективная. Для быстрого перебора всех узлов можно использовать следующий способ.
var CurItem: TTreeNode; begin CurItem: = TreeView1.Items.GetFirstNode; while CurItem<>nil do begin // Выполнить нужные действия над узлом CurItem. CurItem: = CurItem.GetNext; end; end;
Основные методы класса TTreeNode перечислены в таблице 3.
Метод | Описание |
---|---|
function AlphaSort: Boolean; | Сортировка всех потомков узла |
procedure Соllарsе (Recursе: Boolean); | Сжатие узла |
procedure Delete; | Удаление узла и всех его потомков |
procedure DeleteChildren; | Удаление всех потомков узла |
function DisplayRect (TextOnly: Boolean); TRect; | Возвращает прямоугольник, которым узел ограничивается на экране. Если значение параметра TextOnly равно True, то в прямоугольник записывается только область текстового имени узла |
procedure EndEdit (Cancel: Boolean); | Завершает редактирование узла. Если значение параметра Cancel равно True, то восстанавливается прежнее значение свойства Text |
procedure Expand (Recurse: Boolean); | Разворачивает узел. Если значение параметра Recurse равно True, то разворачиваются и все потомки |
function GetFirstChild: TTreeNode; | Возвращает первый узел из списка потомков |
function GetLastChild: TTreeNode; | Возвращает последний узел из списка потомков/TD> |
function GetNext: TTreeNode; | Возвращает следующий узел по отношению к текущему с учетом невидимых узлов и потомков |
function GetNextChild (Value: TTreeNode): TTreeNode; | Возвращает следующий потомок по отношению к потомку Value |
function GetNextSibling: TTreeNode; | Возвращает следующий узел на уровне текущего узла, независимо от того, виден он или нет |
function GetNextVisible: TTreeNode; | Возвращает следующий видимый узел |
function GetPrev: TTreeNode; | Возвращает предыдущий узел по отношению к текущему с учетом невидимых узлов и потомков |
function GetPrevChild (Value: TTreeNode): TTreeNode; | Возвращает предыдущий потомок по отношению к потомку Value |
function GetPrevSibling: TTreeNode; | Возвращает предыдущий узел на уровне текущего узла, независимо от того, виден он или нет |
function GetPrevVisible: TTreeNode; | Возвращает предыдущий видимый узел |
function HasAsParent (Value: TTreeNode): Boolean; | Возвращает значение True, если узел Value является родительским для текущего узла |
function IndexOf (Value: TTreeNode): Integer; | Возвращает позицию узла в списке потомков узла Value. Если узел Value не прямой родитель текущего узла, то функция возвращает значение -1 |
procedure MakeVisible; | Разворачивает подходящие вышестоящие узлы таким образом, чтобы текущий узел стал видимым |
procedure MoveTo (Destination: TTreeNode; Mode: TNodeAttachMode); | Перемещает текущий узел в область узла Destination. Конкретное положение определяется значением параметра Mode |
Основные методы класса TTreeNodes.
function AlphaSort (Arecurse: Boolean = False): Boolean;
function AddChild (Node: TTreeNode; const S: string): TTreeNode;
function AddChildFirst (Node: TTreeNode; const S: string): TTreeNode;
function AddChildObject (Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode;
function AddChildObjectFirst (Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode;
function AddFirst (Node: TTreeNode; const S: string): TTreeNode;
function AddNode (Node, Relative: TTreeNode; const S: string; Ptr: Pointer; Method: TNodeAttachMode): TTreeNode;
function AddObject (Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode;
function AddObjectFirst (Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode;
procedure BeginUpdate; procedure EndUpdate;
function GetFirstNode: TTreeNode;
function GetNode (ItemId: HTreeItem): TTreeNode;
function Insert (Node: TTreeNode; const S: string): TTreeNode;
function InsertNode (Node, Sibling: TTreeNode; const S: string; Ptr: Pointer): TTreeNode;
function InsertObject (Node: TTreeNode; const S: string; Ptr: Pointer): TTreeNode;
На следующем шаге мы рассмотрим компонент TListView.