où placer les méthodes associées à  une action (toujours sans IB)

bofybofy Membre
12:43 modifié dans API AppKit #1
Bonjour

Je sais associer une action à  un menuitem, par exemple ouvrir une fenêtre avec des boutons et des textfields. Je fais à  peu près ce que je veux.

Mais une première chose me chagrine : je dois mettre dans un delegate de NSApp les méthodes associées à  mes menuitem ?

La deuxième : je voudrais que un bouton de ma fenêtre grise le menuitem d'appel si une condition est YES ; pour cela il me semble que les notifications sont bienvenues ; or impossible de récupérer la méthode indiquée par le selector dans le addObserver !

Je n'ai pas vraiment compris la logique qui permet d'associer une action à  un objet et plus précisément où placer la méthode correspondante ? Faut-il nécessairement placer cette méthode dans un delegate de cet objet ? Quid en ce qui concerne les notifications ?

SVP, ce n'est pas la peine de répondre si c'est pour dire YAKA lire la doc sans autre précision

Réponses

  • Philippe49Philippe49 Membre
    août 2008 modifié #2
    dans 1217168774:

    Mais une première chose me chagrine : je dois mettre dans un delegate de NSApp les méthodes associées à  mes menuitem ?

    N'importe quel objet peux implémenter la méthode.
    Après que l'utilisateur ait cliqué sur le menuItem, cet item exécute une suite d'instructions qui en simplifié doit être à  peu près cela :
    id target = [self target];
      SEL selector=[self selector];
      [target performSelector:selector withObject:self];

    Cela a pour effet d'envoyer directement le message d'exécution à  target, la méthode étant précisée par le selector et l'argument étant sender=self.
    On voit bien que cela peut se faire pour n'importe quel target, sans intervention du mécanisme des notifications.

  • Philippe49Philippe49 Membre
    juillet 2008 modifié #3
    dans 1217168774:

    La deuxième : je voudrais que un bouton de ma fenêtre grise le menuitem d'appel si une condition est YES ; pour cela il me semble que les notifications sont bienvenues ; or impossible de récupérer la méthode indiquée par le selector dans le addObserver !

    Le NSButton réagit au clic de la même façon que le NSMenuItem.
      id target = [self target];
      SEL selector=[self selector];
      [target performSelector:selector withObject:self];

    Tous les deux doivent avoir été renseignés sur leur target et selector.
    Par exemple considérons un objet quelconque qui a une référence sur myButton et sur le menuItem
    Dans la phase d'initialisation, et lorsqu'on sait que myButton a été alloc/init-isé
      [myButton setTarget:self];
      [myButton setSelector:@selector(toggleMenuItem:)];


    et quelque part dans le code de la classe de cet objet
    -(void) toggleMenuItem:(id)sender {
       if([myMenuItem isEnabled]) {
           [myMenuItem setEnabled:NO];
       } else {
           [myMenuItem setEnabled:YES];
       }
    }
  • Philippe49Philippe49 Membre
    août 2008 modifié #4
    dans 1217168774:

    Je n'ai pas vraiment compris la logique qui permet d'associer une action à  un objet

    C'est un simple envoi de message. Il faut que l'objet ait connaissance de l'objet cible (target) à  qui envoyer le message, et d'une référence (selector) de la méthode a exécuter que possède cet objet cible
    Cela peut-être de manière plus élégante encapsulé dans une NSInvocation
    NSMethodSignature * methodSignature=[self methodSignatureForSelector:@selector(rightClic:)];
    NSInvocation * invocation=[NSInvocation invocationWithMethodSignature:methodSignature];
    [invocation setTarget:....];
            [invocation setSelector:@selector( .... )];


    dans 1217168774:

    Faut-il nécessairement placer cette méthode dans un delegate de cet objet ? Quid en ce qui concerne les notifications ?

    Les notifications suivent un mécanisme indirect :
    • L'objet qui veut répondre à  une invocation s'inscrit dans un centre de notifications
    • Le bouton, le menuItem, ou n'importe quoi poste une notification et l'envoie au centre de notifications
    • Le centre de notifications redistribue le message à  qui le veut.

  • Philippe49Philippe49 Membre
    juillet 2008 modifié #5
    dans 1217168774:

    impossible de récupérer la méthode indiquée par le selector dans le addObserver !


    Le KeyValueObserving est une troisième méthode d'envoi de transmissions de message, qui semble inappropriée ici.  
  • bofybofy Membre
    12:43 modifié #6
    Merci pour tes réponses complètes et précises.

    dans 1217173182:

    et quelque part dans le code de la classe de cet objet ...


    Cela veut-il dire qu'il faut créer une classe pour tout objet pour lequel on veut utiliser un selector ? Autrement dit sous-classer une classe cocoa pour pouvoir y insérer le code de la méthode associée ?

    Je vais essayer tout ça en détail, notamment le NSInvocation dont je ne vois pas vraiment l'utilité, pour l'instant...
  • bofybofy Membre
    12:43 modifié #7
    Bonjour

    J'ai essayé plein de trucs, dont sous classer les menuitem (les delegate semblent ne pas marcher sur cette classe), mais le selector de l'action n'est pas reconnu.

    La seule chose qui marche est de créer un delegate de NSApp et d'y placer les méthodes-action des menuitem !!!...

    Je n'ai toujours rien compris : du code SVP
    (c'est bien de dire
    <br />&nbsp; id target = [self target];<br />&nbsp; SEL selector=[self selector];<br />&nbsp; [target performSelector:selector withObject:self];<br />
    

    mais où je le mets ?
    ConnConnMenuItemCtrl * connConnMenuItem = [[ConnConnMenuItemCtrl alloc] initWithTitle:title action:select keyEquivalent:key];
    
    ne marche pas ...

    Merci
  • NoNo Membre
    12:43 modifié #8
    Je ne comprends pas ton problème.

    Je pense que tu as créé une classe qui contient toutes les méthodes (les actions) que tes menuitems vont lancer.
    Je pense que tu as instancié cette classe pour obtenir un objet.
    Donc, il ne te reste plus qu'à  mettre le pointeur de cet objet dans target, et le selector (obtenu par @selector(uneMethode:) pour déclencher la méthode uneMethode: par exemple) dans selector.

    C'est simple comme bonjour.

    Note, je crois que la signature de la méthode action doit toujours être de la forme - (void)uneMethode:(id)sender.
  • bofybofy Membre
    12:43 modifié #9
    Pourquoi le code suivant ne marche-t-il pas ? l'action n'est pas appelée quoique je fasse !
    <br />	ConnConnMenuItemCtrl * connConnMenuItem = [[ConnConnMenuItemCtrl alloc] initWithTitle:@&quot;connect ?&quot; action:@selector(connConnAction:) keyEquivalent:@&quot;C&quot;];<br />
    

    Je pense que les noms parlent par eux-même
    sachant que la méthode-action est dans ConnConnMenuItemCtrl :
    <br />-(void)connConnAction:(id)sender {<br />	NSLog(@&quot;connConnAction.in&quot;);<br />	}<br />
    


    Je ne comprends pas pourquoi ça marche lorsque je place cette méthode dans le delegate de NSApp?...

    dans 1217516417:

    Je ne comprends pas ton problème.

    Je pense que tu as créé une classe qui contient toutes les méthodes (les actions) que tes menuitems vont lancer.
    Je pense que tu as instancié cette classe pour obtenir un objet.
    Donc, il ne te reste plus qu'à  mettre le pointeur de cet objet dans target, et le selector (obtenu par @selector(uneMethode:) pour déclencher la méthode uneMethode: par exemple) dans selector.

    C'est simple comme bonjour.

    Note, je crois que la signature de la méthode action doit toujours être de la forme - (void)uneMethode:(id)sender.
  • Philippe49Philippe49 Membre
    août 2008 modifié #10
    Ici, il faut rajouter un
    [connConnMenuItem setTarget: self];
    dont la classe implémente la méthode
    -(void)connConnAction:(id) sender ou -(IBAction)connConnAction:(id) sender

    Et comme disent les bègues, c'est connConnContrôlé  ::)
  • Philippe49Philippe49 Membre
    août 2008 modifié #11
    dans 1217605715:

    Je ne comprends pas pourquoi ça marche lorsque je place cette méthode dans le delegate de NSApp?...


    La méthode de la classe NSMenuItem :
    - (id)initWithTitle:(NSString *)itemName action:(SEL)anAction keyEquivalent:(NSString *)charCode
    ne définit pas la cible target.

    Si target=nil
    Un mécanisme spécial est alors prévu : Le message correspondant est envoyé à  la chaà®ne des responder de l'application. Cette chaà®ne , "automatiquement" mise en place au lancement de l'application, se termine, sauf intervention explicite du programme  par la mainWindow (ou son delegate), et l'instance de l'application ( ou son delegate).
    Ainsi, logiquement, ton message après avoir été refusé par la mainWindow, a été tranmis au delegate de NSApp. Ton NSApp-delegate ayant une méthode adéquate a pu y répondre.

  • NoNo Membre
    12:43 modifié #12
    Philippe,

    T'as bien embrouillé l'esprit de Boffy avec le performSelector:withObject:, les bindings, les NSInvocation, et, pire, les setTarget:self (ce qui est d'ailleurs presque une hérésie en cocoa) dans tes précédents messages.

    Reste simple.
  • NoNo Membre
    12:43 modifié #13
    Boffy,

    si ta classe ConnConnMenuItemCtrl est une sous classe de NSMenuItem, alors je crois que tu vas droit dans le mur du MVC si jamais tu codes ta méthode d'action au sein de ton item.
  • Philippe49Philippe49 Membre
    août 2008 modifié #14
    dans 1217168774:

    Je n'ai pas vraiment compris la logique qui permet d'associer une action à  un objet et plus précisément où placer la méthode correspondante ? Faut-il nécessairement placer cette méthode dans un delegate de cet objet ? Quid en ce qui concerne les notifications ?


    dans 1217609837:

    Philippe,
    T'as bien embrouillé l'esprit de Boffy avec le performSelector:withObject:

    Ben répondre aux questions posées, cela me semble le minimum.

    dans 1217609837:

    Reste simple.

    Bofy semble vouloir démonter la machine en faisant sans IB, on lui démonte, cela répond à  son questionnement ... Bofy prenant le problème à  l'envers (sans la partie masquée de IB) les réponses ne peuvent pas être simples. Il me semble que ce qu'il veut c'est voir comment ça marche, pas vraiment le faire marcher.

    dans 1217609989:

    Boffy,
    si ta classe ConnConnMenuItemCtrl est une sous classe de NSMenuItem, alors je crois que tu vas droit dans le mur du MVC si jamais tu codes ta méthode d'action au sein de ton item.

    Le plus drôle dans l'histoire, ici, c'est que ce serait très acceptable que le NSApp-delegate réponde ici au menu, comme cela a été "obtenu par hasard". Si toutefois Bofy ne nous a pas fait la blague  ::) de déclarer le menuitem ... comme NSApp-delegate ce qui serait là  une offense à  l'académisme officiel en cours.

     
  • bofybofy Membre
    12:43 modifié #15
    Voilà  encore autre chose  : qu'est-ce que le "mur du MVC" ? J'ai bien lu sur le MVC dans Cocoa Application Tutorial, mais on n'y parle pas d'un "mur". Explications STP ?
    En plus ça marche, semble-t-il, parfaitement, cf. réponse à  Philippe.

    dans 1217609989:

    Boffy,

    si ta classe ConnConnMenuItemCtrl est une sous classe de NSMenuItem, alors je crois que tu vas droit dans le mur du MVC si jamais tu codes ta méthode d'action au sein de ton item.
  • bofybofy Membre
    12:43 modifié #16
    Ca ne me semble pas évident à  priori d'imaginer ça. Mais bof!...

    En tout cas, en ajoutant :
    <br />[connConnMenuItem setTarget:connConnMenuItem];
    

    après le
    <br />ConnConnMenuItemCtrl * connConnMenuItem = [[ConnConnMenuItemCtrl alloc] initWithTitle:...<br />
    

    ça semble parfaitement marcher, et c'est logique quand on a compris que le initWithTitle ne définit pas implicitement la target...

    dans 1217609647:

    La méthode de la classe NSMenuItem :
    - (id)initWithTitle:(NSString *)itemName action:(SEL)anAction keyEquivalent:(NSString *)charCode
    ne définit pas la cible target.
  • bofybofy Membre
    12:43 modifié #17
    Ben, tout ça n'est pas faux.

    A la fin du paragraphe cité ci-après, je rajouterais : "le faire marcher dans un but de production industrielle, certes non, mais avoir un logiciel Cocoa créé par moi sur Mac et qui marche avec PostgreSQL (ce qui n'est pas le plus difficile), certes oui.

    Pour finir, une fois encore, MERCI A TOUS.

    dans 1217616147:

    Bofy semble vouloir démonter la machine en faisant sans IB, on lui démonte, cela répond à  son questionnement ... Bofy prenant le problème à  l'envers (sans la partie masquée de IB) les réponses ne peuvent pas être simples. Il me semble que ce qu'il veut c'est voir comment ça marche, pas vraiment le faire marcher.


  • Philippe49Philippe49 Membre
    12:43 modifié #18
    dans 1217679310:

    Voilà  encore autre chose  : qu'est-ce que le "mur du MVC" ?

    C'est un mur dans le sens où c'est la stratégie classique actuelle, recommandée, pour organiser l'interaction des instances que l'on crée dans ce genre de langage.
    Voici [url=http://fr.wikipedia.org/wiki/Modèle-Vue-Contrôleur]un article de Wikipedia sur le sujet[/url]
  • pinuspinus Membre
    12:43 modifié #19
    dans 1217680839:

    ..."le faire marcher dans un but de production industrielle, certes non, mais avoir un logiciel Cocoa créé par moi sur Mac et qui marche avec PostgreSQL (ce qui n'est pas le plus difficile)...


    Je profite de ce passage pour vous demander si vous utilisez un framework PostgreSQL (si oui, où puis-je le trouver ?) ou si vous utilisez directement les libs C clientes de PGSQL ?

    D'avance merci.
  • schlumschlum Membre
    12:43 modifié #20
    En Framework postgre, il y a celui-ci qui est pas mal :
    http://sourceforge.net/projects/pgsqlcocoa/
  • bofybofy Membre
    12:43 modifié #21
    J'utilise NKDPostgreSQL Libraries.
    L'intérêt est la simplicité : une classe pour la connection, deux classes pour accéder à  PGSQL. De plus c'est totalement indépendant de l'installation de PostgreSQL. Bien sûr, ça ne fait pas tout, mais c'est suffisant pour ce que je veux faire.
    J'en ai fait un framework qui marche bien, semble-t-il, mais dont je ne garantirais pas la robustesse.
    Je peux t'envoyer le source et/ou même mon framework, si tu m'envoies un message pour que j'aie ton adresse mail.

    J'avais regardé le framework cité par@ Schlum : il m'avait semblé bien compliqué pour ce que je voulais faire, mais bien sûr il est certainement plus robuste, sinon stable.

    En outre, il y a pgAdmin3 pour l'administration complète des bases pgsql
        http://www.pgadmin.org/


    dans 1217684662:


    Je profite de ce passage pour vous demander si vous utilisez un framework PostgreSQL (si oui, où puis-je le trouver ?) ou si vous utilisez directement les libs C clientes de PGSQL ?

    D'avance merci.
  • bofybofy Membre
    12:43 modifié #22
    Terminé pour moi, merci à  tous
Connectez-vous ou Inscrivez-vous pour répondre.