Delphi. Панель Win32. Компонент TreeView. Часть 1.

Компонент «TreeView» находится на странице Win32.

По сути, он является контейнером для хранения и отображения других компонентов, называемых «TreeNode» (узел дерева). Поэтому при размещении на форме он будет пустой и иметь вид:

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

Свойство Items

Это основное свойство, с помощью которого формируются узлы дерева. Узлы вводятся с помощью редактора, вызываемого соответствующим свойством:

Этот редактор имеет вид:

Результат конструирования дерева отражается в окне «Items». Для начала сформируем главную ветвь дерева (нулевой уровень). Сформируем три узла.

Для формирования новой ветви служит кнопка «New Item» — новый узел. После нажатия на неё появляются 4 точки:

Теперь вводим название узла в поле «Text». Появляется первый узел:

Далее таким же образом формируем два других узла:

Это так называемые узлы нулевого уровня. Если у них будут подузлы (дочерние узлы), то они станут родительскими узлами.

Теперь кликом мыши выделяем узел «1»

Начнём формировать 1-ый уровень.

Нажимаем кнопку «New SubItem» (новый подузел) и пишем в поле «Text» значение «11».

Затем снова кликаем по узлу «1» и вновь нажимаем «New SubItem», после чего вводим «12». Далее поступаем аналогичным образом и формируем подузел «13»:

После этого переходим к узлу «2» и формируем его подузлы:

Третий узел остави без изменений.

Далее выделяем подузел «12» и формируем два новых подузла второго уровня:

После этого нажимаем либо кнопку «Apply» (применить), либо «OK». В первом случае в компоненте «TreeView» дерево отобразится без закрытия редактора, а во втором — с закрытием.

Заметим, что у компонента «TreeView» есть метод, позволяющий сохранить созданное дерево в файле:

self.TreeView1.SaveToFile(‘file_name’);

На месте константы «file_name» должно стоять имя файла, в который будет записано дерево. Если файл будет расположен в той же папке, что и исполняемый файл программы, то полный путь доступа указывать не обязательно. Иначе этот путь должен быть указан полностью.

Кнопка «Load» в редакторе узлов позволяет загрузить этот файл.

Использование компонента TreeView

После того, как компонент создан, необходимо его использовать.

Пусть, например, поставлена такая задача.

Есть три панели, и каждую из них необходимо закрасить своим цветом в зависимости от того, какой узел созданного нами дерева выбран. Если выбран узел нулевого уровня, то закрашивается только первая панель. Если первого уровня — две панели, а третьего — три панели. Пусть первый родительский узел отвечает за красный цвет, второй — за зелёный, а третий — за синий.

Первый способ решения

По мере добавления узлов в дерево каждый узел получает уникальный порядковый номер. Воспользуемся этим обстоятельством. Посмотрим, как пронумерованы узлы в нашем случае (номера узлов обозначены красным).

Принцип назначения номеров узлов понятен интуитивно.

Номера узлов можно непосредственно узнать следующим образом:

procedure TForm1.TreeView2Change(Sender: TObject; Node: TtreeNode);
var i:integer;
begin
i:= node.AbsoluteIndex ;
edit1.Text:=’номер узла=’+inttostr(i);
end;

Выделяя узел, мы наблюдаем номер узла в «edit1» после щелчка по узлу (код приведён под видео).

Закрашиваем панель по щелчку по узлу:

//Событие «OnChange» происходит при переходе от одного узла к другому. Событию передаётся ссылка «node» на выбранный узел.

procedure TForm1.TreeView2Change(Sender: TObject; Node: TtreeNode);
var i:integer;
begin
Panel1.Color:=clWhite;//сбрасываем цвет панели
i:= node.AbsoluteIndex ;
edit1.Text:=’номер узла=’+inttostr(i);//выводим номер узла
case i of
0,6,9:Panel1.Color:=clred;//при щелчке по узлам с абсолютным номером 0,6 и 9 закрашиваем панель в красный цвет.
1,2,5,7,8:Panel1.Color:=clgreen;//закрашиваем в зелёный цвет
3,4:Panel1.Color:=clBlue; //закрашиваем в синий цвет
end;
end;

Второй способ решения

Рассмотрим другой вариант кода, используя анализ «уровня» (нулевая вертикальная линия, 1-я вертикальная линия и так далее), на которой расположен узел:

procedure TForm1.TreeView2Change(Sender: TObject; Node: TtreeNode);
var i:integer;
begin
Panel1.Color:=clWhite;
i:= node.Level;//определяем уровень, на котором находится узел
edit1.Text:=’уровень узла=’+inttostr(i);
case i of
0:Panel1.Color:=clred;
1:Panel1.Color:=clgreen;
2:Panel1.Color:=clBlue;
end;
end;

Можно идентифицировать узел по тексту, содержащемуся в узле, если надписи во всех узлах разные.

procedure TForm1.TreeView2Change(Sender: TObject; Node: TtreeNode);
var i,ii,iii:integer; s:string;
begin
Panel1.Color:=clWhite;
s:= TreeView2.Selected.Text;
edit1.Text:=’текст узла=’+s;
end;

Идентификация узла по трём значениям.

Наконец, рассмотрим ещё один вариант идентификации узла.

Каждый выделенный узел можно идентифицировать тремя значениями: Номер корневого узла ветви, уровень узла и, наконец, номер узла в данном уовне. Например, узел «121» лежит на втором уровне. Его корневой родитель («1») имеет номер «0». На своём уровне узел имеет номер «0».

Таким образом, каждый узел можно характеризовать тремя числами: «№_корневого_узла, №_уровня, №_узла_в_уровне». В нашем примере будем иметь: «0,2,0».

Чтобы получить эту тройку чисел, используем код:

procedure TForm1.TreeView3Expanded(Sender: TObject; Node: TtreeNode);
begin
node.Selected:=true;
end;

Событие «Expanded» происходит при щелчке по знаку узла «+»:

Если не выставлено свойство «AutoExpand», то компонент при запуске программы отображается в виде:

У компонента есть одна особенность. Если щёлкнуть не по первому узлу, а по любому другому (например, по узлу «2»), то всё равно выделенным оказывается «нулевой узел», то есть в нашем случае цифра «1»:

Гораздо удобнее, чтобы выделенным оказывался родительский узел, стоящий рядом со знаком «+». Именно это делает строка программы:

node.Selected:=true;

расположенная в обработчике события раскрытия узла «TreeView3Expanded», показанного выше. Тогда после щелчка по «+» около узла «2» мы увидим:

уровня и индекс узла в уровне, позволяет, например, следующий код: (всегда помните, что, как правило, добиться одного и того же результата можно разными путями).

Для этого используем обработчик события «onChange», вызываемый каждый раз, когда выделяется новый узел.

procedure TForm1.TreeView3Change(Sender: TObject; Node: TtreeNode);
var i,n:integer; nd:TTreeNode;
begin
edit7.Text:=’№ ветви=’+ inttostr(Node.Level)+’ ‘+’№ узла в ветви=’+inttostr(Node.Index);//индекс узла в текущем уровне
edit6.Text:=’№ ветви=’+inttostr(Node.Level);//номер текущего уровня
i:=node.Index;//запоминаем индекс выделенного узла. Если это узел нулевого уровня, то он будет равен «-1»
nd:= Node.Parent;//пытаемся найти родительский, по отношению к текущему, узел
n:= nd.Index ;//если это узел не нулевого уровня, то запоминаем его номер. Если узел нулевого уровня, то индекс будет равен «-1».
while n>-1 do//если «n» не равно «-1» (то есть узел «nd» не нулевого уровня), то входим в цикл
begin
i:= nd.Index;//запоминаем индекс узла «nd»
nd:=nd.Parent;//пытаемся получить родительский для «nd» узел
n:= nd.Index;//определяем индекс этого узла. Если «n оказывается равной -1», то цикл завершается
end;
edit5.Text:=’№ родительского узла=’+inttostr(i);
edit8.Text:=’текст узла=’ + Node.Text;
end;

Например:

или

Компонент «TreeView» обладает очень богатыми возможностями, особенно при динамическом формировании и редактировании его узлов. Но об этом речь пойдёт во второй части статьи.

Перейти к части 2

***

Обновлено: 07.11.2021 — 17:34

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *