DelphiComponent.ru — бесплатно видеоуроки по Delphi, статьи, исходники
Теперь нужно указать у нашего дерева в свойстве images установленный набор картинок. После этого можно переходить к программированию.
По нажатии кнопки Добавить мы должны добавлять в дерево новый элемент. Для этого будем использовать код, представленный в листинге:
procedure TTreeViewForm.AddButtonclick(Sender: TObject) ;
if not InputQuery( ‘ Ввод имени’, ‘Введите заголовок элемента’,CaptionStr) then exit;
NewNode: =TreeView1.Items. Add (TreeView1. Selected, CaptionStr) ;
if NewNode.Parentonil then NewNode.ImageIndex:=1;
Здесь мы объявили две переменные:
- CaptionStr — типа строка string;
- NewNode — типа TTreeNode (тип TTreeNode — это тип отдельного элемента дерева).
В первой строке кода мы обнуляем строку CaptionStr. Эта строка в будущем
будет использоваться для хранения имени нового элемента дерева. Вторая строка имеет следующий код:
if not InputQuery(‘Ввод имени’, ‘Введите заголовок элемента’, CaptionStr) then exit;
Здесь выполняется функция InputQuery, которая используется для вывода на экран окна ввода. У этой функции есть три параметра.
- Заголовок окна ввода.
- Текст-пояснение, который подсказывает пользователю, что ему надо вводить.
- Строковая переменная, в которой мы передаем значение по умолчанию и получаем результат ввода.
Если перед вызовом записать в эту переменную какое- нибудь значение, то оно будет использоваться в качестве значения по умолчанию. Но после вызова этой функции этот параметр всегда хранит реально введенное пользователем значение.
На рис. вы можете увидеть это окно ввода.
Если окно было закрыто не кнопкой ОК, то происходит выход из процедуры. Об этом говорит фрагмент кода:
if not InputQuery(. ) then exit;
Следующая строка кода добавляет новый элемент в наше дерево:
NewNode: =TreeView1. Items.Add(TreeViewl. Selected, CaptionStr);
У компонента Treeviewi есть свойство items, в котором хранятся все элементы дерева. Это свойство имеет объектный тип TTreeNodes. Чтобы добавить туда новый элемент, нужно вызвать метод Add объекта items. Получается, что в объекте Treeview1 есть еще один объект— items, в котором хранятся все элементы. Мы уже сталкивались с такими случаями, когда внутри одного объекта был другой объект. У метода Add есть два параметра:
- элемент, к которому надо добавить новый (здесь мы передаем выделенный элемент Treeview1.Selected);
- заголовок нового элемента.
Результат выполнения этого метода— указатель на новый элемент. Этот результат мы сохраняем в переменной NewNode. Теперь можно изменять и другие значения этого элемента. Например, как в следующем коде изменяется картинка:
if NewNode. Par en tonil then NewNode.Imageindex:=1;
Здесь идет проверка, если свойство Parent нашего дерева не равно нулю (т. е. компонент не является верхним в дереве), то изменить значение imageindex созданного нами элемента на 1 (по умолчанию это значение 0).
Для события, вызываемого нажатием кнопки Добавить элемент, напишем код, показанный в листинге:
var CaptionStr:String; NewNode:TTreeNode;
if not InputQuery(‘Ввод имени подэлемента’, ‘Введите заголовок подэлементаCaptionStr) then exit;
NewNode: =TreeViewl. Items.AddChild(TreeViewl. Selected, CaptionStr) ;
if NewNode. Par en tonil then NewNode.Imageindex: =1 ;
Здесь код практически тот же, что и для кнопки Добавить. Единственная разница в том, что при добавлении нового элемента используется метод Addchiid. Отличие этого метода от просто Add заключается в том, что он добавляет дочерний элемент. Например, если вы выделили в списке какой-то элемент и передали его в качестве первого параметра в Addchiid, то новый элемент будет как бы подчиняться выделенному. При использовании метода Add новый элемент будет находиться на одном уровне дерева с переданным в качестве первого параметра. Теперь напишем код для кнопки Удалить:
if TreeViewl .Selectedonil then TreeViewl.Items.Delete(TreeViewl.Selected);
Здесь нужно удалить выделенный элемент, поэтому сначала мы проверяем, есть ли вообще выделенный элемент в дереве: if TreeViewl.Selectedonil then
Если такой элемент есть, то выполнится следующий код:
TreeViewl.Items.Delete(TreeViewl.Selected);
Здесь используется метод Delete объекта items, чтобы удалить элемент дерева. В качестве параметра надо передать элемент, который мы хотим удалить (мы передаем выделенный TreeViewl.Selected).
Для кнопки Изменить заголовок мы напишем код листинга:
procedure TTreeViewForm.Edi tButtonclick(Sender: TObject);
var CaptionStr:String; begin CaptionStr:=»;
if not InputQuery(‘Ввод имени’,’Введите заголовок элемента’,CaptionStr) then exit;
Здесь снова вызывается окно InputQuery, чтобы пользователь смог ввести новое имя для выделенного элемента. Теперь, чтобы изменить имя, надо изменить свойство Text ДЛЯ выделенного элемента:
TreeView1 .Selected.Text.
Давайте сделаем возможность сохранения и загрузки данных в наше дерево. Для этого создайте обработчик события Onciose и напишите в нем следующее:
procedure TTreeViewForm. FormClose (Sender: TObject; var Action: TCloseAction);
Для сохранения дерева нужно вызвать метод SaveToFile и в качестве единственного параметра указать имя файла. В качестве имени файла можно указывать что угодно, но здесь используется (и это желательно делать) полный путь, чтобы файл случайно не создался в каком-нибудь другом месте. Для этого надо использовать следующую конструкцию:
ExtractFilePath(Application.ExeName)+’tree.dat’
Application. ExeName — указывает на имя запущенного файла. ExtractFilePath— извлекает путь к файлу из указанного в качестве параметра пути К файлу. Получается, ЧТО ВЫЗОВ ExtractFilePath (Application. ExeName) вернет путь к папке, откуда была запущена программа. Остается только к этому пути прибавить имя файла (у нас это ‘tree.dat’) и можно быть уверенным, что файл обязательно будет находиться там же, где и запускаемый файл.
Теперь нужно загрузить сохраненные данные. Для этого по событию Onshow напишем следующий код:
procedure TTreeViewForm.FormShow(Sender: TObject);
begin if FileExists(ExtractFilePath(Application.ExeName) +1 tree.dat’) then TreeViewl.LoadFromFile(ExtractFilePath(Application.ExeName)+ ‘tree.dat’);
Здесь сначала проверяется с помощью вызова функции FileExists существование файла. Этой функции нужно передать полное имя файла, и если он существует, то функция вернет true, иначе false.
Если файл существует, то можно его загрузить с помощью вызова метода LoadFromFile.
Обязательно проверяйте файл на существование. Если его нет или кто-то его удалил, а вы попытаетесь загрузить данные из несуществующего файла, произойдет ошибка.
Попробуйте запустить пример. Если создать несколько элементов и потом перезапустить программу, то вы сразу же сможете заметить, что старые дочерние элементы имеют один рисунок, а вновь созданные другой. Почему так получилось? Ведь мы же всегда меняем рисунок, если это дочерний элемент? Просто после закрытия программы дерево сохраняется в файле, а после загрузки оно загружается без учета изображений. Состояние картинок не сохраняется — об этом нам нужно заботиться самостоятельно. Но это уже отдельная история, о которой мы поговорим в другой раз. В следующем примере мы избавимся от этого неприятного эффекта.
Итак, чтобы восстановить состояние картинок после загрузки данных из файла, надо скорректировать обработчик события Onshow следующим образом:
if FileExists(ExtractFilePath(Application.ExeName)+’tree.dat’) then
TreeViewl. LoadFromFile (ExtractFilePath (Application. ExeName) + ‘tree.dat’);
for i:=0 to TreeViewl.Iterns.Count-1 do
if TreeViewl.Items.Parent=nil then TreeViewl.Iterns.Imageindex:= 0 else TreeViewl.Iterns.Imageindex:=1;
Здесь сначала происходит загрузка данных из файла, а потом запускается цикл, в котором перебираются все элементы дерева. В цикле мы делаем проверку, если у текущего элемента свойство Parent равно nil, значит, у элемента нет родительского элемента и он корневой, поэтому устанавливаем нулевую картинку. Если свойство не равно нулю, то элемент дочерний, и мы устанавливаем ему картинку с номером 1.
Вот и все. Вот таким простым способом мы восстанавливаем картинки элементов, потому что они не сохраняются в файле.
Источник
Delphi. Иерархические данные. DBTreeView своими руками. Просмотр, добавление, редактирование, удаление узлов.
Встала задача построить дерево, связанное с базой данных, поддерживающее отображение иерархической структуры базы данных – какой-то конкретной иерархической таблицы. Например, отделы и сотрудники, содержащиеся в одной таблице – с колонкой idParent. Также нужны операции вставки новой записи в базу и в дерево и каскадное удаление – при удалении узла – удаляются все его дети. Готовых компонентов практически нет – из них ehLib и DevExpress, но это следующий шаг моего развития. В порядке тренировки решил попробовать решить задачу своими силами. В книге Дмитрия Осипова про базы данных. в принципе почти всё расписано – как и что нужно сделать, я повторил его пример, но нашёл там одну ошибку из за которой у меня выскакивало сообщение Invalid Pointer Operation, поправив которую – я получил то, что хотел. Вот что у меня получилось.
Как видно из рисунка все иерархические данные отображены в одной таблице. Каждый элемент либо обладает родителем либо нет. Колонка Index в данном примере нигде не используется, она вспомогательна, для следующего примера, где будем рассматривать сортировку и перестановку узлов. Здесь же только вставку, удаление, редактирование.
Подключение по FireDAC, БД MySQL.
Начнем!
Начать предлагаю с базы данных,в MySQL WorkBench я создал всего 1 таблицу, в принципе, для примера её вполне достаточно.
После создания базы из модели у меня получилось следующее. Базу желательно пока оставить пустой, это на картинке она у меня спустя некоторое время после создания. Это связано с алгоритмом сбора записей из базы, который мы опишем далее. Но если кратко, суть в том, что для правильной работы алгоритма все дети своих родителей должны быть с большим id нежели у родителя, если нарушить этот порядок в ручную – алгоритм будет работать некорректно. Но если заводить всё из интерфейса, то этот порядок будет соблюдаться автоматически, так как невозможно добавить ребенка без создания родителя.
Создание интерфейса
Создадим приложение VCL и добавим на него следующие элементы
Кнопка Selected здесь совершенно случайно, можете её не добавлять. Просто мне было лениво её убирать))) Я экспериментировал с установкой фокуса. Весь основной код по созданию подключения, алгоритмам добавления, редактирования, удаления узлов я перенес в отдельный датамодуль.
Вот какой код у нас в компонентах FDQuery
Источник