[Résolu] IBOutlet: Le menu de mon StatusItem ne s'affiche pas

sisopetronsisopetron Membre
décembre 2009 modifié dans API AppKit #1
Bonjour à  tous,

Je continue l'exploration de cocoa et je suis confronté à  un problème que je n'arrive pas à  résoudre seul.  C'est encore surement une bêtise mais voilà  ...

J'arrive à  afficher une icône dans la StatusBar.  Par contre je n'arrive pas à  binder le menu que j'ai créé à  cette icône.  Je vous laisse mon code pour que vous puissiez trouver où ça coince :

StatusIcon.h :

@interface StatusIcon : NSObject {<br />	<br />	IBOutlet NSMenu *statusMenu;<br />	<br />	NSStatusItem *statusItem;<br /><br />	NSImage *statusImage;<br />	NSImage *statusAltImage;<br /><br />}<br /><br />- (void)afficheIcone;<br /><br />@end<br />


StatusIcon.m :

@implementation StatusIcon<br /><br />- (void)afficheIcone<br />{<br />	// création d&#39;un statusItem de longueur NSSquareStatusItemLength, constante définie par NSStatusBar<br />	statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];<br /><br />	// on détecte où se trouvent les fichiers de l&#39;application<br />	NSBundle *bundle = [NSBundle mainBundle];<br />	statusImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource: @&quot;anniv_status&quot; ofType: @&quot;png&quot;]];<br />	statusAltImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource: @&quot;anniv_status_alt&quot; ofType: @&quot;png&quot;]];<br />	[statusItem setImage: statusImage];<br />	[statusItem setAlternateImage: statusAltImage];<br />	<br />	[statusItem setHighlightMode: YES];<br />	[statusItem setMenu: statusMenu];<br />	[statusItem setToolTip: @&quot;anniversaires&quot;];<br />	[statusItem setEnabled: YES];<br />}<br /><br />- (void)dealloc<br />{<br />	[[NSStatusBar systemStatusBar] removeStatusItem:statusItem];<br />	[statusItem release];<br />	[statusImage release];<br />	[statusAltImage release];<br />	[super dealloc];<br />}<br /><br /><br />@end<br />


AppController.h :

#import &lt;Cocoa/Cocoa.h&gt;<br />@class StatusIcon;<br />@class SplashScreen;<br /><br />@interface AppController : NSObject {<br />	<br />	StatusIcon *myStatusIcon;<br />	SplashScreen *mySplashScreen;<br />	<br />}<br />@end


AppController.m (une partie en tout cas ) :

#import &quot;AppController.h&quot;<br />#import &quot;StatusIcon.h&quot;<br />#import &quot;SplashScreen.h&quot;<br /><br /><br />@implementation AppController<br /><br />- (id)init<br />{<br />	if(self = [super init]){		<br />		//Ici le code pour initialiser l&#39;objet !					<br />	}<br />	return self;<br />}<br />			<br />- (void)awakeFromNib<br />{<br />	// affichage du SplashScreen<br />	mySplashScreen = [[SplashScreen alloc] init];<br />	[mySplashScreen afficheSplashScreen];<br />	<br />	// affichage de l&#39;icône de la statusbar<br />	myStatusIcon = [[StatusIcon alloc] init];<br />	[myStatusIcon afficheIcone];<br />}<br />


Dans IB, j'ai relié ma classe StatusIcon au menu via son outlet statusMenu.

Pourquoi le menu ne s'affiche-t-il pas ?  Ou est mon erreur ?

Merci de me donner un coup de main.

tata !

Réponses

  • ClicCoolClicCool Membre
    21:31 modifié #2
    A première vue je dirais que le MVC paradygm me semble un peu malmené dans ton projet.
    Et ça crée un fouilli dans lequel on (tu) se perd.

    Si j'ai bien compris il y a une instance de StatusIcon dans le nib, dont l'outlet est bien connecté au menu.

    Mais alors pourquoi le controlleur instancie-t-il une autre instance de StatusIcon ?
    Cette instance là  n'est pas dans le nib et son outlet vers le menu n'est pas connecté.
  • sisopetronsisopetron Membre
    21:31 modifié #3
    En fait, j'ai créé une classe StatusIcon.  Dans mon AppController j'instancie une instance de cette classe.

    Evidemment, dans le NIB c'est la classe mère (si j'ose dire) qui apparait et à  laquelle est relié le menu. 

    Ce n'est pas ainsi que je dois procéder ?
  • ClicCoolClicCool Membre
    décembre 2009 modifié #4
    Non.

    Si un reste au plus près de ta conception:

    • Soit ton controller a un outlet sur l'instance (et pas la classe) de StatusIcon du nib et utilise alors cette instance pour configurer ton statusMenu.


    • Soit le controlleur a un outlet sur le menu et s'en sert pour instancier et configurer le StatusIcon avec lequel il configure ton statusMenu

  • sisopetronsisopetron Membre
    21:31 modifié #5
    Je ne comprends pas : comment dans IB faire pointer (lier) mon menu avec une instance ?  N'y apparait que les classes pas les instances.  Et pourquoi est-ce le controleur qui doit avoir un outlet pointant sur le menu et pas ma classe StatusIcon ?  Quelque chose m'échappe là .

    Merci de m'aider.
  • ClicCoolClicCool Membre
    décembre 2009 modifié #6
    En fait, je me rend compte que tu n'as pas une vision claire de ce que sont les objects dans un XIB.

    Penses aux NSWindows qu'y s'y trouvent souvent par exemple.
    Tu les y configures en taille, type, contenu divers que tu agences au mieux possible etc..
    Bref en y réfléchissant, tu vois bien que ce que tu configures dans ton XIB c'est pas La Classe NSWindow, mais Une Instance toute particulière avec des réglages pré-établis par tes soins dans le XIB.
    Et, même si c'est, par exemple, un MyDocument.Xib, donc que, dans ce cas, plusieurs fenêtres jumelles peuvent être affichées dans ton appli, n'oublies pas qu'alors chaque fois (chaque document ici) le XIB est chargé en mémoire et instancie ta fenêtre selon tes choix.

    Quand tu crée un objet perso dans un XIB (le petit cube bleu comme pour les WC ;) ) il en est de même.
    Tu donnes à  IB le nom de la classe que tu dois instancier.
    Au chargement du XIB l'instance de ta classe est crée, ET ses outlets connectés.

    Du reste les outlets ne sont pas des variables de classe mais bien des variables d'instance.
    Sinon tu parles d'un bordel si toutes les fenêtres (donc toutes les instances de NSWindow partageant l'unique 'outlet de classe') d'une appli devaient partager le même outlets "delegate" etc ...  ;D
  • ClicCoolClicCool Membre
    21:31 modifié #7
    Au fait, record battu ALi !!  :kicking:

    Une réponse de 14 lignes en 23 secondes !  :brule:
  • sisopetronsisopetron Membre
    21:31 modifié #8
    dans 1259693644:
    Du reste les outlets ne sont pas des variables de classe mais bien des variables d'instance.
    Sinon tu parles d'un bordel si toutes les fenêtres (donc toutes les instances de NSWindow partageant l'unique 'outlet de classe') d'une appli devaient partager le même outlets "delegate" etc ...  ;D


    Oui, je n'avais pas pensé à  ça.

    dans 1259693644:
    Quand tu crée un objet perso dans un XIB (le petit cube bleu comme pour les WC ;) ) il en est de même.
    Tu donnes à  IB le nom de la classe que tu dois instancier.
    Au chargement du XIB l'instance de ta classe est crée, ET ses outlets connectés


    Mais il me semble bien avoir fait ça : l'outlet de mon menu (IBOutlet NSMenu *statusMenu;) est déclaré dans la classe StatusIcon et relié à  ma classe StatusIcon de façon à  ce que chaque instance de ma classe StatusIcon possède un menu.

    Or ce menu ne s'affiche pas.  Pratiquement au vu du code que j'ai édité plus haut, où se trouve l'erreur ?  J'ai remarqué que si je ne crée pas de classe StatusIcon mais que j'écris simplement dans AppController.m  une méthode pour afficher mon icone (le même code que dans le StatusIcon.m), que je crée un outlet statusmenu dans le même AppController et que je relie dans IB mon menu et mon Outlet, le menu s'affiche bien quand je clique sur l'icone.  Or je ne fais rien de bien différent que quand je crée ma classe StatusIcon. 

    Bref, tu l'auras remarqué, il y a encore quelque chose qui m'échappe dans tout cela.
  • ClicCoolClicCool Membre
    21:31 modifié #9
    dans 1259696950:
    dans 1259693644:
    .../...Quand tu crée un objet perso dans un XIB (le petit cube bleu comme pour les WC ;) ) il en est de même.
    Tu donnes à  IB le nom de la classe que tu dois instancier.
    Au chargement du XIB l'instance de ta classe est crée, ET ses outlets connectés


    Mais il me semble bien avoir fait ça : l'outlet de mon menu (IBOutlet NSMenu *statusMenu;) est déclaré dans la classe StatusIcon et relié à  ma classe StatusIcon de façon à  ce que chaque instance de ma classe StatusIcon possède un menu.


    L'outlet est une variable d'instance, il n'est pas "relié" magiquement à  la classe.
    Chaque instance de ta classe StatusIcon possède un outlet nommé statusMenu.
    Mais seule l'instance du XIB (crée lors du chargement du XIB) verra son outlet pointer vers la bonne instance de NSMenu telle que t'en a spécifié les caractéristiques.

    Et encore quand je dis pointer il faut préciser que ces "liens" qu'on trace sous IB entre un outlet et "sa cible" ne sont qu'une façon de dire ici au XIB "quand tu te chargera en mémoire et que tu aura instancié mon objet (cube bleu) de la classe StatusIcon et tous les autres objets du XIB (dont le NSMenu) tu donnera à  l'outlet statusMenu de l'instance crée de StatusIcon la valeur de l'adresse mémoire de l'instance que tu viens de créer de la classe NSMenu."

    Bref, tel que tu l'as fait, seule l'instance (de ta classe StatusIcon) crée "dans" le XIB a un outlet valide pointant vers le menu.
    A partir de là  c'est de cette instance StatusIcon là  et pas une autre qu'il faut utiliser par la suite.
    Or ton controlleur ne possède aucune référence vers cette instance.
    Donc (première solution simple) tu crées dans ton controlleur un IBOutlet pointant sur ton cube bleu StatusIcon et le controlleur l'utilise pour configuer le statusMenu.

    Alors que dans le code que tu donnes ton controlleur instancie "un autre exemplaire" de StatusIcon dont l'outlet reste non initialisé par le XIB et pour cause c'est pas le XIB qui l'a crée.

    C'est plus clair ?

    En attendant je vais m'instancier un bon verre de cocoa que je ferai pointer vers mon instance de bouche à  moi (et pas celle de ma belle mère !)
    (toutes les instances de verres de coca ont un outlet prévu pour pointer vers une bouche, mais ceux que j'instancie dans ma cuisine ne pointent jamais sur la bouche de ma belle mère  ;D )
  • AliGatorAliGator Membre, Modérateur
    21:31 modifié #10
    dans 1259694935:

    Au fait, record battu ALi !!  :kicking:

    Une réponse de 14 lignes en 23 secondes !  :brule:
    :o ??? B)
    Mouais... en même temps t'as mis plus de 2h pour faire la suivante, alors bon...  ;D
  • sisopetronsisopetron Membre
    21:31 modifié #11
    dans 1259705576:
    Donc (première solution simple) tu crées dans ton controlleur un IBOutlet pointant sur ton cube bleu StatusIcon et le controlleur l'utilise pour configuer le statusMenu.


    Eh bien voilà  !  Ca marche parfaitement grâce à  toi et à  tes explications limpides.

    Un grand merci !
  • ClicCoolClicCool Membre
    21:31 modifié #12
    :p A la tienne alors !  :p
Connectez-vous ou Inscrivez-vous pour répondre.