double arrow

Создание и сохранение в таблицу дерева разделов

Работа с деревьями состоит из двух этапов:

1. Сохранение дерева в таблицу.

2. Считывание дерева из таблицы.

В этом разделе разберем первый этап. Щелкните дважды по компоненту PopupMenu1, который "привязан" к дереву, и создайте в нем следующие разделы:

· Создать главный раздел

· Добавить подраздел к выделенному

· Переименовать выделенный

· Удалить выделенный

· -

· Свернуть дерево

· Развернуть дерево

Все эти команды относятся к работе с разделами дерева. Прежде всего, создадим обработчик для команды "Создать главный раздел". Листинг процедуры смотрите ниже:

{Создать главный раздел}procedure TfMain.N1Click(Sender: TObject);var s: String; //для получения имени раздела (подраздела) NewRazd: TTreeNode; //для создания нового узла дереваbegin //вначале очистим s s:= ''; //Получим в s имя нового раздела: if not InputQuery('Ввод имени раздела', 'Введите заголовок раздела:', s) then Exit; //снимаем возможное выделение у дерева: TreeView1.Selected:= nil; //создаем главный раздел (ветвь): NewRazd:= TreeView1.Items.Add(TreeView1.Selected, s); //Сразу же сохраняем его в базу: tRazdels.Append; //добавляем запись tRazdels['R_Parent']:= 0; //не имеет родителя //присваиваем значение созданного раздела: tRazdels['R_Name']:= NewRazd.Text; //сохраняем изменения в базе: tRazdels.Post;end;

Разберем код. Переменная NewRazd имеет тип TTreeNode, к которому относятся все разделы и подразделы (узлы) дерева. В текстовую переменную s с помощью функции InputQuery() мы получаем имя нового главного узла. Функция имеет три строковых параметра:

1. Заголовок окна.

2. Пояснительная строка.

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

Если переменная, передаваемая в качестве третьего параметра, пуста, то поле ввода будет пустым. Если же в ней содержался текст - он будет выведен как текст "по умолчанию". Функция возвращает True, если пользователь ввел (или изменил) текст, и False в противном случае.

В результате работы функции для пользователя будет выведено простое окно с запросом:


Окно функции InputQuery()

Далее строкой

TreeView1.Selected:= nil;

мы снимаем выделение, если какой либо раздел был выделен, ведь мы создаем главный раздел, не имеющий родителя.

Свойство Selected компонента TreeView указывает на выделенный узел и позволяет производить с ним различные действия, например, получить текст узла:

TreeView1.Selected.Text;

А присваиваемое значение nil (ничто) снимает всякое выделение, если таковое было. Далее мы создаем сам узел:

NewRazd:= TreeView1.Items.Add(TreeView1.Selected, s);

Разберем эту строку подробней. Переменная NewRazd - это новый узел дерева. Каждый узел - объект, обладающий своими свойствами и методами. Все узлы хранятся в списке - свойстве Items дерева TreeView, а метод Add() этого свойства позволяет добавить новый узел. У метода два параметра - выделенный узел (у нас он равен nil) и строка текста, которая будет присвоена новому узлу. Таким образом, в дереве появляется новый главный узел.

Затем мы сохраняем его в базу данных, предварительно добавив в таблицу новую запись:

tRazdels.Append; //добавляем запись tRazdels['R_Parent']:= 0; //не имеет родителя //присваиваем значение созданного раздела: tRazdels['R_Name']:= NewRazd.Text; //сохраняем изменения в базе: tRazdels.Post;

Такие методы, как Append или Insert автоматически переводят таблицу в режим редактирования, поэтому вызывать метод Edit излишне.

Обратите внимание на то, что мы сохраняем ноль в поле "R_ Parent ", так как это - главный раздел, не имеющий родителя. Свойство Text нового узла NewRazd содержит название нового узла, которое мы присваиваем полю "R_Name".

Далее сгенерируем процедуру для команды меню "Добавить подраздел к выделенному":

{Добавить подраздел к выделенному разделу(подразделу)}procedure TfMain.N2Click(Sender: TObject);var s: String; //для получения имени раздела (подраздела) z: String; //для формирования заголовка окна NewRazd: TTreeNode; //для создания нового узла дереваbegin //Проверим - есть ли выделенный раздел? //Если нет - выходим: if TreeView1.Selected = nil then Exit; //вначале очистим s s:= ''; //сформируем заголовок окна запроса: z:= 'Раздел "' + TreeView1.Selected.Text + '"'; //Получим в s имя нового раздела: if not InputQuery(PChar(z), 'Введите заголовок подраздела:', s) then Exit; //создаем подраздел: NewRazd:= TreeView1.Items.AddChild(TreeView1.Selected, s); //перед сохранением подраздела в базу, прежде получим //номер его родителя: Q1.SQL.Clear; Q1.SQL.Add('select * from Razdels where R_Name='''+ NewRazd.Parent.Text+''''); Q1.Open; //Теперь сохраняем его в базу: tRazdels.Append; //добавляем запись //присваиваем № родителя: tRazdels['R_Parent']:= Q1['R_Num']; //присваиваем название узла: tRazdels['R_Name']:= NewRazd.Text; //сохраняем изменения в базе: tRazdels.Post;end;

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

Далее, мы ввели строковую переменную z, чтобы сформировать запрос. Ведь пользователю будет удобней, если в окне InputQuery() он сразу увидит, к какому именно разделу он добавляет подраздел.

Затем, при добавлении дочернего узла вместо метода Add() мы используем метод AddChild().

Ну и, наконец, при сохранении узла в таблицу мы записываем не только созданный узел, но и номер его родителя, получив его с помощью запроса

Q1.SQL.Add('select * from Razdels where R_Name='''+ NewRazd.Parent.Text+'''');

Запрос формирует набор данных с единственной строкой - записью родителя добавляемого элемента. Поле Q1['R_Num'], как вы понимаете, хранит номер этого родителя в запросе.

Код процедуры переименования выделенного раздела выглядит так:

{Переименовать выделенный раздел (подраздел)}procedure TfMain.N3Click(Sender: TObject);var s: String; //для получения имени раздела (подраздела) z: String; //для формирования заголовка окнаbegin //Проверим - есть ли выделенный раздел? //Если нет - выходим: if TreeView1.Selected = nil then Exit; //получаем текущий текст: s:= TreeView1.Selected.Text; //формируем заголовок: z:= 'Редактирование "' + s + '"'; //если не изменили, выходим: if not InputQuery(PChar(z), 'Введите новый заголовок:', s) then Exit; //находим эту запись в таблице, учитывая, что ее по каким то //причинам может и не быть: if not tRazdels.Locate('R_Name', TreeView1.Selected.Text, []) then begin ShowMessage('Ошибка! Указанный раздел не существует в таблице.'); Exit; end; //if //если до сих пор не вышли из процедуры, значит запись найдена, //и является текущей. изменяем ее: tRazdels.Edit; tRazdels['R_Name']:= s; tRazdels.Post; //теперь меняем текст выделенного узла: TreeView1.Selected.Text:= s;end;

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

Удаление выделенного узла:

{Удалить выделенный раздел (подраздел)}procedure TfMain.N4Click(Sender: TObject);var s: String; //для строки запросаbegin //Проверим - есть ли выделенный раздел? //Если нет - выходим: if TreeView1.Selected = nil then Exit; //иначе формируем строку запроса: s:= 'Удалить "' + TreeView1.Selected.Text + '"?'; //запросим подтверждение у пользователя: if Application.MessageBox(PChar(s), 'Внимание!', MB_YESNOCANCEL+MB_ICONQUESTION) <> IDYES then Exit; //если не вышли - пользователь желает удалить раздел. //найдем и удалим его вначале из таблицы: if tRazdels.Locate('R_Name', TreeView1.Selected.Text, []) then tRazdels.Delete; //теперь удаляем раздел из дерева: TreeView1.Items.Delete(TreeView1.Selected);end;

Далее осталось сгенерировать процедуры для сворачивания и разворачивания дерева:

{свернуть дерево}TreeView1.FullCollapse; {развернуть дерево}TreeView1.FullExpand;

Итак, метод FullCollase дерева TreeView сворачивает его узлы, а метод FullExpand разворачивает.

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



Сейчас читают про: