Отображение дерева с дополнительной структурой Data

Архангельский Андрей

       Если же нам хочется в узлах дерева показывать картинки и нет возможности использовать свободные переменные ImageIndex и т.п., то к каждому узлу можно привязать отдельную сруктуру Data и заполнять ее при построении дерева. При этом в структуру Data можно записывать строку таблицы полностью. Как это сделать показано в примере {Example02}.
       Для начала нужно объявить новый тип, например, PItemRec указывающий на запись типа ItemRec, которая описывает хранимые данные. Как минимум структура записи повторяет структуру таблицы, но возможны варианты. Объявите новый тип как показано ниже:

type  {Example02}
  PItemRec = ^ItemRec;
  ItemRec = record
  PId : integer;
  Parent: integer;
  PSurName : String;
  PBrDate : TDate;
  PStatus : String;
  PSalary : Double;
  end;

       Поля PCount и POrder не включены в запись ItemRec, так как являются служебными и в приложении не изменяются.
       После этого можно изменить процедуры из примера {Example01} следующим образом:

procedure TForm1.PeopleDatasetOpen(); {Example02}
Var
   sFld,sCod  : String;
   ChildNode,NewNode : TTreeNode;
   RecNode : PItemRec;
   Cnt : Integer;
begin
  inherited;
  If qrTVPeople.Database.Connected then begin
01   tvPeople.Items.Clear;
02   tvPeople.Items.BeginUpdate;
03   trTVPeople.Active := True;
04   qrTVPeople.Close;   qrTVPeople.SQL.Clear;
05   qrTVPeople.SQL.Add('Select * from People');
06   qrTVPeople.SQL.Add(' where Parent=0 and PID<>0');
07   qrTVPeople.SQL.Add(' order by POrder');
08   qrTVPeople.Open;     qrTVPeople.First;
09   While not qrTVPeople.EOF do begin
10      sCod := '';
11      If not VarIsNull(qrTVPeople.FieldValues['PStatus']) then begin
12         sCod := qrTVPeople.FieldValues['PStatus'];
13         sCod := sCod + ' - ';
14         end;
15      sFld := qrTVPeople.FieldValues['PSurName'];
16      New(RecNode);
17      RecNode^.PId    := qrTVPeople.FieldValues['PID'];
18      RecNode^.Parent := qrTVPeople.FieldValues['Parent'];
19                  Cnt := qrTVPeople.FieldValues['PCount'];
20      If not VarIsNull(qrTVPeople.FieldValues['PSurName'])
21             then RecNode^.PSurName:=qrTVPeople.FieldValues['PSurName'];
22      If not VarIsNull(qrTVPeople.FieldValues['PBrDate'])
23             then RecNode^.PBrDate:=qrTVPeople.FieldValues['PBrDate'];
24      If not VarIsNull(qrTVPeople.FieldValues['PStatus'])
25             then RecNode^.PStatus:=qrTVPeople.FieldValues['PStatus'];
26      If not VarIsNull(qrTVPeople.FieldValues['PSalary'])
27             then RecNode^.PSalary:=qrTVPeople.FieldValues['PSalary'];
28      NewNode:=tvPeople.Items.AddObject(tvPeople.TopItem,sCod+sFld,RecNode);
29      If Cnt>0 then
30         ChildNode:=tvPeople.Items.AddChild(NewNode,IntToStr(Cnt));
31      NewNode.ImageIndex := 0; //Поставить картинку
32      qrTVPeople.Next;
33   end; // While not qrTVPeople.EOF do
34   tvPeople.Items.EndUpdate;
35   tvPeople.Update;
36   qrTVPeople.Close;      trTVPeople.Active := False;
   end; // qrTVPeople.Database.Connected
end;

       Строки 01-15 не изменились, а вот в строке 16 создаем новый экземпляр записи и в строках 17-27 заполняем элементы записи значениями из таблицы.
       В строке 28 создаем не просто узел, а узел с объектом. Соответственно, появился дополнительный параметр, в котором записываем указатель на созданную запись RecNode.
       В строке 31 можно присвоить номер картинки, которая будет показана около узла. Здесь можно также указать номер картинки для ImageStatus.
       Вторая процедура, которая вызывается при раскрытии узла, также претерпела изменения.
       Точно таким же образом создается новый экземпляр записи, заполняется данными и указатель на него передается в качестве параметра при создании узла.

procedure TForm1.tvPeopleExpanding(Sender: TObject; Node: TTreeNode;
                                   var AllowExpansion: Boolean); {Example02}
Var
   sFld,sCod : String;
   ChildNode,NewNode : TTreeNode;
   RecNode, RecChild : PItemRec;
   Cnt : Integer;
begin
  inherited;
  If Node.HasChildren then begin
01   Node.DeleteChildren;  New(RecNode); RecNode := Node.Data;
02   trTVPeople.Active := True;
03   qrTVPeople.Close;  qrTVPeople.SQL.Clear;
04   qrTVPeople.SQL.Add('Select * from People');
05   qrTVPeople.SQL.Add(' where Parent='+IntToStr(RecNode.PId));
06   qrTVPeople.SQL.Add(' order by POrder');
07   qrTVPeople.Open;  qrTVPeople.First;
08   tvPeople.Items.BeginUpdate;
09   While not qrTVPeople.EOF do Begin
10      sCod := '';
11      If not VarIsNull(qrTVPeople.FieldValues['PStatus']) then begin
12         sCod := qrTVPeople.FieldValues['PStatus'] + ' - ';
13         end;
14      sFld := qrTVPeople.FieldValues['PSurName'];
15      New(RecChild);
16      RecChild^.PId    := qrTVPeople.FieldValues['PID'];
17      RecChild^.Parent := qrTVPeople.FieldValues['Parent'];
18                   Cnt := qrTVPeople.FieldValues['PCount'];
19      If not VarIsNull(qrTVPeople.FieldValues['PSurName'])
20             then RecChild^.PSurName:=qrTVPeople.FieldValues['PSurName'];
21      If not VarIsNull(qrTVPeople.FieldValues['PBrDate'])
22             then RecChild^.PBrDate:=qrTVPeople.FieldValues['PBrDate'];
23      If not VarIsNull(qrTVPeople.FieldValues['PStatus'])
24             then RecChild^.PStatus:=qrTVPeople.FieldValues['PStatus'];
25      If not VarIsNull(qrTVPeople.FieldValues['PSalary'])
26             then RecChild^.PSalary:=qrTVPeople.FieldValues['PSalary'];
27      newNode := tvPeople.Items.AddChildObject(Node,sCod+sFld,RecChild);
28      If Cnt>0 then
29         ChildNode := tvPeople.Items.AddChild(NewNode,IntToStr(Cnt));
30      NewNode.ImageIndex := 0; //Поставить картинку
31      qrTVPeople.Next;
32   end; // While not qrTVPeople.EOF do
33      tvPeople.Items.EndUpdate;
34      trTVPeople.Active := False;
  end; // Node.HasChildren
  tvPeople.Update;
end;

       В строке 01 удаляем существующих детей, создаем новый экземпляр записи и копируем в него содержимое записи из узла.
       В строках 03-07 строим и открываем запрос для отображение детей текущего узла, для чего из полученной записи извлекаем PID текущего узла (строка 05).
       Остальные строки повторяют соответствующие строки из PeopleDatasetOpen, за исключением строки 27, где узел создается как дочерний к текущему узлу, а не к корню дерева.
       Однако, Delphi не следит за распределением памяти для дополнительных структур данных в узлах. Для того чтобы правильно освобождать память при удалении узла необходимо для события onDeletion написать следующий код:

procedure TForm1.tvPeopleDeletion(Sender:TObject; Node:TTreeNode); {Example02}
begin
   Dispose(Node.Data);
end;

© 01.08.2009, Архангельский А.Г.

<<Пред. Оглавление
Об Авторе
Все персоны
Главная страница
След.>>



Поддержите культуру
ЯндексЯндекс. ДеньгиХочу такую же кнопку

Google
 
Web azdesign.ru az-libr.ru


Дата последнего изменения:
Wednesday, 23-Oct-2013 09:02:56 UTC