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

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

Создание меню из дерева


Mitrofan ©   (2004-08-30 10:29:00) 

Господа, нужен помощь в виде програмного кода.
 Имеем дерево в виде таблицы

Id Parent_Id Name

0  Null      File
1  Null      Edit
2  Null      Help
3  0         New
4  0         Open
5  0         Save
6  2         About

И т.д.

Как по этой табличке построить главное меню программы ?


AlexSV   (2004-08-31 12:04:00) [1]

Дополнение:
во втором примере
Filter := 'Parent_id = -1';
т.е. вместо
Null в Parent_id надо поставить -1
При фильтрации Null воспринимается как 0


AlexSV   (2004-08-31 11:59:00) [2]

> Mitrofan
есть два варианта построения меню:
(в примерах MenuTable - таблица из вопроса)
1. прямой проход по таблице.
Поскольку у MainMenu нет сквозного списка его Item'ов,
то создаем массив array of TMenuItem
пример:
procedure TForm1.FormShow(Sender: TObject);
var
 ItemList: array of TMenuItem;
begin
 with MenuTable do begin
   Open;
   SetLength(ItemList, RecordCount);
   try
     First;
     while not Eof do begin
       ItemList[FieldByName('id').AsInteger] := TMenuItem.Create(MMenu);
       ItemList[FieldByName('id').AsInteger].Caption := FieldByName('Name').AsString;
       if FieldByName('parent_id').IsNull then begin
         MMenu.Items.Add(ItemList[FieldByName('id').AsInteger]);
       end else
         ItemList[FieldByName('parent_id').AsInteger].Add(ItemList[FieldByName('id').AsInteger]);
       Next;
     end;
   finally
     SetLength(ItemList, 0);
     Close;
   end;
 end;
end;

2. Рекурсивный обход с фильтрацией набора данных.
пример:
procedure TForm1.CreateSubMenu(AMenu: TMenu; AMenuItem: TMenuItem; ADataSet: TDataSet);
var
 ParentItem, NewItem: TMenuItem;
 ItemID: integer;
begin
 with ADataSet do begin
   if AMenuItem = nil then begin
     Filter := 'Parent_id = -1';
     ParentItem := AMenu.Items;
   end else begin
     Filter := 'Parent_id = ' + IntToStr(AMenuItem.Tag);
     ParentItem := AMenuItem;
   end;
   Filtered := True;
   First;
   while not Eof do begin
     NewItem := TMenuItem.Create(MMenu);
     NewItem.Caption := FieldByName('Name').AsString;
     NewItem.Tag := FieldByName('id').AsInteger;
     ParentItem.Add(NewItem);
     Next;
   end;
   Filtered := False;
   if (ParentItem.Count > 0) then
     for ItemID := 0 to ParentItem.Count - 1 do begin
       CreateSubMenu(AMenu, ParentItem.Items[ItemID], ADataSet);
       if (ParentItem.Items[ItemID].Count = 0) then
         ParentItem.Items[ItemID].OnClick := ItemClick;
     end;
 end;
end;

procedure TForm1.ItemClick(Sender: TObject);
begin
 ShowMessage(TMenuItem(Sender).Caption);
end;

запуск процедуры создания меню:
procedure TForm1.FormShow(Sender: TObject);
begin
 MenuTable.Open;
 try
   CreateSubMenu(MMenu, nil, MenuTable);
 finally
   MenuTable.Close;
 end;
end;


Mitrofan   (2004-08-31 10:18:00) [3]

> begin...end
Данный код не пропустит следующую струтктуру
FArray[7, 1] := '7';
FArray[7, 2] := '3';
FArray[7, 3] := 'New 1';

Т.е. если дерево имеет более сложную иерерхию чем представлено в [0]


begin...end   (2004-08-30 17:31:00) [4]


> [16] Erik1   (30.08.04 16:51)

Неужели? А что же тогда представляет из себя Ваш пост [9] ?

Вот Вам код:

var
 I, J: Integer;
 NewMenuItem: TMenuItem;
 FArray: array [0..6, 1..3] of String;
begin

 // Имитация чтения файла

 FArray[0, 1] := '0';
 FArray[1, 1] := '1';
 FArray[2, 1] := '2';
 FArray[3, 1] := '3';
 FArray[4, 1] := '4';
 FArray[5, 1] := '5';
 FArray[6, 1] := '6';
 FArray[0, 2] := 'Null';
 FArray[1, 2] := 'Null';
 FArray[2, 2] := 'Null';
 FArray[3, 2] := '0';
 FArray[4, 2] := '0';
 FArray[5, 2] := '0';
 FArray[6, 2] := '2';
 FArray[0, 3] := 'File';
 FArray[1, 3] := 'Edit';
 FArray[2, 3] := 'Help';
 FArray[3, 3] := 'New';
 FArray[4, 3] := 'Open';
 FArray[5, 3] := 'Save';
 FArray[6, 3] := 'About';

 // Заполнение меню

 for I := 0 to 6 do
   if FArray[I, 2] = 'Null' then
   begin
     NewMenuItem := TMenuItem.Create(MainMenu);
     NewMenuItem.Tag := I;
     NewMenuItem.Caption := FArray[I, 3];
     MainMenu.Items.Add(NewMenuItem);
   end
   else
   begin
     for J := 0 to MainMenu.Items.Count - 1 do
       if MainMenu.Items[J].Tag = StrToInt(FArray[I, 2]) then
       begin
         NewMenuItem := TMenuItem.Create(MainMenu);
         NewMenuItem.Caption := FArray[I, 3];
         MainMenu.Items[J].Add(NewMenuItem);
       end;
   end;

end;


Коряво, некрасиво, нерационально? НЕ СПОРЮ.
Но - это корректно обрабатывает таблицу, указанную в [0].
А Вы в [9], насколько я понял, намекали на то, что это неправильно.

Но давайте не будем больше спорить.
Возможно, мы просто по-разному поняли задание.
Без обид.

:-)

---
Sorry, I'm drunk now


Erik1   (2004-08-30 16:51:00) [5]

To begin...end
Я флеймом незанимаюсь. :)


begin...end   (2004-08-30 12:00:00) [6]

>  [13] Erik1   (30.08.04 11:46)

> Вопрос был как построить мену по дереву

Вопрос был: Как по этой табличке построить главное меню программы ?

Ещё раз: методом [4] этого принципиально нельзя сделать?


DesWind   (2004-08-30 11:54:00) [7]

Таблицу можно скэшировать.
TCacheItem=class(TObject)
ID: integer;
ParentID: integer;
Value: string;
end;

TCache=class(TObjectList);

procedure AddChild(ID:integer);
var
c: integer;

begin
for c:=0 to cacheList.Count-1 do
if CacheList[c].ParentID=ID then
 begin
  ...// добавление дочернего элемента в меню
 if IsParent(CacheList[c].ID) then AddChild(CacheList[c].ID);
 end;

end;

for c:=0 to cacheList.Count-1 do
if CacheList[c].ParentID=0 then
 begin
  ...// добавление корневого элемента в меню
 if IsParent(CacheList[c].ID) then AddChild(CacheList[c].ID);
 end;

Это у меня для TreeView так что может придется кой че подправить


Erik1   (2004-08-30 11:46:00) [8]

To begin...end
Вопрос был как построить мену по дереву. А твой ответ подрузамевает выкинуть часть алгоритма обхода. Общий метод потом ненаписать если пойдеш по указаному тобой пути. Если бы ты просто написал
NewMenuItem := TMenuItem.Create(MainMenu);
MainMenu.Items.Add(...)
то я бы неимел ничего против. А так включил в общею компанию :)


YurikGL   (2004-08-30 11:38:00) [9]

Делал с TTreeNode алгоритм рекурсии примерно такой.

Рекурсия (входной элемента)
В датасет1 выбираем всех детей входного элемента
Создаем динамический список элементов
Если их количество=0 то выход
Иначе
 Для всех элементов датасет1 начало
   добавить в дерево используя в качестве родителя Входной элемент.
   добавить в динамический список
                             конец
Для всего динамического списка применть рекурсию
Удалить динамический список
Выход


begin...end   (2004-08-30 11:29:00) [10]

> [9] Erik1   (30.08.04 11:21)

> Вопрос к отвечающим, ну зачем человеку ерунду советовать если сами незнаете?

Встречный вопрос: чем Вас ПРИНЦИПИАЛЬНО не устроило [4]?


Mitrofan   (2004-08-30 11:27:00) [11]

Просто может кто нибудь уже сталкивался с подобной проблемой ?
Меню хранится в базе и его надо создать при запуске приложения.


Erik1   (2004-08-30 11:21:00) [12]

Как сложно воспользоватся поисковиком и набрать "рекурсивный алгоритм обхода дерева".
 Вопрос к отвечающим, ну зачем человеку ерунду советовать если сами незнаете?


Ega23   (2004-08-30 11:11:00) [13]

TMainMenu.FindItem?


KADAN   (2004-08-30 11:06:00) [14]

в Tag хранить Id или создать массив связок
array[i,0]:=Id;
array[i,1]:=integer(MenuItem);


begin...end   (2004-08-30 11:02:00) [15]

> Mitrofan   (30.08.04 10:56) [5]

Например, можно при создании NewMenuItem записывать его Id в TMenuItem.Tag.
А потом, при поиске, пробежаться по Items и найти Item с нужным Tag.


Mitrofan   (2004-08-30 10:56:00) [16]

Вот в этот то и вопрос как его найти ???


begin...end   (2004-08-30 10:51:00) [17]

Может быть, что-то вроде этого...

1. Читаем строку таблицы.
2. Если Parent_Id = NULL, то
   {
     NewMenuItem := TMenuItem.Create(MainMenu);
     MainMenu.Items.Add(...)
   }
   иначе
   {
     MenuItem := // вот тут надо как-то найти существующий Item с Parent_Id
     MenuItem.Items.Add(...)
   }


Erik1   (2004-08-30 10:38:00) [18]

Тебе наверное нужно обойти дерево? И то этому дереву построить меню. Можеш сам придумать рекурсивный алгоритм обхода дерева, а можеш в инете посикать.


Mitrofan   (2004-08-30 10:36:00) [19]

Нужен программный код видимо с рекурсией.
А вот как именно организовать эту рекурсию не могу сообразить.


Ega23   (2004-08-30 10:33:00) [20]

TMainMenu.Items.add ?


Наверх

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