The following code demonstrates the issue. It updates the text of some menu items. The FormActivate function takes over half a second on my laptop. That time increases significantly the more menu items there are and especially if the menu items have images. That increases startup time for my app significantly. I have used TForm.BeginUpdate to try to prevent update until all are done, but that only seems to help a little. Running for Windows 32-bit.
Note that there are two types of menu item in my example. The ones I'm updating and the ones I'm not. The ones I'm updating don't have images. It's the presence of the ones I'm not updating that have images that slows it down. From this I have to assume that the whole menu is being updated and repainted each time I update one menu item. What seems to be missing is a TMainMenu.BeginUpdate and TMainMenu.EndUpdate.
Edit: I found the following comment in FMX.Platform.Menu.Win procedure TWinMenuService.UpdateMenuItem.
// If Visible, Text or Shortcut are changed, then we need to rebuild menu. Because WinApi doesn't support
RecreateMainMenu(MenuItem);
Form:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 480
ClientWidth = 640
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
OnActivate = FormActivate
OnCreate = FormCreate
DesignerMasterStyle = 0
object MainMenu1: TMainMenu
Images = ImageList1
Left = 32
Top = 40
object MenuItem1: TMenuItem
Text = 'File'
object MenuItem22: TMenuItem
Locked = True
Text = 'Recent Files'
object MenuItem2: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem3: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem4: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem5: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem6: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem7: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem8: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem9: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem10: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem11: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem12: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem13: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem14: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem15: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem16: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem17: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem18: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem19: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem20: TMenuItem
Locked = True
Text = 'Recent File'
end
object MenuItem21: TMenuItem
Locked = True
Text = 'Recent File'
end
end
object MenuItem33: TMenuItem
Locked = True
Text = 'MenuItem33'
ImageIndex = 0
end
object MenuItem32: TMenuItem
Locked = True
Text = 'MenuItem32'
ImageIndex = 0
end
object MenuItem31: TMenuItem
Locked = True
Text = 'MenuItem31'
ImageIndex = 0
end
object MenuItem30: TMenuItem
Locked = True
Text = 'MenuItem30'
ImageIndex = 0
end
object MenuItem29: TMenuItem
Locked = True
Text = 'MenuItem29'
ImageIndex = 0
end
object MenuItem28: TMenuItem
Locked = True
Text = 'MenuItem28'
ImageIndex = 0
end
object MenuItem27: TMenuItem
Locked = True
Text = 'MenuItem27'
ImageIndex = 0
end
object MenuItem26: TMenuItem
Locked = True
Text = 'MenuItem26'
ImageIndex = 0
end
object MenuItem25: TMenuItem
Locked = True
Text = 'MenuItem25'
ImageIndex = 0
end
object MenuItem24: TMenuItem
Locked = True
Text = 'MenuItem24'
ImageIndex = 0
end
object MenuItem23: TMenuItem
Locked = True
Text = 'MenuItem23'
ImageIndex = 0
end
object MenuItem34: TMenuItem
Locked = True
Text = 'MenuItem34'
ImageIndex = 0
end
object MenuItem35: TMenuItem
Locked = True
Text = 'MenuItem35'
ImageIndex = 0
end
object MenuItem36: TMenuItem
Locked = True
Text = 'MenuItem36'
ImageIndex = 0
end
object MenuItem37: TMenuItem
Locked = True
Text = 'MenuItem37'
ImageIndex = 0
end
end
object MenuItem38: TMenuItem
Text = 'MenuItem38'
object MenuItem39: TMenuItem
Locked = True
Text = 'MenuItem23'
ImageIndex = 0
end
object MenuItem40: TMenuItem
Locked = True
Text = 'MenuItem24'
ImageIndex = 0
end
object MenuItem41: TMenuItem
Locked = True
Text = 'MenuItem25'
ImageIndex = 0
end
object MenuItem42: TMenuItem
Locked = True
Text = 'MenuItem26'
ImageIndex = 0
end
object MenuItem43: TMenuItem
Locked = True
Text = 'MenuItem27'
ImageIndex = 0
end
object MenuItem44: TMenuItem
Locked = True
Text = 'MenuItem28'
ImageIndex = 0
end
object MenuItem45: TMenuItem
Locked = True
Text = 'MenuItem29'
ImageIndex = 0
end
object MenuItem46: TMenuItem
Locked = True
Text = 'MenuItem30'
ImageIndex = 0
end
object MenuItem47: TMenuItem
Locked = True
Text = 'MenuItem31'
ImageIndex = 0
end
object MenuItem48: TMenuItem
Locked = True
Text = 'MenuItem32'
ImageIndex = 0
end
object MenuItem49: TMenuItem
Locked = True
Text = 'MenuItem33'
ImageIndex = 0
end
object MenuItem50: TMenuItem
Locked = True
Text = 'MenuItem34'
ImageIndex = 0
end
object MenuItem51: TMenuItem
Locked = True
Text = 'MenuItem35'
ImageIndex = 0
end
object MenuItem52: TMenuItem
Locked = True
Text = 'MenuItem36'
ImageIndex = 0
end
object MenuItem53: TMenuItem
Locked = True
Text = 'MenuItem37'
ImageIndex = 0
end
end
end
object ImageList1: TImageList
Source = <
item
MultiResBitmap.LoadSize = 0
MultiResBitmap = <
item
Width = 16
Height = 16
PNG = {
89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF
61000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000
032949444154384F5D934B685C551CC67FF79E7BEFBC3BEF4CD3249369A32636
B6962A68C5E24221561A176E44ECC285F52D2E447421C58D0B11379A45A156A4
8A101485162D546335D08598D6C6A41AA3A6339D4CF39874DA6492CE64E69E7B
BD270C68FCE0700EE7FFFDBEF3E01C8DFF69E2A43D756A489B397E6646BA64EB
A0B950F23F3D9035065F7477EC7AD4E86B5937B429E0A5841CFEB28D68EE39B7
379A231200296AC8D5066E65817AF1236DFAB14556862AE2F116F26F403F856F
52473A72771CA4B3BD4CF54006BD238195CA34E30BF366E5F309562F2645ECAF
B372EEFA91D2E54B743FA2B88D80C3B7C9538BCFB8BDFD0F93CD9F66E6C461D9
23A296A56AFFD55B1FC8DF6FDC47B630CA5CFAA836756C5A0CEA63DFDA57266F
77E37B06C9FDF21BAB3F2F237E1815A5F18BB27CE86D79696858FEBD5E935205
0CDC4D4CC1997B68578C62B5375EB07FAA1FA07B566035D6B04D89737D92F2B5
2081543FE92BA314475EA6ABAB5B6C999C94E5E3799C8DED78F29FA6A0FF3821
6AB50461BF8DBB35846E8531B49D6CF36F2779EE3B160705EB0A069777BFA2DC
62518C62F57A501A8910462C8096AFE25E28D22C9469CC2E504BE7A9BCF78EB6
5701CFBEE9FCFA4911F187147E05AB39C5EAE1ED840316DAD82CF26A154216E6
B64E82F35354875F230B3A5F7C2FAF1E9BC7B76F80F6D2A2B4C7A7A92D398850
1761DDF01CE3D770BC819ED9828847D0A523DCBDB7E2DBB98B985AE9B3332CF7
DE4F9B7A17A918BAF2AA79D3EBB5D78FDAF9F31D248202DD6922BDA322C288A5
3C6BE747980F87D1434902BB1F204303C72BA39B889BDE65DF55A2A21FBC57C4
EA73ACC5E29866106146BCA6A3359AD81F3E4FC7C957C9F56509AC7BABF92318
860F5D7915A3587DFF1E2DB6A346A3D140C6A31841036DA58EB3DB0F4FEE17C9
7DBD22FCF513EB69B78EED33D112094CE5558C6237CE72E215A37B6E8C25E9E0
A4DAB0B626318B1AE2C68A6CAAFAFB177C55159E4C612A8FF22A46D5367DA6A7
3EB51796A2F87B7A0854BDE752F8936AC412A2EE97D62D19ACFC65D652CBD43F
3E64645AC8E600A59129FBE6D959D1182B4B5BF379DBF56ECDD7A079671AF3A1
4ECC07FB8C60CBEA09FE01BAF244AA6BA3EA9D0000000049454E44AE426082}
FileName = 'about.png'
end>
Name = 'about'
end>
Destination = <
item
Layers = <
item
Name = 'about'
end>
end>
Left = 104
Top = 40
end
end
Unit:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Menus,
System.ImageList, FMX.ImgList;
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
MenuItem1: TMenuItem;
MenuItem2: TMenuItem;
MenuItem3: TMenuItem;
MenuItem4: TMenuItem;
MenuItem5: TMenuItem;
MenuItem6: TMenuItem;
MenuItem7: TMenuItem;
MenuItem8: TMenuItem;
MenuItem9: TMenuItem;
MenuItem10: TMenuItem;
MenuItem11: TMenuItem;
MenuItem12: TMenuItem;
MenuItem13: TMenuItem;
MenuItem14: TMenuItem;
MenuItem15: TMenuItem;
MenuItem16: TMenuItem;
MenuItem17: TMenuItem;
MenuItem18: TMenuItem;
MenuItem19: TMenuItem;
MenuItem20: TMenuItem;
MenuItem21: TMenuItem;
MenuItem22: TMenuItem;
MenuItem23: TMenuItem;
MenuItem24: TMenuItem;
MenuItem25: TMenuItem;
MenuItem26: TMenuItem;
MenuItem27: TMenuItem;
MenuItem28: TMenuItem;
MenuItem29: TMenuItem;
MenuItem30: TMenuItem;
MenuItem31: TMenuItem;
MenuItem32: TMenuItem;
MenuItem33: TMenuItem;
ImageList1: TImageList;
MenuItem34: TMenuItem;
MenuItem35: TMenuItem;
MenuItem36: TMenuItem;
MenuItem37: TMenuItem;
MenuItem38: TMenuItem;
MenuItem39: TMenuItem;
MenuItem40: TMenuItem;
MenuItem41: TMenuItem;
MenuItem42: TMenuItem;
MenuItem43: TMenuItem;
MenuItem44: TMenuItem;
MenuItem45: TMenuItem;
MenuItem46: TMenuItem;
MenuItem47: TMenuItem;
MenuItem48: TMenuItem;
MenuItem49: TMenuItem;
MenuItem50: TMenuItem;
MenuItem51: TMenuItem;
MenuItem52: TMenuItem;
MenuItem53: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
RecentFileItems : array[0..19] of TMenuItem;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
begin
// Assign menu items to array
RecentFileItems[0] := MenuItem2;
RecentFileItems[1] := MenuItem3;
RecentFileItems[2] := MenuItem4;
RecentFileItems[3] := MenuItem5;
RecentFileItems[4] := MenuItem6;
RecentFileItems[5] := MenuItem7;
RecentFileItems[6] := MenuItem8;
RecentFileItems[7] := MenuItem9;
RecentFileItems[8] := MenuItem10;
RecentFileItems[9] := MenuItem11;
RecentFileItems[10] := MenuItem12;
RecentFileItems[11] := MenuItem13;
RecentFileItems[12] := MenuItem14;
RecentFileItems[13] := MenuItem15;
RecentFileItems[14] := MenuItem16;
RecentFileItems[15] := MenuItem17;
RecentFileItems[16] := MenuItem18;
RecentFileItems[17] := MenuItem19;
RecentFileItems[18] := MenuItem20;
RecentFileItems[19] := MenuItem21;
end;
procedure TForm1.FormActivate(Sender: TObject);
var
i : Integer;
st : TDateTime;
begin
st := now;
BeginUpdate; // Reduces runtime only slightly
try
for i := 0 to 19 do
RecentFileItems[i].Text := 'Recent File Name ' + IntToStr(i);
finally
EndUpdate;
end;
// Display the time this function took in ms
// Time increases significantly if there are many other menu items with images
Caption := IntToStr(Round((now - st)*24*3600*1000));
end;
end.