VCL Delphi

Title: Flexmenu component
Question: How to add or remove itmes on a menu dynamicly?
Answer:
How to add or remove itmes on a menu dynamicly?
TFlexMenu enables you to add or remove itmes on a menu dynamicly.
Useful for flexibe menu entries like recently used or window lists.Features automatic numbering of the added menuitems and automatic add/remove of separator lines. TFlexMenu is a non visual component.
TFlexMenu provides the following properties and methods:
Properties:
===========
MaxItems = Number of menuitems that can be added to the menu.
-1 means that there is no limit. If you set a Limit,
not more than MaxItems entries are added to the
parent menu.
ParentMenu = The TMenuItem that the Subitems are added to,
NumberItems = True means, that the entries are numberd by
TFlexMenu. Example:
1 Entry No. one
2 Entry No. two
3 Entry No. three
4 Entry No. four
If you remove "Entry No. two" the items will be
renumberd and look like this:
1 Entry No. one
2 Entry No. three
3 Entry No. four
If NumberItems is true, the Number is the Shotcut
to the MenuItem!
CreateLine = If true, The first added menuitem also adds a
separator line to the menu. The line is
automaticly removed, if all menus that are added
are removed.
Methodes:
=========
Create = Creates the component
Destroy = Destroys the component
Add = Adds a menuitem to the parent menu. The methode
returns the added Menuitem as a TMenuItem object.
Parameters:
title = The caption of the menuitem
checked = The item is checked
enabled = The item is enabled
tag = The property Tag of the TMenuItem
click = The event handler for the OnClick event of
the TMenuItem
Remove = Removes the menuitem from the parent menu. Parameters:
item = The TMenuItem, returned by Add or GetItem.
ChangeCaption = Changes the Caption OF the menuitem. You should
always use this methode instead manipulating
the menuitem in direct way,because ChangeCaption
updates the numbering. Parameters:
item = The TMenuItem, returned by Add or GetItem
title = The new caption of the menuitem
GetItem = Returns the TMenuItem with the specific number from
the list of the added menuitems, or NIL if the item
not exist. Parameters:
item = The Number of the wanted TMenuItem
Installation:
Copy the unit FLEXMENU.PAS into your library path.
Select Components - Install Components from the Delphi
main menu and put FLEXMENU.PAS to a package of your choice.
//-----------------------------------------------------------
unit FlexMenu;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Menus;
type Str80 = string[80];
type PtrMenuEntry = ^tMenuEntry;
tMenuEntry = Record
Caption: Str80;
item: TMenuItem;
end;
type TFlexMenu = class(TComponent)
private
Flist: TList;
FMenuLine: TMenuItem;
FAdded: BOOLEAN;
protected
FMenu: TMenuItem;
FMax: INTEGER;
FNumber: BOOLEAN;
FLine: BOOLEAN;
procedure NumberEntries;
public
published
constructor Create (AOwner: TComponent); override;
destructor Destroy; override;
property MaxItems: INTEGER read FMax write FMax;
property ParentMenu: TMenuItem read FMenu write FMenu;
property NumberItems: BOOLEAN read FNumber write FNumber;
property CreateLine: BOOLEAN read FLine write FLine;
function Add (CONST title: STRING;
Checked, Enabled: BOOLEAN; tag: INTEGER;
click: TNotifyEvent): TMenuItem;
procedure ChangeCaption (item: TMenuItem; title: STRING);
procedure Remove (item: TMenuItem);
function GetItem (item: INTEGER): TMenuItem;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TFlexMenu]);
end;
constructor TFlexMenu.Create (AOwner: TComponent);
begin
INHERITED;
FMax:= -1;
FNumber:= False;
FLine:= False;
FMenuLine:= NIL;
FMenu:= NIL;
FList:= TList.Create; // List of Menuitems
FAdded:= False;
end;
desturctor TFlexMenu.Destroy;
var i: integer;
begin
// Free the list
for i:= 0 to FList.Count - 1 do Dispose (FList[i]);
FList.Free;
inherited;
end;
function TFlexMenu.GetItem (item: integer): TMenuItem;
// returns item number "item" from the list
var m: PtrMenuEntry;
begin
m:= FList.Items[item];
if m NIL then Result:= m.item
else Result:= NIL;
end;
procedure TFlexMenu.NumberEntries;
var m: PtrMenuEntry;
s: string;
i: integer;
begin
// modify captions, if the user want numbering
if FNumber then begin
for i:= 0 to FList.Count - 1 DO begin
m:= FList.Items[i];
if m NIL then begin
s:= '&' + IntToStr (i+1) + ' ' + m^.Caption;
m.item.Caption:= s;
end;
end;
end;
end;
function TFlexMenu.Add (const title: string;
Checked, Enabled: Boolean;
tag: integer;
click: TNotifyEvent): TMenuItem;
// Add a Menuitem to the parentmenu
var p: PtrMenuEntry;
begin
Result:= NIL;
// More items than allowed?
if (FMax -1) and (FList.Count = FMax) then Exit;
// Shall we add a line?
IF (NOT FAdded) AND FLine then begin
FMenuLine:= NewLine;
FMenu.Add (FMenuline);
FAdded:= TRUE;
end;
New (p); // New Entry
IF p NIL then begin
p^.Caption:= title;
// generate the Menuitem
p^.item:= NewItem (title, 0, checked, enabled, click, 0, '');
p^.item.Tag:= tag;
Result:= p^.item;
FList.Add (p); // Save entry to the list
FMenu.Add (p^.item); // Number the entries
NumberEntries;
end;
end;
procedure TFlexMenu.Remove (item: TMenuItem);
// Remove a Menuitem from the parentmenu
var p: PtrMenuEntry;
i: integer;
begin
// find the item
for i:= 0 to FList.Count - 1 DO begin
p:= FList.Items[i];
IF p NIL then begin
IF p^.item = item then begin
// Remove it from the menu
FMenu.Remove (p^.item);
// free the Entry
Dispose (p);
// Delete it from the list
FList.Delete (i);
// Pack the list
FList.Pack;
// New number of entry?
NumberEntries;
// If it was the last entry, then remove the tearline
IF (FList.Count FMenu.Remove (FMenuLine);
FMenuLine:= NIL;
FAdded:= False;
end;
EXIT;
end;
end;
end;
end;
procedure TFlexMenu.ChangeCaption (item: TMenuItem; title: STRING);
// Change Caption of an Menuitem
var p: PtrMenuEntry;
i: integer;
begin
// Search for item
for i:= 0 TO FList.Count - 1 DO begin
p:= FList.Items[i];
IF p NIL then begin
IF p^.item = item then begin
// change caption
p^.Caption:= title;
p^.item.Caption:= p^.Caption;
// New numeration
NumberEntries;
EXIT;
end;
end;
end;
end;
end.