2
  1. 我插入了一些子菜单作为主菜单的窗口项子菜单
  2. 我有一个我的对象的实例(假设它的类名是 MenuController)从 NSObject 继承并支持来自 NSMenuDelegate 方法的 2:-numberOfItemsInMenu:--menu:updateItem:atIndex:shouldCancel:
  3. 此实例作为蓝色对象添加到 NIB 中以在运行时唤醒
  4. 步骤 2-3 中的对象配置为子菜单的委托(步骤 1)

现在,我可以在运行时提供子菜单内容。

接下来,我执行以下操作:我可以添加新项目或从通过协议和委托映射到实际子菜单的数组(在包含菜单标题的 MenuController 内)中删除旧项目。一切正常。除了一件事:我喜欢为我的动态菜单项分配快捷方式。CMD-1、CMD-2、CMD-3 等

窗口/我的子菜单/我的项目1 CMD-1,我的项目2 CMD-2,...

所以,为了调用一些我不想去 Window / MySubmenu / MyItem 用鼠标单击它的项目,我只想按一个快捷方式,比如 CMD-3 来调用该项目。

好的,它会定期按预期工作。但是,一般来说,除了打开 Window / MySubmenu 重新加载其内容外,我无法通知 Main Menu 我的嵌套子菜单更改。重现问题的一种稳定方法 - 只需尝试删除某些项目并按下分配给它的旧快捷方式,在您创建新项目作为已删除的替换后 - 宾果游戏 - 在导航到 Window / MySubmenu 以查看当前子菜单内容之前快捷方式将不起作用.

我不知道强制主菜单重建其子菜单的方法...我尝试过:[[NSApp mainMenu] update] 和使用 NSNotificationCenter 发送 NSMenuDidAddItemNotification、NSMenuDidRemoveItemNotification、NSMenuDidChangeItemNotification 的游戏

我尝试到我的子菜单并显式调用更新方法 - 没有办法......有时 AppKit 调用我的委托方法 - 我看到了,有时它不想调用任何东西。看起来像一个随机策略。

如何确保在“某些调用”之后我的子菜单在内部数组修改后处于实际状态?

4

3 回答 3

5

要实现 1:1 映射,请在委托中实现以下 3 个方法:

- (BOOL)menu:(NSMenu *)menu
updateItem:(NSMenuItem *)item 
atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel

- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu

- (void)menuNeedsUpdate:(NSMenu *)menu
{
    if (!attachedMenu)
        attachedMenu = menu;
    if (!menu)
        menu = attachedMenu;
    NSInteger count = [self numberOfItemsInMenu:menu];
    while ([menu numberOfItems] < count)
        [menu insertItem:[[NSMenuItem new] autorelease] atIndex:0];
    while ([menu numberOfItems] > count)
        [menu removeItemAtIndex:0];
    for (NSInteger index = 0; index < count; index++)
        [self menu:menu updateItem:[menu itemAtIndex:index] atIndex:index shouldCancel:NO];
}

attachMenu - 是 NSMenu* 类型的内部变量

接下来,当您想强制刷新子菜单时,随时 - 只需调用

[self menuNeedsUpdate:nil];
于 2010-02-10T12:30:37.407 回答
3

我试过了:[[NSApp mainMenu] update] ...</p>

你在正确的轨道上。这可能是 Cocoa 应用程序中需要使用并行数组的一种情况。

  1. 保持一个可变的菜单项数组,与菜单项表示的模型对象数组平行。
  2. 当您收到 时numberOfItemsInMenu:,将您拥有的模型对象的数量与 menu-items 数组的数量进行比较。如果它更少,请使用removeObjectsInRange:方法缩短 menu-items 数组。如果更多,请使用NSNull对象填充数组。(你不能nil在这里使用,因为 NSArray 只能包含对象,并且nil没有对象。)
  3. 当您收到时menu:updateItem:atIndex:shouldCancel:,在返回新菜单项之前,将该索引处的数组中的对象替换为新菜单项。
  4. 符合 NSMenuValidation 协议,如方法文档中所述update。在您的验证方法中,找到数组中菜单项的索引,然后在模型对象数组中的该索引处获取模型对象并从中更新菜单项。如果您使用的是 Snow Leopard,您可以向菜单项的菜单发送一条propertiesToUpdate消息,以确定您需要从模型对象中赋予哪些属性值。

需要注意的是,这个对象,菜单的委托,也必须是菜单项的目标。我假设它是。如果不是,这将在第 4 步失败,因为验证消息被发送到菜单项的目标。

您可能需要提交增强请求以寻求更好的方法。

于 2010-02-10T09:11:25.490 回答
0

在委托调用中numberOfItemsInMenu:......removeAllItems这很奇怪,但菜单不会更新,即使它正在调用委托

- (NSInteger)numberOfItemsInMenu:(NSMenu*)menu {

    [menu removeAllItems];

    return [self.templateURLs count] + 2;

}
于 2016-05-18T21:53:56.337 回答