2010-11-08 9 views
1

Bon, cette question devient de plus en plus complexe, donc je vais la rayer complètement et recommencer. J'ai réussi à créer une application Cocoa très basique qui démontre mon problème.Modifier le titre des éléments de menu d'état alors que le menu d'état est ouvert provoque des plantages dans mon application Cocoa

Alors, voici le problème:

A l'intérieur d'un fil, je mise le titre d'un élément de menu dans le menu de la barre d'état de ma demande. Lorsque l'application tente de modifier le titre de l'élément de menu et que le menu est ouvert, la plupart du temps, cela fonctionne, mais il bloque parfois l'application.

Voici le code complet de l'exemple d'application:

MenubarFailAppDelegate.h

#import <Cocoa/Cocoa.h> 

@interface MenubarFailAppDelegate : NSObject <NSApplicationDelegate> { 
    IBOutlet NSMenu *statusMenu; 
    NSStatusItem *statusItem; 
    IBOutlet NSMenuItem *menuItem; 

    int currentDelay; 
} 

@end 

MenubarFailAppDelegate.m

#import "MenubarFailAppDelegate.h" 

@implementation MenubarFailAppDelegate 

- (id)init { 

    self = [super init]; 

    if (self != nil) 
    { 
     currentDelay = 0; 
    } 

    return self;  

} 

- (void)awakeFromNib { 

    // Create status menu item 
    statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain]; 
    [statusItem setMenu:statusMenu]; 
    [statusItem setTitle:@"Fail"]; 
    [statusItem setHighlightMode:YES]; 

    currentDelay = 3; 
    [NSThread detachNewThreadSelector:@selector(changeStatusItemTitleLoopThread) 
          toTarget:self 
          withObject:nil]; 

} 

- (void)changeStatusItemTitleLoopThread { 

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    while (currentDelay > 0) { 
     // Sleep for one second 
     NSDate *future = [NSDate dateWithTimeIntervalSinceNow:1]; 
     [NSThread sleepUntilDate:future]; 

     // Decrement current delay 
     currentDelay--; 
    } 

    NSLog(@"Setting menu item title"); 
    [menuItem setTitle:@"lol cat"]; 

    [pool release]; 

} 

@end 

Et voici le rapport de l'accident qui apparaît lorsque le programme se bloque après la connexion " Réglage du titre de l'élément de menu ":

#0 0x7fff870f74c0 in HIStandardMenuView::FetchItemCache 
#1 0x7fff870f6345 in HIStandardMenuView::GetOptimalSizeSelf 
#2 0x7fff870f612b in HIView::GetOptimalSizeWithLimitsSelf 
#3 0x7fff870f5fb5 in HIView::SendGetOptimalBounds 
#4 0x7fff870f5edb in HIView::GetOptimalSize 
#5 0x7fff870f5dc1 in HandleCalculateMenuSize 
#6 0x7fff8709b600 in MenuData::EventHandler 
#7 0x7fff87093997 in DispatchEventToHandlers 
#8 0x7fff87092ee6 in SendEventToEventTargetInternal 
#9 0x7fff87092d57 in SendEventToEventTargetWithOptions 
#10 0x7fff870f5b7a in _CalcMenuSizeOnDevice 
#11 0x7fff8710811c in RecalcAndResizeMenu 
#12 0x7fff8720efa6 in ResizeMenuArray 
#13 0x7fff8720eff6 in ResizeOpenMenus 
#14 0x7fff87093997 in DispatchEventToHandlers 
#15 0x7fff87092ee6 in SendEventToEventTargetInternal 
#16 0x7fff87092d57 in SendEventToEventTargetWithOptions 
#17 0x7fff870c012a in ToolboxEventDispatcherHandler 
#18 0x7fff87093d91 in DispatchEventToHandlers 
#19 0x7fff87092ee6 in SendEventToEventTargetInternal 
#20 0x7fff870b0ba9 in SendEventToEventTarget 
#21 0x7fff870bdeed in AcquireEventFromQueue 
#22 0x7fff870ba737 in ReceiveNextEventCommon 
#23 0x7fff87104db8 in IsUserStillTracking 
#24 0x7fff870f1a48 in TrackMenuCommon 
#25 0x7fff87215ac9 in PopUpMenuSelectCore 
#26 0x7fff87215dce in _HandlePopUpMenuSelection7 
#27 0x7fff864d71c9 in _NSSLMPopUpCarbonMenu3 
#28 0x7fff86706e71 in -[NSStatusBarButtonCell trackMouse:inRect:ofView:untilMouseUp:] 
#29 0x7fff8640a4b5 in -[NSControl mouseDown:] 
#30 0x7fff86324763 in -[NSWindow sendEvent:] 
#31 0x7fff86707c10 in -[NSStatusBarWindow sendEvent:] 
#32 0x7fff86259ee2 in -[NSApplication sendEvent:] 
#33 0x7fff861f0922 in -[NSApplication run] 
#34 0x7fff861e95f8 in NSApplicationMain 
#35 0x100001499 in main at main.m:13 
+0

Veuillez modifier votre question pour inclure le rapport d'erreur. En outre, 'rConnectionButton' est-il réellement un NSButton? (Cela ne causera pas de plantage, mais il y aura confusion si un point de sortie est tapé comme contenant un pointeur vers un objet NSMenuItem contenant un pointeur sur un bouton NSButton.) –

+0

@Peter: J'ai modifié la question. Et pour répondre à votre question, 'rConnectionButton' est en fait un' NSMenuItem', et non un 'NSButton'. – Chetan

+0

Est-ce cela? On dirait qu'il devrait y avoir plus de cadres de pile après # 17. –

Répondre

5

La modification de l'interface utilisateur dans le code threadé n'est généralement pas recommandée. Y at-il une raison impérieuse pour laquelle vous devez changer les titres de menu dans un fil? Je recommande de renvoyer la modification réelle au thread principal. Vous pouvez faire n'importe quel calcul dont vous avez besoin dans le thread d'arrière-plan et utiliser performSelectorOnMainThread pour effectuer le changement réel du titre.

+0

Wow, vraiment? Je ne le savais pas. Votre solution fonctionne! Merci beaucoup! En passant, y a-t-il un endroit officiel qui dit que faire du code UI est généralement déconseillé? Je suis juste curieux de savoir comment j'ai raté ça. – Chetan

+2

Je ne l'avais pas vu dans aucun document Apple que je me souvienne, mais je l'ai vu sur un certain nombre de blogs. J'ai jeté un coup d'oeil, et il s'est avéré qu'il y a une très courte discussion de la question dans le Guide de programmation Threading. http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/AboutThreads/AboutThreads.html#//apple_ref/doc/uid/10000057i-CH6-SW21 –

+0

Je pense qu'il est mentionné dans certains des matériel d'introduction AppKit. Je ne peux pas regarder le moment, car je suis au travail sur IE6. :( – paulbailey