gèrer le menu d'une application par programmation, sans IB

bofybofy Membre
12:48 modifié dans API AppKit #1
Je crée un project "toto" avec xcode, application cocoa standard.
Mon main.m modifié :
<br />#import &lt;Cocoa/Cocoa.h&gt;<br />int main(int argc, char *argv&#91;]) {<br />	[NSApplication sharedApplication];<br />	[NSApp run];<br />	return 0;<br />	}<br />

Tout marche parfaitement, naturellement mon appli ne fait rien :
- elle affiche un menu "toto" à  droite de la pomme
- l'icône habituelle dans la barre des tâches avec "toto"
Maintenant, je veux :
- au lieu de "toto" que ce soit "tata" qui s'affiche
- ajouter un sous-menu, avec l'item "quit"

NB :
- je sais parfaitement faire tout ce qui est proposé dans le fil "nib minimal"
de Philippe49...
- il semble qu'il y ait un "rootmenu" imposé dont la clé est introuvable pour moi
(les méthodes mainMenu, supermenu, etc. ne donnent rien)
PS :
- je comprends toujours aussi mal que ce soit aussi compliqué de trouver
comment faire par programmation ce qu'on fait avec IB (par vraiment
simplement d'ailleurs)
- l'expérience de mon insistance à  me passer de IB me montre en fait que
la programmation n'est pas si compliquée que ça, une fois qu'on a les clés

Réponses

  • NoNo Membre
    12:48 modifié #2
    dans 1212337781:

    Maintenant, je veux :
    - au lieu de "toto" que ce soit "tata" qui s'affiche

    Impossible. OSX fonctionne comme ça et ce n'est pas négociable.
    Le nom de ton menu toto provient de la clé "CFBundleName" du fichier "info.plist".

    dans 1212337781:

    - ajouter un sous-menu, avec l'item "quit"

    Le truc de créer un menu et d'insérer un item a déjà  été donné dans un autre sujet.
    Pour modifier le menu toto, t'as juste à  créer un nouveau menu avec comme nom le symbole "APPLE". Ce menu écrasera le menu toto créé automatiquement.
    Mais je le rappelle, ça va créer un nouveau menu toto avec ton propre contenu mais sans pouvoir changer son nom.
    <br />#import &lt;Cocoa/Cocoa.h&gt;<br />#import &lt;Carbon/Carbon.h&gt;<br /><br />int main(int argc, char *argv&#91;])<br />{<br />&nbsp;  NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];<br />&nbsp;  [NSApplication sharedApplication];<br /><br />&nbsp;  // creation d&#39;un menu &quot;TOTO&quot; contenant 1 seul item &quot;Quit&quot;<br />&nbsp;  NSMenu *menu_application=[[NSMenu alloc] initWithTitle:[NSString stringWithFormat:@&quot;%C&quot;, kAppleLogoUnicode]];<br />&nbsp;  NSMenuItem *item_quitter=[[NSMenuItem alloc] initWithTitle:@&quot;Quit&quot; action:@selector(terminate:) keyEquivalent:@&quot;q&quot;];<br />&nbsp;  [menu_application addItem:item_quitter];<br />&nbsp;  [item_quitter release];<br /><br />&nbsp;  // création d&#39;un item pour appel du menu &quot;TOTO&quot; et attachement du sous menu &quot;TOTO&quot; créé avant<br />&nbsp;  NSMenuItem *item_menu_application=[[NSMenuItem alloc] initWithTitle:@&quot;&quot; action:NULL keyEquivalent:@&quot;&quot;];<br />&nbsp;  [item_menu_application setSubmenu:menu_application];<br />&nbsp;  [menu_application release];<br /><br />&nbsp;  // creation d&#39;un menu qui servira de barre de menu et insertion de l&#39;item su sous menu &quot;TOTO&quot;<br />&nbsp;  NSMenu *barre_menu=[[NSMenu alloc] initWithTitle:@&quot;&quot;];<br />&nbsp;  [barre_menu addItem:item_menu_application];<br />&nbsp;  [item_menu_application release];<br /><br />&nbsp;  // mise en place de la nouvelle barre de menu<br />&nbsp;  [NSApp setMainMenu:barre_menu];<br />&nbsp;  [barre_menu release];<br /><br />&nbsp;  [NSApp run];<br />&nbsp;  [pool release];<br />&nbsp;  return 0;<br />}<br />
    


    dans 1212337781:

    - il semble qu'il y ait un "rootmenu" imposé dont la clé est introuvable pour moi
    (les méthodes mainMenu, supermenu, etc. ne donnent rien)

    Comme ça a été dit, la barre de menu d'une appli cocoa est créée via carbon.
    En cocoa, la méthode mainMenu renvoie cette barre sous forme d'un objet NSMenu. Mais mainMenu n'est valide qu'en fin d'initialisation de l'appli.
    Pour accéder à  cette barre dans les cas où mainMenu est nil, faut utiliser la fonction carbon AcquireRootMenu().
    Mais la barre de menu du point de vue application ne contient pas le menu pomme, le menu application, et les menus à  droites (spotlight, etc.).

    Il n'existe aucune méthode officielle pour toucher aux parties de la barre de menu qui ne sont pas accessibles en tant qu'appli.
    C'est comme ça, ou alors, change d'OS si ça ne convient pas.

    dans 1212337781:

    - je comprends toujours aussi mal que ce soit aussi compliqué de trouver
    comment faire par programmation ce qu'on fait avec IB (par vraiment
    simplement d'ailleurs)

    Une appli cocoa a besoin d'un mainMenu.nib.
    C'est comme ça que ça a été prévu par Apple, et c'est documenté.
    Tout le reste c'est de la bidouille, donc il faut pécher les infos.

    dans 1212337781:

    - l'expérience de mon insistance à  me passer de IB me montre en fait que
    la programmation n'est pas si compliquée que ça, une fois qu'on a les clés

    C'est bien d'avoir les clés.
    Mais faut aussi respecter la notice d'utilisation qui est avec.
    Sinon la clé tournera mal dans la serrure.
  • bofybofy Membre
    12:48 modifié #3
    dans 1212357062:

    dans 1212337781:

    Maintenant, je veux :
    - au lieu de "toto" que ce soit "tata" qui s'affiche

    Impossible. OSX fonctionne comme ça et ce n'est pas négociable.
    Le nom de ton menu toto provient de la clé "CFBundleName" du fichier "info.plist".
    Bizarre, j'ai viré "CFBundleName" du fichier "info.plist" et rien ne change. Bof !... en fait ce qui était plus important pour moi est ce qui suit.

    Pour modifier le menu toto, t'as juste à  créer un nouveau menu avec comme nom le symbole "APPLE". Ce menu écrasera le menu toto créé automatiquement.
    Mais je le rappelle, ça va créer un nouveau menu toto avec ton propre contenu mais sans pouvoir changer son nom.

    C'est très exactement ce que je cherchais. Mais il suffisait de me donner la clé :
    &nbsp;  NSMenu *menu_application=[[NSMenu alloc] initWithTitle:[NSString stringWithFormat:@&quot;%C&quot;, kAppleLogoUnicode]];
    

    Le reste je sais faire, grâce à  toi.

    Tout le reste c'est de la bidouille, donc il faut pécher les infos.
    C'est bien d'avoir les clés.
    Mais faut aussi respecter la notice d'utilisation qui est avec.
    Sinon la clé tournera mal dans la serrure.


    Un peu de polémique :
    Je pense que la programmation objet (ou dite objet) est le contraire de la bidouille. C'est même l'un des avantages vantés de ce type de programmation : une fois qu'un objet est testé et validé, en principe plus de problèmes. Par contre la programmation graphique, qui impose de reproduire les mêmes adaptations à  chaque nouvelle application, est source d'erreurs, car on ne peut ni tout mémoriser, ni tout noter à  chaque nouvel essai, en plus elle ne permet pas de comprendre ce qu'on fait.

    Pour tout un grand merci :
    Tu m'a permis de comprendre comment marchent les menus d'application (mélange de Cocoa et de Carbon) et de les construire à  ma guise (sans IB naturellement !).

  • NoNo Membre
    12:48 modifié #4
    dans 1212410106:

    Bizarre, j'ai viré "CFBundleName" du fichier "info.plist" et rien ne change. Bof !... en fait ce qui était plus important pour moi est ce qui suit.

    Si tu changes le info.plist de ton projet, il faut le recompiler totalement (par un "clean all targets" je crois).
    Ensuite, il faut simuler une install de l'appli pour forcer le launch service à  reconstruire ses caches (va dans le répertoire build de ton projet, repère l'appli, puis déplace là  via le Finder dans un autre répertoire).
    Maintenant, en l'absence de clé "CFBundleName", je ne sais pas comment le système va réagir (va t'il chercher le nom de l'appli autre part ?).

    dans 1212410106:

    Un peu de polémique :
    Je pense que la programmation objet (ou dite objet) est le contraire de la bidouille. C'est même l'un des avantages vantés de ce type de programmation : une fois qu'un objet est testé et validé, en principe plus de problèmes. Par contre la programmation graphique, qui impose de reproduire les mêmes adaptations à  chaque nouvelle application, est source d'erreurs, car on ne peut ni tout mémoriser, ni tout noter à  chaque nouvel essai, en plus elle ne permet pas de comprendre ce qu'on fait.

    Il n'y a pas de polémique.
    Même en prog objet, les problèmes que tu évoques sont possibles.
    Cocoa date de Next, or il évolue constamment. Nombre de classes ou de méthodes sont devenues "deprecated" au fil des versions.
    Concernant le gestion des menus... Cocoa implante une gestion des menus, mais à  la mode Next.
    Quand Apple a pondu OSX à  partir de Next, il n'a pas pu reprendre cette gestion des menus, car elle était en désaccord avec celle propre à  MAC OS (et ceci depuis Système 1).
    Je pense que par raccourci, les ingénieurs de la Pomme ont repris le code de gestion des menus (le menu manager) tel quel. Ce code appartenait à  la toolbox puis à  Carbon. Cocoa a était "tordu" afin de rentrer dans ce moule : c'est pourquoi des classes commes NSMenuView et NSMenuItemCell qui permettaient de personnaliser l'affichage des menus n'ont jamais été fonctionnelles (car trop éloignées de la manière dont le menu manager dessine ses menus).
    Le truc du symbole "POMME" pour faire le menu applications date de Système 1 (où ce menu s'appelait... menu Pomme). Il a été repris et mis au gout du jour (l'équivalent du menu Pomme d'avant étant le menu Application d'aujourd'hui).
    Le problème de ce truc est que s'est documenté dans les IM (Inside Macintosh) mais pas dans la doc Cocoa.
  • bofybofy Membre
    12:48 modifié #5
    C'est passionnant tout ça, instructif et vraiment nécessaire.
    Juste deux questions
    1. comment récupérer le nom de l'appli ? CFBundleName ne semble pas fiable ? sinon comment utiliser cette variable, j'ai oublié (un début d'Alzheimer ?)

    2. comment (idem) vider le cache de NSLog() afin de n'être pas obligé de lancer plusieurs fois l'appli (j'ai cherché, mais je n'ai pas trouvé grand chose sur NSLog, hors du formatage évident)

    dans 1212411953:

    dans 1212410106:

    Bizarre, j'ai viré "CFBundleName" du fichier "info.plist" et rien ne change. Bof !... en fait ce qui était plus important pour moi est ce qui suit.

    Si tu changes le info.plist de ton projet, il faut le recompiler totalement (par un "clean all targets" je crois).
    Ensuite, il faut simuler une install de l'appli pour forcer le launch service à  reconstruire ses caches (va dans le répertoire build de ton projet, repère l'appli, puis déplace là  via le Finder dans un autre répertoire).
    Maintenant, en l'absence de clé "CFBundleName", je ne sais pas comment le système va réagir (va t'il chercher le nom de l'appli autre part ?).

    dans 1212410106:

    Un peu de polémique :
    Je pense que la programmation objet (ou dite objet) est le contraire de la bidouille. C'est même l'un des avantages vantés de ce type de programmation : une fois qu'un objet est testé et validé, en principe plus de problèmes. Par contre la programmation graphique, qui impose de reproduire les mêmes adaptations à  chaque nouvelle application, est source d'erreurs, car on ne peut ni tout mémoriser, ni tout noter à  chaque nouvel essai, en plus elle ne permet pas de comprendre ce qu'on fait.

    Il n'y a pas de polémique.
    Même en prog objet, les problèmes que tu évoques sont possibles.
    Cocoa date de Next, or il évolue constamment. Nombre de classes ou de méthodes sont devenues "deprecated" au fil des versions.
    Concernant le gestion des menus... Cocoa implante une gestion des menus, mais à  la mode Next.
    Quand Apple a pondu OSX à  partir de Next, il n'a pas pu reprendre cette gestion des menus, car elle était en désaccord avec celle propre à  MAC OS (et ceci depuis Système 1).
    Je pense que par raccourci, les ingénieurs de la Pomme ont repris le code de gestion des menus (le menu manager) tel quel. Ce code appartenait à  la toolbox puis à  Carbon. Cocoa a était "tordu" afin de rentrer dans ce moule : c'est pourquoi des classes commes NSMenuView et NSMenuItemCell qui permettaient de personnaliser l'affichage des menus n'ont jamais été fonctionnelles (car trop éloignées de la manière dont le menu manager dessine ses menus).
    Le truc du symbole "POMME" pour faire le menu applications date de Système 1 (où ce menu s'appelait... menu Pomme). Il a été repris et mis au gout du jour (l'équivalent du menu Pomme d'avant étant le menu Application d'aujourd'hui).
    Le problème de ce truc est que s'est documenté dans les IM (Inside Macintosh) mais pas dans la doc Cocoa.
  • NoNo Membre
    12:48 modifié #6
    dans 1212418253:

    1. comment récupérer le nom de l'appli ? CFBundleName ne semble pas fiable ? sinon comment utiliser cette variable, j'ai oublié (un début d'Alzheimer ?)

    Par défaut le nom de l'appli tel qu'il apparait dans le moniteur d'activité, dans le menu pomme ("forcer à  quitter") ou dans le titre du menu de l'application provient de CFBundleName de info.plist.
    Si cette clé n'est pas trouvée, alors le système utilise comme nom d'appli le contenu de la clé CFBundleExecutable. Généralement elles sont identiques. Si cette dernière clé n'est pas trouvée, alors l'appli refuse de se lancer (message "appli endommagée").
    Pour récupérer le contenu de "info.plist" dans le programme, faut utiliser la méthode objectForInfoDictionaryKey: de la classe NSBundle :
    <br />NSLog(@&quot;le nom de l&#39;appli est : %@&quot;, [[NSBundle mainBundle] objectForInfoDictionaryKey:@&quot;CFBundleName&quot;]);
    


    dans 1212418253:

    2. comment (idem) vider le cache de NSLog() afin de n'être pas obligé de lancer plusieurs fois l'appli (j'ai cherché, mais je n'ai pas trouvé grand chose sur NSLog, hors du formatage évident)

    Je ne comprends pas la question.
    Quel cache ? Quel est le problème avec NSLog() ?
  • bofybofy Membre
    12:48 modifié #7
    Bonjour

    Merci à  tous
Connectez-vous ou Inscrivez-vous pour répondre.