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

Продолжим создание программы, начатой в части 3.1.

Построение узлов. Описание блока:

Рассмотрим структуру блока 2.

Укрупнённая блок-схема для БЛОК2.

Оформим это описание в блок-схему:

Данной блок-схеме будет соответсвовать следующий код.

В процедуру передаётся ссылка на узел и массив ключей.

В результате работы процедуры будет построено полное дерево узлов, соответствующее ключам.

procedure Tform1.pr_BLOCK2(node_bunch:TTReeNode;
ARR_of_KEYS:T_ARR_of_KEYS);
var b:boolean; node_child, node_match:TTReeNode;
BOOL_NODE:T_BOOL_NODE;
begin
b:=true;
//цикл до тех пор, пока индикатор цикла b не станет равным false
while b do
begin //1
//найти в грозди узел, совпадающий с ключом
node_match:=f_BLOCK21(node_bunch,ARR_of_KEYS);
//если узел, совпадающий с ключом, есть
if node_match <> nil then
begin
//возвращаем дочерний узел по отношению к узлу node_match
BOOL_NODE:=f_BLOCK22(node_match,ARR_of_KEYS);
node_bunch:=BOOL_NODE.node;
b:=BOOL_NODE.b;
end;

//если узла, совпадающего с ключом, нет
if node_match = nil then
begin//2
//дополнить гроздь и сформировать дочерние узлы
pr_BLOCK23(node_bunch,ARR_of_KEYS);
b:=false;
end;//2

end; //1

end;

Описание работы процедуры.

BLOCK2 осуществляет вставку узлов дерева в зависимости от ряда условий. Первое условие — найдено ли совпадение значения ключа с одним из значений в грозди узлов на соответствующем уровне.

Второе условие — проверка логической переменной «b» при организации цикла. Само значение переменной «b» формируется или в блоке «BLOCK2», или передаётся из блока «BLOCK22». В «BLOCK22» передаётся ссылка на узел и проверяется, если ли у этого узла дочерний узел. Если дочернего узла нет, то внутри записи «BOOL_NODE» возвращается «nil» и «false».

Поиск узла, совпадающего с ключом. Описание блока:

В функцию передаётся ссылка на узел и массив ключей. Возвращает функция ссылку на узел, совпадающий с ключом.

function Tform1.f_BLOCK21(node:TTreeNode;ARR_of_KEYS:T_ARR_of_KEYS):TTreeNode;
var ARR_of_NODES:T_ARR_of_NODES; key:string;
begin
//получить ключ
key:=ARR_of_KEYS[node.Level];

//для данного узла node построить гроздь
ARR_of_NODES:=f_GET_ARR_of_NODES(node); //ОТЛАЖЕНО

//поиск совпадения (match) узла с ключом. Если совпадение есть, возвращается
узел.
node:=f_GET_NODE_FIND_MATCH(key,ARR_of_NODES); //ОТЛАЖЕНО

result:= node;
end;

Описание работы функции f_BLOCK21.

В функцию передаётся ссылка на узел «node». В иерархии дерева этот узел имеет уровень «node.Level».

В цепочке ключей этому уровню соответствует ключ «key:=ARR_of_KEYS[node.Level]».

Функция f_GET_ARR_of_NODES возвращает массив узлов (гроздь).

Эта функция (метод) возвращает динамический массив узлов, соответствующих данному уровню и принадлежащих ветви, на которой расположен узел «node».

Функция «f_GET_NODE_FIND_MATCH» определяет, есть ли совпадение одного из узлов грозди с ключом (match-совпадение). Если совпадение найдено, возвращается ссылка на узел, иначе «nil».

Создать гроздь, содержащую узел. Описание блока:

Оформим это описание в блок-схему:

//получить массив узлов (построить гроздь)

В функцию передаётся ссылка на узел. Обратно функция возвращает массив узлов.

function Tform1.f_GET_ARR_of_NODES(node:TTReeNode):T_ARR_of_NODES;
var arr_of_node:T_ARR_of_NODES; node_next:TTReeNode;
i:integer;
begin
i:=1;

//устанавливаем размерность динамического массива равной 1
setlength(arr_of_node,1);
//записываем узел в массив
arr_of_node[i-1]:=node;

//получить гроздь узлов, содержащих текущий узел node
while node<>nil do
begin
//на том же уровне взять узел, следующий после узла node
node_next:=node.getNextSibling;

//если узел не nil, то добавляем его в массив
if node_next<>nil then
begin
//Увеличиваем i на 1
inc(i);
//устанавливаем новую размерность динамического массива
setlength(arr_of_node,i);
//добавляем узел в массив
arr_of_node[i-1]:=node_next;
end;//if
//делаем узел node_next текущим (развязываем циклическую ссылку)
node:=node_next;
end;//while

result:=arr_of_node;

end;

Описание работы функции f_GET_ARR_of_NODES

В функцию предается ссылка на узел «node». Необходимо создать массив всех узлов, находящихсяна на одной ветви с узлом «node» и лежащих с ним на одном уровне (построить гроздь узлов, содержащих узел «node»).

Для развязки циклических ссылок вводим дополнительную переменную «node_next».

Функция возвращает массив узлов одного уровня — «гроздь узлов».

Найти узел, совпадающий с ключом. Блок-схема:

Функция возвращает ссылку на узел (или «nil»).

//в грозди ищем совпаление узла с ключом. При нахождении совпадения функция возвращает найденный узел, иначе возвращается nil
function Tform1.f_GET_NODE_FIND_MATCH(key:string;
ARR_of_NODES:T_ARR_of_NODES):TTReeNode;
var i,n_nodes:integer;
begin
//определить количество переменных в массиве (количество узлов в грозди)
n_nodes:=length(ARR_of_NODES);
//найти совпадение
for i:=0 to n_nodes-1 do
begin
if ARR_of_NODES[i].Text=key then
begin
result:=ARR_of_NODES[i];
exit;
end;
end;//for
result:=nil;
end;

Получить дочерний узел. BLOCK22

В блок передаётся ссылка на узел «node_match» и массив ключей «ARR_of_KEYS».

Функция возвращает запись типа «T_BOOL_NODE»

Задача функции — осуществление поиска узла, дочернего по отношению к узлу «node_match». Если дочерний узел есть, то он просто возвращается функцией.

Если такого узла нет (node_child=nil), то проверяется, можно ли продолжить цепочку узлов (то есть, есть ли ключи более высокого уровня, чем у узла «node_match» — процедура « pr_ADD_CHILD_NODES»).

function Tform1.f_BLOCK22(node_match:TTReeNode;ARR_of_KEYS:T_ARR_of_KEYS):T_BOOL_NODE;
var node_child:TTReeNode; BOOL_NODE:T_BOOL_NODE;
begin
//получить узел, дочерний по отношению к node_match
node_child:=node_match.getFirstChild;

BOOL_NODE.node:=node_child;
BOOL_NODE.b:=true;
result:=BOOL_NODE;

if node_child=nil then
begin //2
//добавить все дочерние узлы, если таковые могут быть
pr_ADD_CHILD_NODES(node_match, ARR_of_KEYS);
//признак выхода из цикла while в блоке BLOCK2
BOOL_NODE.b:=false;
result:=BOOL_NODE;
end; //2

end;

Процедура pr_ADD_CHILD_NODES.

Пусть на данный момент использовано три строки списка:

В результате будут выстроены узлы, расположенные на нулевом, первом, втором и третьем уровнях.

Следующей строкой будет:

На третьем уровне имеется соответствие одного из значений грозди третьего уровня (а именно — разд_3) с ключом, соответсвующим третьему уровню.

Как видно из уже построенной части дерева, у узла «разд_3» нет дочерних узлов.

Однако есть ключи, соответствующие четвёртому и пятому уровням.

Поэтому добавляем сначала дочерний узел четвёртого уровня:

А затем дочерний узел пятого уровня:

Реализация процедуры.

procedure TForm1.pr_ADD_CHILD_NODES(node:TTReeNode; ARR_of_KEYS:T_ARR_of_KEYS);
var n_level,n_key:integer;
begin
//определяем уровень узла node
n_level:=node.Level;
//определяем количество ключей
n_key:=length(ARR_of_KEYS);
while n_level<n_key-1 do
begin
node:=self.TreeView1.Items.AddChild(node,ARR_of_KEYS[n_level+1]);
n_level:=node.Level;
end;

end;

BLOCK23

Этот блок служит для добавления в гроздь нового узла. А также дочерних по отношению к нему узлов.

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

procedure Tform1.pr_BLOCK23(node_bunch:TTReeNode;ARR_of_KEYS:T_ARR_of_KEYS);
begin
//добавить в гроздь узел и все дочерние узлы
pr_ADD_NODES(node_bunch, ARR_of_KEYS);
end;

procedure TForm1.pr_ADD_NODES(node:TTReeNode; ARR_of_KEYS:T_ARR_of_KEYS);
var i,n_level,n_key:integer; key:string;
begin
//определить уровень переданного узла
n_level:=node.Level;
//взять ключ, соответствующий данному уровню
key:=ARR_of_KEYS[n_level];
//добавить узел в гроздь
node:=self.TreeView1.Items.Add(node,key);
pr_ADD_CHILD_NODES(node,ARR_of_KEYS);
end;

Далее полученное дерево можно сохранить в файле и загружать его по мере надобности.

Заключение.

Ещё раз посмотрим блок-схему взаимодействия разных блоков, входящих в «БЛОК2»:

В программе использованы методы:

node:=self.TreeView1.Items.AddFirst(nil,«название_узла»). Если в дереве нет узлов, то метод вставляется самый первый узел и возвращает ссылку на него.

Иначе, если AddFirst(«узел»,«название_узла»), то вставляемый узел станет первым в грозди, содержащей «узел».

node:=TreeView1.Items.AddChild(«родительский_узел», «название_узла»). Метод создаёт узел, дочерний по отношению к родительскому узлу,

node:=self.TreeView1.Items.Add(«узел»,«название_узла»). Метод вставляет узел после «узел» и возвращает ссылку на вставленный узел.

node:=TreeView1.Items.GetFirstNode. Метод возвращает ссылку на самый первый (то есть с абсолютным индексом «0») узел дерева. Если такого узла нет, то возвращает «nil».

node_next:=node.getNextSibling. На том же уровне, что и узел node, взять и вернуть следующий за ним узел.

node_child:=node.getFirstChild. Взять и вернуть узел, дочерний по отношению к узлу node.

Начало смотри «Delphi. Панель Win32. Компонент TreeView. Часть 3_1.»

Следующая статья «Delphi. Панель Win32. Компонент TreeView. Часть 4«

Обновлено: 13.11.2021 — 19:04

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

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