Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

TreeView [D7]


ДяволСД ©   (2006-10-18 08:18:00) 

Мне из базы нужно заполнить TreeView сделающим образом
Корень
 Категория 1
   Подкатегория 1
     подподкатегория 1
   Подкатегория 2
 Категория 2
И т.д....
Желательно ещё у ентих пунктов как-то хранить ID категории из базы. Данные в базе следующего вида: catid (ID категории), parentid (ID родителя категории 0 - родитель корень), name (Имя категории), ...
Как сие оптимально реализовать? Пасибо заранее за ответ!


Loginov Dmitry   (2006-10-19 07:50:00) [1]

Может здесь че-нить полезного найдешь:

procedure TCardsFrame.BuildTreeByDBData;
var
 MainNode, TempNode, SelectNode: TTreeNode;
 I: Integer;
 NodeList: TList;
 CardData: PCardData;
 AKey: Integer;
begin
 if CardioDM.dstCards.FieldByName('CRD_ID').IsNull then
   AKey := -1
 else
   AKey := CardioDM.dstCards.FieldByName('CRD_ID').AsInteger;
   
 DBTreeView.Items.BeginUpdate;
 ClearData;
 DBTreeView.Items.Clear;

 // Создаем корень дерева
 MainNode := DBTreeView.Items.AddChild(nil, 'Все картотеки');
 with MainNode do
 begin
   ImageIndex := 1;
   SelectedIndex := 1;
 end;
 SelectNode := MainNode;

 NodeList := TList.Create;
 try
   with CardioDM.dstCards do
   begin
     First;
     while not Eof do
     begin
       TempNode := DBTreeView.Items.AddChild(MainNode, FieldByName('CRD_NAME').AsString);
       with TempNode do
       begin
         New(CardData);
         FillChar(CardData^, SizeOf(TCardData), 0);
         CardData^.cdKey := FieldByName('CRD_ID').AsInteger;
         if CardData^.cdKey = AKey then SelectNode := TempNode;
         if not FieldByName('CRD_OWNERID').IsNull then
           CardData^.cdOwnerKey := FieldByName('CRD_OWNERID').AsInteger;
         if not FieldByName('CRD_DATE').IsNull then
           CardData^.cdDate := FieldByName('CRD_DATE').AsDateTime;
         Data := CardData;
       end;

       // Добавляем новый итем в список
       NodeList.Add(TempNode);
       Next;
     end;
     // Упорядочиваем итемы в соответствии в CRD_OWNERID
     for I := 0 to NodeList.Count - 1 do
       TTreeNode(NodeList[I]).MoveTo(FindParentNode(TTreeNode(NodeList[I])), naAddChild);

   end;
 finally
   NodeList.Free;
   DBTreeView.Items.EndUpdate;
 end;

 // Выделяем необходымый итем
 DBTreeView.Selected := SelectNode;
end;


markers   (2006-10-18 23:53:00) [2]

to Сергей М.
Мдя, столкнулся с такой проблемой, почему-то в не находил родителя...
Начал переделывать на рекурсию... Толи чё-то не так делаю (Давно в Дельфях не работал и долго в PHP) толи чё.... Вообщем вот код
function catfill(parentid:string='0'; pnod : TTreeNode = nil):Boolean;
 var nod: TTreeNode;
 begin
  ResRow:=DB.exec('SELECT * FROM mag_categories WHERE parentid = '+onequote+
    parentid+onequote+' AND cattype <> '+onequote+'Deleted'+onequote+' ORDER ' +
    'BY `name` ASC');
  while not ResRow.eof do
   begin
    nod := Tree.Items.AddChild(pnod,VarToStr(ResRow[4]));
    nod.Data := Pointer(StrToInt(VarToStr(ResRow[0])));
    catfill(ResRow[0],nod);
    ResRow.next;
   end;
 end;

Как я понял вызов построения детей происходит и от туда уже не возвращается..... :( если закоментировать catfill(ResRow[0],nod); то построится дерево подчинёных корню (как и должно быть). Подскажите плиз!


Сергей М.   (2006-10-18 12:03:00) [3]


> Можно сделать что если узел не найден то делать корнем


Хм ... В базе элемент дерева числится как дочерний, а в TreeView он вдруг ни с того ни с сего выглядит корневым ? Ну и разве это правильно ? Подумай ... Дело даже не в том как это визуально выглядит - такая ситуация чревата серьезными ошибками при дальнейшей модификации базы ..


Amoeba   (2006-10-18 11:44:00) [4]

http://www.delphikingdom.com/asp/viewitem.asp?catalogid=783


ДьяволСД   (2006-10-18 11:27:00) [5]

Можно сделать что если узел не найден то делать корнем.


Сергей М.   (2006-10-18 11:08:00) [6]

Боюсь что твой алгоритм когда-нибудь затрещит по швам.

Вот смотри :

  else if StrToInt(VarToStr(ResRow[3])) <> 0 then
  //узел не корневой
  begin
   //ищем родителя
   Nod := FindTreeNode(CatsView.TopItem,StrToInt(VarToStr(ResRow[3])));
   //если родитель не найден, то родителем создаваемого узла у тебя станет черт-те какой узел, но только не тот который должен быть
   TTreeNode(Tree.Items.AddChild(Nod,VarToStr(ResRow[4]))).Data :=
    Pointer(StrToInt(VarToStr(ResRow[0]))); // Добавляет под....
  end;

Нужен рекурсивный алгоритм, и одним SQL-запросом в общем случае не обойтись: для каждого "родителя" должен осуществляться SQL-запрос его "детей". Самый первый запрос должен вернуть корневые узлы, от которых и пойдет дальнейшая пляска


ДьяволСД   (2006-10-18 10:55:00) [7]

Я всё-таки енто сделал :) Если кому интересно, вот код:
procedure TMainForm.CatListFill(Tree: TTreeView);
var
 Nod:TTreeNode;

 Function FindTreeNode(FirstNode: TTreeNode; Const Pointid: integer): TTreeNode;
  Begin
   Result:= FirstNode;
   While Result <> Nil Do
     Begin
       If Integer(Result.Data) = Pointid Then Exit;
       Result:= Result.GetNext;
     End;
  End;

begin
ResRow:=DB.exec('SELECT * FROM mag_categories WHERE cattype <> '+onequote+
  'Deleted'+onequote+' ORDER BY `name` ASC');
Tree.Items.BeginUpdate;
Tree.SortType:=TSorttype(stNone);
while not ResRow.eof do
 begin
  if StrToInt(VarToStr(ResRow[3])) = 0 then
   begin
    TTreeNode(Tree.Items.Add(nil,VarToStr(ResRow[4]))).Data :=
     Pointer(StrToInt(VarToStr(ResRow[0]))); //Корневые ноды
   end
  else if StrToInt(VarToStr(ResRow[3])) <> 0 then
   begin
    Nod := FindTreeNode(CatsView.TopItem,StrToInt(VarToStr(ResRow[3])));
    TTreeNode(Tree.Items.AddChild(Nod,VarToStr(ResRow[4]))).Data :=
     Pointer(StrToInt(VarToStr(ResRow[0]))); // Добавляет под....
   end;
  ResRow.next
 end;
Tree.Items.EndUpdate;
end;

Всем спасибо :)))


Сергей М.   (2006-10-18 09:49:00) [8]


> как интегер в поинте сохранить ентом?


SomeTreeNode.Data := Pointer(12345);


ДьяволСД   (2006-10-18 09:27:00) [9]

Сергей М.
А не подскажите как интегер в поинте сохранить ентом? Где-то проскакивало, найти не могу :(


ДьяволСД   (2006-10-18 09:22:00) [10]

вообщем так я получаю данные
ResRow:=DB.exec('SELECT * FROM mag_categories ORDER BY `name` ASC');
while not ResRow.eof do
 begin
  cols:=ResRow.fieldcount;
  v:=ResRow[4]; // 1 - Catid, 3 - parentid, 4 - name
  a1:=VarToStr(v);
  CatsView.Items.AddChildFirst(nil,a1); // сделал тестовое заполнение корня
  ResRow.next
 end


Сергей М.   (2006-10-18 09:15:00) [11]


> ДьяволСД   (18.10.06 09:00) [2]


Абракадабра какая-то ...


> как ID дополнительно хранить?
>


Например, в св-ве TTreeNode.Data


ДьяволСД   (2006-10-18 09:08:00) [12]

Хотяб подскажите как ID дополнительно хранить?


ДьяволСД   (2006-10-18 09:00:00) [13]

У меня база не через гриды таблицы и т.д. проходит. Я с базой работаю через юнит (мне так проще) соответственно привязать к DBTreeView не смогу


Сергей М.   (2006-10-18 08:53:00) [14]


> Мне из базы нужно заполнить TreeView


DBTreeView чем не угодил ?


Наверх

Титульная страница Поиск, карта сайта Написать письмо