2010-02-09 10 views
2
  1. Je certains sous-menu inséré comme sous-menu de l'élément de fenêtre du menu principal
  2. J'ai une instance de mon objet (supposons que son nom de classe est MenuController) hérité de NSObject et supporte deux procédés de NSMenuDelegate: - numberOfItemsInMenu: - Menu: updateItem: atIndex: shouldCancel:
  3. Cet exemple ajouté en tant Blue-objet dans NIB de réveil lors de l'exécution
  4. objet à partir des étapes 2-3 configurées comme délégué pour le sous-menu (étape 1)

Maintenant, je peux fournir le contenu du sous-menu en cours d'exécution.force NSMenu (sous-menu imbriqué) mise à jour du menu principal de l'App Cocoa

Ensuite, je fais ce qui suit: Je peux ajouter de nouveaux éléments ou supprimer les anciens d'un tableau (à l'intérieur de MenuController qui contient des titres de menus) qui sont mappés au sous-menu réel via protocole et délégué. Tout fonctionne très bien. Sauf une chose: j'aime attribuer des raccourcis à mes éléments de menu dynamiques. CMD-1, CMD-2, CMD-3, etc

Fenêtre/MySubmenu/MyItem1 CMD-1, MyItem2 CMD-2, ...

Donc, pour appeler certains articles que je ne veux pas aller à la fenêtre/MySubmenu/MyItem pour cliquer dessus avec la souris, je veux appuyer sur un seul raccourci, comme CMD-3 pour appeler l'élément.

Ok, périodiquement cela fonctionne comme prévu. Mais, généralement, je n'ai aucun moyen d'informer le menu principal sur mes changements de sous-menu imbriqués, sauf ouvrir le menu Window/MySub pour recharger son contenu. Une manière stable de reproduire le problème - juste essayer de supprimer un élément et appuyez sur son ancien raccourci affecté, après avoir créé un nouvel élément comme remplacer pour supprimé - bingo - raccourci ne fonctionnera pas avant de naviguer dans le menu Fenêtre/MySub pour voir le sous-menu actuel contenu.

Je ne sais pas un moyen de forcer le menu principal pour reconstruire ses sous-menus ... Je essayé: [[NSApp mainMenu] mise à jour] et les jeux avec NSNotificationCenter pour envoyer NSMenuDidAddItemNotification, NSMenuDidRemoveItemNotification, NSMenuDidChangeItemNotification

J'ai essayé sortie à mon sous-menu et appel à mettre à jour la méthode explicitement - il n'y a aucun moyen ... Parfois, AppKit appelle mes méthodes de délégué - et je vois cela, parfois il ne veut rien appeler. On dirait une stratégie aléatoire.

Comment puis-je m'assurer que, après "certains appels", mon sous-menu sera dans l'état actuel après des modifications internes de la matrice?

Répondre

4

Pour mettre en œuvre mappage 1: 1, la mise en œuvre déléguer ces 3 méthodes:

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

et

- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu 

et

- (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]; 
} 

attachedMenu - est var interne de type NSMenu *

Ensuite, lorsque vous forcez voulez rafraîchir le sous-menu, en tout temps - il suffit d'appeler

[self menuNeedsUpdate:nil]; 
+0

pour empêcher le deadloop avec la mémoire mangeant (si aucun menu n'a été initialisé encore la première fois avec l'appel nul) - dans le menuNeedsUpdate a eu besoin d'une condition additionnelle: si (! Menu) return;/* avant le compte = ... * / – UncleMiF

3

J'ai essayé: [[NSApp mainMenu] mise à jour] ...

Vous êtes sur la bonne voie. Cela peut être la seule situation dans laquelle un tableau parallèle dans une application Cocoa est justifiée. Conservez un tableau mutable d'éléments de menu, parallèle à votre tableau d'objets de modèle que les éléments de menu représentent.

  • Lorsque vous recevez numberOfItemsInMenu:, comparez le nombre d'objets de modèle dont vous disposez au nombre du tableau d'éléments de menu. Si c'est moins, utilisez the removeObjectsInRange: method pour raccourcir le tableau des éléments de menu. Si c'est plus, pad le tableau avec NSNull objets.(Vous ne pouvez pas utiliser nil ici, car un NSArray ne peut contenir que des objets et nil est l'absence d'un objet.)
  • Lorsque vous recevez menu:updateItem:atIndex:shouldCancel:, replace the object in the array at that index avec le nouvel élément de menu avant de retourner le nouvel élément de menu.
  • Conforme au protocole NSMenuValidation, comme indiqué dans the documentation for the update method. Dans votre méthode de validation, find the index of the menu item within the array, récupérez l'objet modèle à cet index dans le tableau d'objets du modèle et mettez à jour l'élément de menu. Si vous êtes sur Snow Leopard, vous pouvez envoyer au menu de l'élément de menu un propertiesToUpdate message pour déterminer les valeurs de propriété que vous devez attribuer à l'objet de modèle. L'inconvénient est que cet objet, le délégué du menu, doit également être la cible des éléments de menu. Je suppose que c'est. Si ce n'est pas le cas, cela échouera à l'étape n ° 4, car les messages de validation sont envoyés aux cibles des éléments de menu. Vous voudrez peut-être file an enhancement request demander un meilleur moyen.

  • +0

    Merci Peter. Cependant, j'ai cherché la méthode pour mapper ma matrice 1: 1 au menu (pas inverse). J'ai trouvé une solution - quelque chose comme vous l'avez dit. – UncleMiF

    0

    Dans l'appel de délégué pour numberOfItemsInMenu: appel removeAllItems ... il est tout à fait étrange, mais sinon le menu ne met pas à jour, même qu'il appelle pour un délégué

    - (NSInteger)numberOfItemsInMenu:(NSMenu*)menu { 
    
        [menu removeAllItems]; 
    
        return [self.templateURLs count] + 2; 
    
    }