在将一个TMenuItem实例分配给另一个TMenuItem实例时出现EConvertError异常

4

在我的一个应用程序中,下拉菜单和弹出菜单共享一些菜单项(这些菜单项是动态构建的),因此我认为可以使用以下代码将TMenuItem实例添加到两个菜单中:

MI := TMenuItem.Create(nil);
{ set MI action }
DropDownMenu.Add(MI);
PopupMenu.Items.Add(MI);

错误。我遇到了一个带有消息“菜单二次插入”的EMenuError。这是合理的,所以我更改了我的代码,使用以下代码来创建两个菜单项实例:

MI := TMenuItem.Create(nil);
{ set MI action }
PopupMenu.CreateMenuItem.Assign(MI);
DropDownMenu.Add(MI);

再次错误。我收到一个EConvertError,并显示此消息:无法将TMenuItem分配给TMenuItem。 我做错了什么吗?


2
您可以在多个菜单中使用一个常见的 TAction - Andreas Rejbrand
1
你只能通过 TMenuItem.Assign 分配 TCustomAction 的后代类,你可以在 TMenuItem.AssignTo 重写方法中进行验证。 - TLama
1
@TLama,我原本以为Assign()是用来从另一个TPersistant派生类中复制所有属性的。这个假设是错误的吗? - iMan Biglari
1
iMan:是的。Assign方法并不是魔法,它们是手动实现的,针对最重要的情况。 - Andreas Rejbrand
1
@iManBiglari 我不认为所有TPersistent的子类都需要实现Assign方法。无论如何,你现在知道该做什么了。 - David Heffernan
显示剩余3条评论
1个回答

6
这是一个常见的错误消息。在Delphi中,大多数视觉组件都没有重写TPersistent.Assign。当该方法未被重写时,默认实现会接管,它只是抛出一个异常并填充源对象和目标对象的类名。我认为之所以没有实现它是因为不清楚应该复制哪些属性,所以这个决定留给你作为程序员来做。
如果您使用的是这些类的后代,您可以实现AssignAssignTo以复制您想要的所有属性,但这可能不值得努力。相反,最简单的方法可能是编写一个执行复制的函数:
procedure AssignMenuItem(Target, Source: TMenuItem);

对于菜单和按钮,最好的解决方案是使用 TAction。将动作的标题、图标、帮助 ID 和事件处理程序分配给它,然后将该动作与需要具有相同行为的所有按钮和菜单项相关联。它们都可以共享同一个动作。在运行时更改动作的属性将自动反映在关联的可视控件中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接