charger un menu depuis XIB

problème simple que je n'arrive pas à résoudre en cocoa :
j'ai plusieurs XIB, chacun représentant un menu ( NSMenu sous classé en "PopMenu").
Sur un clic bouton droit dans une NSView, je veux afficher un menu pop-up avec [NSMenu popUpContextMenu:[(NSMenu *)menu] withEvent:theEvent forView:self]; ( nota: le menu à afficher dépend de la position de la souris, c'est pour çà qu'il y en a plusieurs en Xib).
il me faut donc un NSmenu.
Je voudrais donc écrire une méthode générique pour charger et instancier un menu depuis mes XIB.
NSMenu * getMenuFromXib: (NSString *) Nibname

Comment faire cette procédure en cocoa ?

Merci..
Paul

Réponses

  • Tu peux le faire avec une class method sur NSMenu dont tu as déjà proposé la signature : NSMenu * getMenuFromXib: (NSString *) Nibname (même si je lui préfèrerai NSMenu * instantiateFromXib: (NSString *) Nibname mais je pinaille...)

    Après c'est plutôt simple et ça se passe avec la classe NSNib et la méthode - (instancetype)initWithNibNamed:(NSNibName)nibName bundle:(NSBundle *)bundle pour récupérer le Nib en lui même et le charger.
    Après à toi de charger son contenu avec - (BOOL)instantiateWithOwner:(id)owner topLevelObjects:(NSArray * _Nullable *)topLevelObjects et de bien gérer la mémoire comme c'est recommandé dans la doc.

    Je ne m'étendrai pas plus que ça. Je pense que tu as tout ce qu'il te faut pour te débrouiller en ta qualité de développeur aguerri 😉

  • Merci pour le compliment...Mais pas vraiment le cas !! Je connais Carbon sur le bout des doigts, mais la complexité de Cocoa me déroute un peu. Question de temps pour fouiller et absorber...
    Si tu pouvais t'étendre un peu plus ( en tout bien tout honneur hein ! ;) )ça m'aiderait !!
    j'ai écrit çà :
    _ NSArray *tlObj = [[NSArray alloc] init];
    NSNib *MyNib= [[NSNib alloc] initWithNibNamed:@PopUpMain bundle:nil];
    BOOL bMenuOK = [MyNib instantiateWithOwner:self topLevelObjects:tlObj];_
    la dernière ligne ne compile pas :(
    et là je nage ....

    je vais tout de même pas désactiver l'autorelease...
    CDT
    Paul

  • C'est normal que ça ne compile pas vu que tu ne lui donne pas ce qu'il attend. Si je me réfère à la signature en Swift (mon Obj-C est très très rouillé...) tu as func instantiate(withOwner owner: Any?, topLevelObjects: AutoreleasingUnsafeMutablePointer<NSArray?>?) → Bool ce qui veut dire qu'il attend un pointeur sur un NSArray comme second paramètre ou rien.

    Ce qui fait que BOOL bMenuOK = [MyNib instantiateWithOwner:self topLevelObjects:&tlObj]; a plus de chance de fonctionner.

    Maintenant vient la question que j'aurai du poser directement : si tes menus sont à afficher en relation avec un vue précise pourquoi est-ce que tu ne mets pas ces menus directement dans le xib de la vue en question ?

    Dans un registre voisin je vois bien que tu modernise ton logiciel de 3D mais sans vraiment utiliser de technologies modernes. Alors je ne dis pas d'utiliser forcément Swift vu qu'il te faudrait l'apprendre au préalable mais utiliser les storyboards ne serait pas trop mal.
    Qu'as-tu utilisé comme ressources pour te mettre le pieds à l'étrier en Cocoa par exemple ? Comment as-tu organisé ton code et ton projet ? Il faut prendre les bonnes décisions aussi tôt que possible 😉

  • Merci Pyroh. j'avais trouvé le &tlObj !

    `Maintenant vient la question que j'aurai du poser directement : si tes menus sont à afficher en relation avec un vue précise pourquoi est-ce que tu ne mets pas ces menus directement dans le xib de la vue en question>

    parce que il n'y a pas de Xib pour la fenêtre (aka View) en question. Elle est entièrement dynamique et peut changer d' état a tout moment.

    Dans un registre voisin je vois bien que tu modernise ton logiciel de 3D mais sans vraiment utiliser de technologies modernes.>

    tu vois juste. mais il me semble que Cocoa est une techno moderrne non ? ! le coeur de mon soft est un micro-langage qui décrit le comportement de l'utilisateur à partir des events. Ca permet de microprogrammer toutes sortes de fonctions de dessin 2D et 3D à partir d'instructions générique, sans rien coder de spécifique... ca fonctionne donc très près de events et des views et des menus contextuels sur plein de sortes d'entités (points, vecteurs, surfaces, cotations, objets 3D, camera,... )

    Alors je ne dis pas d'utiliser forcément Swift vu qu'il te faudrait l'apprendre au préalable mais utiliser les storyboards ne serait pas trop mal. >

    L'interface n'est pas réellement le problème. ... quelques fenêtres avec vues empilées et quelques barres d'outils.
    par franchement besoin d'un storyboard. ( mais vais zieuter quand même) Le Pb c'est de recoder plus de 800 fonctions et 150 dialogues.

    Qu'as-tu utilisé comme ressources pour te mettre le pieds à l'étrier en Cocoa par exemple ? Comment as-tu organisé ton code et ton projet ? Il faut prendre les bonnes décisions aussi tôt que possible>

    Etudié Cocoa sur Internet et Doc apple... Mon code carbon était déjà organisé en objets, donc pas de soucis de ce côté là. La structure est solide ainsi que la base de donnée géométrique. Le soucis est de mettre en oeuvre des mécanismes simples et répétitifs pour simplifier le portage. d'où mes questions sur les différents posts auxquels tu as l'amabilité de répondre.

    Dans mon ViewController:
    ....
    NSArray *tlObj;
    NSNib *MyNib= [[NSNib alloc] initWithNibNamed:@PopUpMain bundle:nil];
    BOOL bMenuOK = [MyNib instantiateWithOwner:self topLevelObjects:&tlObj];
    if( bMenuOK )
    {
    T3DMenus *theMenu =[tlObj firstObject];
    NSLog(@.....PopingUp);
    [theMenu popUpMenuPositioningItem:[theMenu itemAtIndex:9] atLocation: locationInWindow inView:self];
    NSLog(@.....Away);
    }

    ....
    me donne aléatoirement l'exception suivante... .. Pourtant tous les MenuItems sont branchés sur une action..
    Je ne comprends pas...

    Turbo64[7827:2368075] rightMouseDown at: 75.828125, 375.019531
    2018-08-16 04:14:18.065 Turbo64[7827:2368075] .....PopingUp
    2018-08-16 04:14:18.066 Turbo64[7827:2368075] -[NSApplication itemAtIndex:]: unrecognized selector sent to instance 0x618000100f30
    2018-08-16 04:14:18.066 Turbo64[7827:2368075] -[NSApplication itemAtIndex:]: unrecognized selector sent to instance 0x618000100f30
    2018-08-16 04:14:18.175 Turbo64[7827:2368075] (
    0 CoreFoundation 0x00007fff8883e4f2 exceptionPreprocess + 178
    1 libobjc.A.dylib 0x00007fff955c3f7e objc_exception_throw + 48
    2 CoreFoundation 0x00007fff888a81ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3 CoreFoundation 0x00007fff887ae571 ___forwarding
    + 1009
    4 CoreFoundation 0x00007fff887ae0f8 CF_forwarding_prep_0 + 120
    5 Turbo64 0x0000000100002709 -[ViewDraw rightMouseDown:] + 393
    6 AppKit 0x00007fff8fdbdb15 -[NSWindow _reallySendEvent:isDelayedEvent:] + 2108
    7 AppKit 0x00007fff8f7fc539 -[NSWindow sendEvent:] + 517
    8 AppKit 0x00007fff8f77cac7 -[NSApplication sendEvent:] + 2683
    9 AppKit 0x00007fff8f5e3df2 -[NSApplication run] + 796
    10 AppKit 0x00007fff8f5ad368 NSApplicationMain + 1176
    11 Turbo64 0x0000000100002053 main + 51
    12 libdyld.dylib 0x00007fff848625ad start + 1
    13 ??? 0x0000000000000003 0x0 + 3

    CDT
    Paul

  • LexxisLexxis Membre
    août 2018 modifié #6

    Bonjour,
    Tu est sûr d'avoir ajouté un objet NSMenu dans le fichier Nib qui est chargé ? J'ai l'impression ici que le premier objet qui est trouvé lors du chargement est du type NSApplication (comme indiqué dans ton message d'erreur) et non pas un MSMenu.

  • Premièrement réponse à ton soucis :
    T3DMenus *theMenu =[tlObj firstObject]; ne t'assure absolument pas de récupérer le menu. Comme tu as un tableau d'objets instanciés depuis le xib tu vas y trouver tout ce qui traîne. Notamment la référence NSApp, c'est elle qui te file cette erreur pour le coup : -[NSApplication itemAtIndex:]: unrecognized selector sent to instance 0x618000100f30. Ça sera plus clair si tu mets un point d'arrêt et que tu regarde ce qu'il y a dans tlObj.
    Pour trouver exactement ce que tu recherche je te conseille de regarder le protocol NSUserInterfaceItemIdentification (et surtout @property(copy) NSUserInterfaceItemIdentifier identifier;) que NSMenu adopte qui te permettra de retrouver tes petits au runtime.

    Pour le reste il y a deux trois choses qui me chiffonnent un peu :

    Tu semble instancier les menus à chaque fois que tu as besoin de les afficher ce qui est une mauvaise idée. Pas une très mauvaise idée en 2018 avec les machines de sagouins qu'on a mais quand même. Ça ne ferait pas de mal de les stocker dans ton contrôleur et de les garder en mémoire.
    Tu vas très certainement me dire qu'ils sont dynamiques ou qu'il faut faire des trucs avec selon le contexte alors regarde le protocol NSMenuDelegate.

    parce que il n'y a pas de Xib pour la fenêtre (aka View) en question. Elle est entièrement dynamique et peut changer d' état a tout moment.

    Pour la NSWindow tu as quand même un xib, non ? Après j'imagine que tu place ta vue principale dans le contentView de cette fenêtre. Tu peux créer tes menu dans ce xib et les lier avec un IBOutlet. Tu t'évite de les instancier à la main et de les instancier à chaque fois surtout.

    tu vois juste. mais il me semble que Cocoa est une techno moderrne non ? !

    Oui mais y'a toujours moyen de garder quelques vieux automatisme et manière de bosser qui font que même si le framework est moderne le méthode de programmation ne l'est pas forcément. Tu peux très bien coder en Swift à la mode Obj-C par exemple. Tu auras un langage moderne mais avec une méthode de programmation qui t'empêche de profiter de tout son potentiel.
    Un autre exemple plus parlant est de ne pas utiliser l'auto-layout au profit du bon vieux calcul de vues à la main. Y'a aussi des gens qui désactivent l'ARC...

  • DrakenDraken Membre
    août 2018 modifié #8

    @Pyroh a dit :
    Y'a aussi des gens qui désactivent l'ARC...

    Y'a aussi des gens qui vont chez le marabout en cas de douleurs dentaires...

  • @Draken a dit :
    Y'a aussi des gens qui vont chez le marabout en cas de douleurs dentaires...

    Et il ne faut pas ?

  • @Eric P. a dit :

    @Draken a dit :
    Y'a aussi des gens qui vont chez le marabout en cas de douleurs dentaires...

    Et il ne faut pas ?

    Euh .. comment dire ? La principale médication de ces "guérisseurs" est une infusion de feuilles de papier portant des sourates du Coran.

Connectez-vous ou Inscrivez-vous pour répondre.