如何在显示子项时将子项动态添加到 TMenuItem
How to add subitems dynamically to a TMenuItem the moment its subitems are shown
我有一个这样的菜单结构:
1. Option A
1.1 Option B
1.1.1 Option C
1.1.2 Option D
1.2 Option C
1.2.1 Option B
1.2.2 Option D
1.3 Option D
1.3.1 Option B
1.3.2 Option C
2. Option B
2.1 Option A
2.1.1 Option C
2.1.2 Option D
2.2 Option C
2.2.1 Option A
2.2.2 Option D
2.3 Option D
2.3.1 Option A
2.3.2 Option C
3. Option C
3.1 Option A
3.1.1 Option B
3.1.2 Option D
3.2 Option B
3.2.1 Option A
3.2.2 Option D
1.3 Option D
3.3.1 Option A
3.3.2 Option B
4. Option D
4.1 Option A
4.1.1 Option B
4.1.2 Option C
4.2 Option B
4.2.1 Option A
4.2.2 Option C
4.3 Option C
4.3.1 Option A
4.3.2 Option B
我为什么要这样做? - 此菜单用于 select 选项组合 A,B,C,D
,其中 selected 选项的顺序很重要。
例如:用户点击菜单项 2.3.1。结果组合 B-D-A
.
现在,你知道我目前在理论上是怎么做的了。实际上,有更多的选择可以组合。但是只能同时组合三个。
问题是我必须在显示菜单之前创建所有菜单项(三层深)。
有没有办法在需要时(即应该显示的时候)添加子菜单项?
有点复杂,因为 Delphi 在 PopupMenu 中没有这方面的事件。我的想法是,也许可以通过以下方式完成:
首先,检查自定义弹出菜单,例如 TMS' one。有了这个,您可以防止用户单击弹出窗口时自动关闭它。之后,您可以捕获该事件并动态添加您想要的子菜单。但是我不知道它会立即显示它,还是Popup应该关闭并重新打开。
你可以尝试用标准弹出来实现同样的效果,你可以找到如何防止关闭here。
您可以添加一个虚拟项目作为子菜单的占位符,然后使用 OnClick
具有虚拟项目的项目的事件处理程序将其替换为真实项目。
以下仅供演示,不用于生产代码。它重复了问题中的示例。
procedure TForm1.PopupMenu1Popup(Sender: TObject);
var
NewItem: TMenuItem;
i: Integer;
begin
PopupMenu1.Items.Clear;
for i := 0 to 3 do begin
NewItem := TMenuItem.Create(PopupMenu1);
NewItem.Caption := Format('%d. Option %s', [i + 1, Chr(i + 65)]);
NewItem.OnClick := ItemClick;
NewItem.Tag := i;
NewItem.Add(TMenuItem.Create(NewItem));
PopupMenu1.Items.Add(NewItem);
end;
end;
procedure TForm1.ItemClick(Sender: TObject);
var
Root: TMenuItem;
function ItemLevel(Item: TMenuItem): Integer;
begin
Result := 0;
while Item.Parent <> Root do begin
Item := Item.Parent;
Inc(Result);
end;
end;
function ExistsInTree(Item: TMenuItem; Option: Integer): Boolean;
begin
Result := Option = Item.Tag;
if not Result then
while Item.Parent <> Root do begin
Item := Item.Parent;
Result := Option = Item.Tag;
if Result then
Break;
end;
end;
function LevelString(Item: TMenuItem): string;
begin
Result := '';
while Item.Parent <> Root do begin
Item := Item.Parent;
Result := IntToStr(Item.MenuIndex + 1) + '.' + Result;
end;
end;
var
Item, NewItem: TMenuItem;
i: Integer;
path: string;
begin
Item := Sender as TMenuItem;
Root := PopupMenu1.Items;
if ItemLevel(Item) < 2 then begin
if Item.Count = 1 then begin
for i := 0 to 3 do begin
if ExistsInTree(Item, i) then
Continue;
NewItem := TMenuItem.Create(Item);
NewItem.OnClick := ItemClick;
NewItem.Tag := i;
Item.Add(NewItem);
NewItem.Caption := Format('%s%d. Option %s',
[LevelString(NewItem), Item.Count - 1, Chr(i + 65)]);
if ItemLevel(NewItem) < 2 then
NewItem.Add(TMenuItem.Create(NewItem));
end;
Item.Delete(0);
end;
end else begin
path := Chr(Item.Tag + 65);
while Item.Parent <> Root do begin
Item := Item.Parent;
path := Chr(Item.Tag + 65) + '-' + path;
end;
ShowMessage(path);
end;
end;
我有一个这样的菜单结构:
1. Option A
1.1 Option B
1.1.1 Option C
1.1.2 Option D
1.2 Option C
1.2.1 Option B
1.2.2 Option D
1.3 Option D
1.3.1 Option B
1.3.2 Option C
2. Option B
2.1 Option A
2.1.1 Option C
2.1.2 Option D
2.2 Option C
2.2.1 Option A
2.2.2 Option D
2.3 Option D
2.3.1 Option A
2.3.2 Option C
3. Option C
3.1 Option A
3.1.1 Option B
3.1.2 Option D
3.2 Option B
3.2.1 Option A
3.2.2 Option D
1.3 Option D
3.3.1 Option A
3.3.2 Option B
4. Option D
4.1 Option A
4.1.1 Option B
4.1.2 Option C
4.2 Option B
4.2.1 Option A
4.2.2 Option C
4.3 Option C
4.3.1 Option A
4.3.2 Option B
我为什么要这样做? - 此菜单用于 select 选项组合 A,B,C,D
,其中 selected 选项的顺序很重要。
例如:用户点击菜单项 2.3.1。结果组合 B-D-A
.
现在,你知道我目前在理论上是怎么做的了。实际上,有更多的选择可以组合。但是只能同时组合三个。
问题是我必须在显示菜单之前创建所有菜单项(三层深)。
有没有办法在需要时(即应该显示的时候)添加子菜单项?
有点复杂,因为 Delphi 在 PopupMenu 中没有这方面的事件。我的想法是,也许可以通过以下方式完成:
首先,检查自定义弹出菜单,例如 TMS' one。有了这个,您可以防止用户单击弹出窗口时自动关闭它。之后,您可以捕获该事件并动态添加您想要的子菜单。但是我不知道它会立即显示它,还是Popup应该关闭并重新打开。
你可以尝试用标准弹出来实现同样的效果,你可以找到如何防止关闭here。
您可以添加一个虚拟项目作为子菜单的占位符,然后使用 OnClick
具有虚拟项目的项目的事件处理程序将其替换为真实项目。
以下仅供演示,不用于生产代码。它重复了问题中的示例。
procedure TForm1.PopupMenu1Popup(Sender: TObject);
var
NewItem: TMenuItem;
i: Integer;
begin
PopupMenu1.Items.Clear;
for i := 0 to 3 do begin
NewItem := TMenuItem.Create(PopupMenu1);
NewItem.Caption := Format('%d. Option %s', [i + 1, Chr(i + 65)]);
NewItem.OnClick := ItemClick;
NewItem.Tag := i;
NewItem.Add(TMenuItem.Create(NewItem));
PopupMenu1.Items.Add(NewItem);
end;
end;
procedure TForm1.ItemClick(Sender: TObject);
var
Root: TMenuItem;
function ItemLevel(Item: TMenuItem): Integer;
begin
Result := 0;
while Item.Parent <> Root do begin
Item := Item.Parent;
Inc(Result);
end;
end;
function ExistsInTree(Item: TMenuItem; Option: Integer): Boolean;
begin
Result := Option = Item.Tag;
if not Result then
while Item.Parent <> Root do begin
Item := Item.Parent;
Result := Option = Item.Tag;
if Result then
Break;
end;
end;
function LevelString(Item: TMenuItem): string;
begin
Result := '';
while Item.Parent <> Root do begin
Item := Item.Parent;
Result := IntToStr(Item.MenuIndex + 1) + '.' + Result;
end;
end;
var
Item, NewItem: TMenuItem;
i: Integer;
path: string;
begin
Item := Sender as TMenuItem;
Root := PopupMenu1.Items;
if ItemLevel(Item) < 2 then begin
if Item.Count = 1 then begin
for i := 0 to 3 do begin
if ExistsInTree(Item, i) then
Continue;
NewItem := TMenuItem.Create(Item);
NewItem.OnClick := ItemClick;
NewItem.Tag := i;
Item.Add(NewItem);
NewItem.Caption := Format('%s%d. Option %s',
[LevelString(NewItem), Item.Count - 1, Chr(i + 65)]);
if ItemLevel(NewItem) < 2 then
NewItem.Add(TMenuItem.Create(NewItem));
end;
Item.Delete(0);
end;
end else begin
path := Chr(Item.Tag + 65);
while Item.Parent <> Root do begin
Item := Item.Parent;
path := Chr(Item.Tag + 65) + '-' + path;
end;
ShowMessage(path);
end;
end;