![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Создание меню из дерева
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 ?