How to load a menu from a file (Views: 31)
Problem/Question/Abstract: 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: unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, Menus; type TForm1 = class(TForm) Button1: TButton; Label1: TLabel; MainMenu1: TMainMenu; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } procedure MenuClick(Sender: TObject); public { Public declarations } end; var Form1: TForm1; implementation uses contnrs; {$R *.DFM} function IScan(ch: Char; const S: string; fromPos: Integer): Integer; var i: Integer; begin Result := 0; for i := fromPos to Length(S) do begin if S[i] = ch then begin Result := i; Break; end; end; end; procedure SplitString(const S: string; separator: Char; substrings: TStringList); var i, n: Integer; begin if Assigned(substrings) and (Length(S) > 0) then begin i := 1; repeat n := IScan(separator, S, i); if n = 0 then n := Length(S) + 1; substrings.Add(Copy(S, i, n - i)); i := n + 1; until i > Length(S); end; end; procedure LoadMenuFromText(aMenu: TMenu; text: TStrings; aHandler: TNotifyEvent); type TMenuData = record level: Integer; name: string; caption: string end; procedure SplitLine(const line: string; var data: TMenuData); var sl: TStringlist; begin sl := TStringlist.Create; try SplitString(line, '|', sl); Assert(sl.count >= 3); data.level := StrToInt(sl[0]); data.name := sl[1]; data.caption := sl[2]; finally sl.free end; end; var itemStack: TStack; level: Integer; i: Integer; menudata: TMenuData; newitem: TMenuItem; begin level := 0; itemstack := TStack.Create; try itemstack.Push(aMenu.Items); {skip header line} for i := 1 to text.count - 1 do begin SplitLine(text[i], menudata); newitem := Menus.NewItem(menudata.caption, 0, false, true, aHandler, 0, menudata.name); while level > menudata.level do begin itemstack.Pop; Dec(level); end; TMenuItem(itemstack.Peek).Add(newitem); Itemstack.Push(newitem); Inc(level) end; finally itemstack.free; end; end; procedure TForm1.Button1Click(Sender: TObject); begin LoadMenuFromText(mainmenu1, memo1.lines, MenuClick); end; procedure TForm1.MenuClick(Sender: TObject); begin label1.caption := (Sender as TMenuItem).Name; end; end. |