Author: Jonas Bilinkevicius
How do I load or recreate a menu stored in a text file? I'm looking for a recursive
function.
Answer:
The following seems to work if the data is always organized the way you gave
(depth-first recursion).
Level|Name|Caption|
0|miItem1|Item 1|
1|miItem11|Sub Item 1-1|
1|miItem12|Sub Item 1-2|
2|miItem121|Sub sub Item 1-2-1|
0|miItem2|Item 2|
1|miItem21|Sub Item 2-1|
1|miItem22|Sub Item 2-2|
I found it easier to use a stack instead of recursion, however:
1 unit Unit1;
2
3 interface
4
5 uses
6 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
7 ComCtrls, StdCtrls, Menus;
8
9 type
10 TForm1 = class(TForm)
11 Button1: TButton;
12 Label1: TLabel;
13 MainMenu1: TMainMenu;
14 Memo1: TMemo;
15 procedure Button1Click(Sender: TObject);
16 private
17 { Private declarations }
18 procedure MenuClick(Sender: TObject);
19 public
20 { Public declarations }
21 end;
22
23 var
24 Form1: TForm1;
25
26 implementation
27
28 uses contnrs;
29
30 {$R *.DFM}
31
32 function IScan(ch: Char; const S: string; fromPos: Integer): Integer;
33 var
34 i: Integer;
35 begin
36 Result := 0;
37 for i := fromPos to Length(S) do
38 begin
39 if S[i] = ch then
40 begin
41 Result := i;
42 Break;
43 end;
44 end;
45 end;
46
47 procedure SplitString(const S: string; separator: Char; substrings: TStringList);
48 var
49 i, n: Integer;
50 begin
51 if Assigned(substrings) and (Length(S) > 0) then
52 begin
53 i := 1;
54 repeat
55 n := IScan(separator, S, i);
56 if n = 0 then
57 n := Length(S) + 1;
58 substrings.Add(Copy(S, i, n - i));
59 i := n + 1;
60 until
61 i > Length(S);
62 end;
63 end;
64
65 procedure LoadMenuFromText(aMenu: TMenu; text: TStrings; aHandler: TNotifyEvent);
66 type
67 TMenuData = record
68 level: Integer;
69 name: string;
70 caption: string
71 end;
72
73 procedure SplitLine(const line: string; var data: TMenuData);
74 var
75 sl: TStringlist;
76 begin
77 sl := TStringlist.Create;
78 try
79 SplitString(line, '|', sl);
80 Assert(sl.count >= 3);
81 data.level := StrToInt(sl[0]);
82 data.name := sl[1];
83 data.caption := sl[2];
84 finally
85 sl.free
86 end;
87 end;
88
89 var
90 itemStack: TStack;
91 level: Integer;
92 i: Integer;
93 menudata: TMenuData;
94 newitem: TMenuItem;
95 begin
96 level := 0;
97 itemstack := TStack.Create;
98 try
99 itemstack.Push(aMenu.Items);
100 {skip header line}
101 for i := 1 to text.count - 1 do
102 begin
103 SplitLine(text[i], menudata);
104 newitem := Menus.NewItem(menudata.caption, 0, false, true, aHandler, 0,
105 menudata.name);
106 while level > menudata.level do
107 begin
108 itemstack.Pop;
109 Dec(level);
110 end;
111 TMenuItem(itemstack.Peek).Add(newitem);
112 Itemstack.Push(newitem);
113 Inc(level)
114 end;
115 finally
116 itemstack.free;
117 end;
118 end;
119
120 procedure TForm1.Button1Click(Sender: TObject);
121 begin
122 LoadMenuFromText(mainmenu1, memo1.lines, MenuClick);
123 end;
124
125 procedure TForm1.MenuClick(Sender: TObject);
126 begin
127 label1.caption := (Sender as TMenuItem).Name;
128 end;
129
130 end.
|