Barre d'outils et validation des items

muqaddarmuqaddar Administrateur
19:54 modifié dans API AppKit #1
Salut la compagnie créole, :P

Aujourd'hui, jouons avec les barres d'outils et la validation des élements.

1) Cette action sert à  valider un icone de la barre d'outils, c.a.d activer ou pas l'icone :

- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem<br />{<br />&nbsp; &nbsp; if ( [theItem action] == @selector(removeGroup:) )<br />     return [toto numberOfSelectedRows] &gt; 0;<br />}


C'est cool, mais dites-moi (surtout les binders), comment puis-je vérifier la sélection d'un élement sans faire encore un outlet sur ma table (ici toto) ?


2) Ensuite, on appelle une fonction comme ça en cliquant un icone avec les barres d'outils :
[item setAction:@selector(addWebsite:)];

Pour une fonction définie en dur dans le code, pas de problème, mais pour l'action toute faite "add:" des bindings comment procéder ?
J'ai essayé ça sans succès :
[item setAction:@selector([groupsController add: _groups])];



3) Est-ce qu'il est déjà  arrivé à  quelqu'un ici d'avoir des icônes floues et basse def ds la barre d'outils ? Moi j'en ai 1 sur 2. Incompréhensible. Ce sont des images Tiff (avec calques), j'ai essayé sans calque j'ai le même résultat...  :why?:
«1

Réponses

  • muqaddarmuqaddar Administrateur
    19:54 modifié #2
    Pour le 2) j'ai trouvé, je fais comme ça :

    [item setAction:@selector(addGroup)];
    


    puis :

    -(void)addGroup {<br />   [groupsController add: _groups];<br />}
    


    ça marche. Je ne sais pas si c'est le plus pratique en revanche.
  • muqaddarmuqaddar Administrateur
    19:54 modifié #3
    Pour le 1) , j'ai donc ajouté un outlet tableView à  une de mes tables, c'est rapide finalement, je pense pas qu'il puisse y avoir plus simple en fait. C'ets le problème des débutants, même quand ça marche, on se demande toujours si on a choisi la meilleure technique. :)
  • ClicCoolClicCool Membre
    19:54 modifié #4
    et en faisant:

    NSArray *selectionDeToto = [totoController selectedObjects];<br />return [selectionDeToto count];<br />
    


    ça marche pas ?
  • muqaddarmuqaddar Administrateur
    septembre 2004 modifié #5
    Effectivement, ça a l'air de marcher. ;)
    Et ça évite donc de créer 4 outlets en plus. Niveau code, ça revient au même. :)
    Merci Jeunot ! ;)

    Reste que tout ça marche à  moitié !

    //activation des icones<br />- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem<br />{<br />    if ([theItem action] == @selector(removeGroup:)) {<br />         NSArray *groupsSelection = [groupsController selectedObjects];<br />            return [groupsSelection count];<br />   }<br />    else if ([theItem action] == @selector(removeWebsite:)) {<br />              NSArray *websitesSelection = [websitesController selectedObjects];<br />                return [websitesSelection count];<br /> }<br />    else if ([theItem action] == @selector(removeServer:)) {<br />               NSArray *serversSelection = [serversController selectedObjects];<br />          return [serversSelection count];<br />  }<br />    else if ([theItem action] == @selector(removeHost:)) {<br />         NSArray *hostsSelection = [hostsController selectedObjects];<br />              return [hostsSelection count];<br />    }<br />}
    


    Déjà  quand je lance l'appli toutes les icones sont "On". Si je ne sélectionne pas d'éléments ds mes groupes, l'icône removeGroup n'est pas active OK. Si je sélectionne un site, l'icône RemoveServer est quand même sélectionnée... :((( Bref, ça marche à  moitié.

    Peut-être un pb de firstResponder qd je lance le soft ?
  • ClicCoolClicCool Membre
    19:54 modifié #6
    dans 1095947558:

    Reste que tout ça marche à  moitié !

    Déjà  quand je lance l'appli toutes les icones sont "On". Si je ne sélectionne pas d'éléments ds mes groupes, l'icône removeGroup n'est pas active OK. Si je sélectionne un site, l'icône RemoveServer est quand même sélectionnée... :((( Bref, ça marche à  moitié.

    Peut-être un pb de firstResponder qd je lance le soft ?


    J'ai pas bien saisi, si tu sélectionnes un site, RemoveServer devrait être désactivée même si un serveur est sélectionné ?

    Au passage, tu devrais peut être éviter les if else if ... imbriqués.
    Vu le nombre des possibilités un case serait sans doute plus efficient et surtout plus lisible ;)

    Tu peux même condenser la ligne return (que j'avais développée en 2 lignes par soucis de clarté) avec un:
    return [[groupsController selectedObjects] count];<br />
    
  • muqaddarmuqaddar Administrateur
    19:54 modifié #7
    J'ai bien essayé un switch, mais on me dit que ce n'est pas possible : switch quantity not an integer...

    Oui, tu as bien saisi, remove server devrait être déselctionné même si je sélectionne un site ! ET ce n'est pas le cas.
  • ClicCoolClicCool Membre
    19:54 modifié #8
    dans 1095949541:

    J'ai bien essayé un switch, mais on me dit que ce n'est pas possible : switch quantity not an integer...

    en effet :(

    dans 1095949541:
    Oui, tu as bien saisi, remove server devrait être déselctionné même si je sélectionne un site ! ET ce n'est pas le cas.


    Mais c'est pas ce que tu lui demandes.
    Tu lui demande d'être acif si un serveur est sélectionné sans lui préciser de se désactiver si un site est sélectionné.
    Ajoutes (0 == [[sitesController selectedObjects] count]) à  tes conditions pour le removeServer alors, non ?
  • muqaddarmuqaddar Administrateur
    septembre 2004 modifié #9
    Ah bon ?
    Je pensais que la condition qui renvoie YES implique que toutes les autres sont NO...

    Tiré d'un tutorial de PO :
    http://www.projectomega.org/article.php?lg=fr&php=oreilly_cocoa20&p=3

    "Si vous avez plusieurs éléments de barre d'outils ayant le même destinataire mais invoquant différentes actions, il est alors impératif que vous testiez, d'une façon ou d'une autre, que l'élément est l'élément de la barre d'outils que nous voulons valider avant de considérer que la validation est correcte. Un bon moyen de le faire est de comparer l'action de l'élément à  la méthode que nous voulons valider. C'est tout à  fait logique puisque ce que nous voulons vraiment faire c'est activer ou désactiver un comportement plutôt qu'un élément.


    Dans ce cas, nous avons vérifié si l'action de l'élément en question était la méthode deleteRecord:. Si c'est le cas, nous vérifions alors combien de lignes sont sélectionnées. Si une ou plus sont sélectionnées, alors YES est retourné, sinon, NO. Et c'est comme cela que fonctionne la validation d'élément de barre d'outils."
  • muqaddarmuqaddar Administrateur
    19:54 modifié #10
    Je pense qu'il faut faire un truc de ce genre :

    &nbsp; &nbsp; if ([theItem action] == @selector(removeGroup:)) {<br />               return (([[groupsController selectedObjects] count] &gt; 0)&amp;&amp;(0 == [[websitesController selectedObjects] count])&amp;&amp;(0 == [[serversController selectedObjects] count])&amp;&amp;(0 == [[hostsController selectedObjects] count]));<br />  }
    


    Non ?
  • ClicCoolClicCool Membre
    19:54 modifié #11
    Oui c'est à  un truc comme ça que je pensais,
    mais tout dépend du comportement que tu attends :

    Si tu veux vraiment que removeGroup ne soit actif QUE si aucun site NI serveur NI host ne sont sélectionnés même si un groupe est sélectionné alors oui c'est ce qu'il te faut.
    Là  y'a que toi qui peut décider le comportement adéquat.
    Mais pourquoi interdire le retrait d'un groupe si un serveur est aussi sélectionné ? ???
    J'imagine que pour toi ça a un sens ;)
  • ClicCoolClicCool Membre
    19:54 modifié #12
    dans 1095933416:

    Pour le 2) j'ai trouvé, je fais comme ça :

    [item setAction:@selector(addGroup)];
    


    puis :

    -(void)addGroup {<br />      [groupsController add: _groups];<br />}
    


    ça marche. Je ne sais pas si c'est le plus pratique en revanche.


    tu veux dire:

    -(void)addGroup {<br /> [groupsController addObject: unGroup];<br />}
    

    ou
    -(void)addGroup {<br /> [groupsController add: self];<br />}
    


    non ?

    la méthode add d'un controller prend comme argument le "sender". Elle crée un nouvel objet puis elle appèle addObject avec comme argument le nouvel objet créé (et pas l'argument de add).

    la méthode addObject, elle prend comme argument l'objet à  ajouter.
  • muqaddarmuqaddar Administrateur
    19:54 modifié #13
    dans 1095955856:

    Oui c'est à  un truc comme ça que je pensais,
    mais tout dépend du comportement que tu attends :

    Si tu veux vraiment que removeGroup ne soit actif QUE si aucun site NI serveur NI host ne sont sélectionnés même si un groupe est sélectionné alors oui c'est ce qu'il te faut.
    Là  y'a que toi qui peut décider le comportement adéquat.
    Mais pourquoi interdire le retrait d'un groupe si un serveur est aussi sélectionné ? ???
    J'imagine que pour toi ça a un sens ;)


    Non, non je faisais juste des tests rapidos j'ai pas approfondi le comportement que j'attends exactement mais je vais m'y atteler très bientôt. Merci.
  • muqaddarmuqaddar Administrateur
    19:54 modifié #14
    Pour le addGroup, ces 2 méthodes marchent et semblent donner le même résultat :

    -(void)addGroup {
          [groupsController add: self];
    }

    ou

    -(void)addGroup {
          [groupsController add: _groups];
    }

    Par ailleurs, je n'ai pas saisi ton explication / addObject... :(
  • ClicCoolClicCool Membre
    19:54 modifié #15
    et bien la méthode add: des controllers est en fait une méthode action et même une IBAction (conectable directement sous IB comme toutes IBActions)

    Et comme toutes méthodes action elle ne prend qu'un seul argument: (id) sender.

    Et comme beaucoup l'action, elle ne fait rien de son argument "sender".
    Elle se contente de créer un objet et d'appeler la méthode addObject: avec le nouvel objet créé comme argument.
    Ce qui explique que tes 2 versions fonctionnent en fait.
    t'aurais donc aussi pu écrire:
    -(void)addGroup {
           [groupsController add: le_Pape];
    }
    que le résultat serait le même.

    Néanmoins la sacrosainte documentation Apple nous précisant que l'argument doit être le sender, et le sender étant ici l'instance pointée par self, [groupsController add: self] est plus conforme aux spécification d'Apple qu'autre chose.

    Ouf, je finissait par m'enméler un peu sur la fin, j'étais plus clair là  ? ;)
  • ClicCoolClicCool Membre
    19:54 modifié #16
    dans 1095927566:

    ... Incompréhensible. Ce sont des images Tiff (avec calques), j'ai essayé sans calque j'ai le même résultat...  :why?:


    Ouais moi aussi j'ai des truc bizards avec un Tiff qui s'affiche chaque fois sans cheveux sur le forum  ;D ;D :P >:D

    ok, je sors ... ::)
  • muqaddarmuqaddar Administrateur
    19:54 modifié #17
    Bon, merci de ta deuxième explication, j'ai compris maintenant. ;-)
    Hasta luego ClicCool.
  • Eddy58Eddy58 Membre
    19:54 modifié #18
    En ce qui concerne les "else if", effectivement tu peux t'en passer dans de tels cas.

    Tu suis un code du genre :

    if (condition)
    { return }
    if (condition)
    { return }
    if (condition)
    { return }

    etc....

    Ca marche aussi bien.... :)
  • muqaddarmuqaddar Administrateur
    19:54 modifié #19
    je pensais que les else if bouffaient moins de ressources que les if à  la suite...
  • Eddy58Eddy58 Membre
    19:54 modifié #20
    Oui mais dans ton cas tu as des Return, ce qui fait que ca revient au-même, du moins je pense, non ?  :-\
  • muqaddarmuqaddar Administrateur
    19:54 modifié #21
    Bon pour ce que ça intéresse, voilà  comment j'ai finalement codé mes validations d'icones. De plus, j'ai une fenêtre à  tabView, donc j'ai aussi pris en compte la bonne sélection de ces dernières pour afficher l'icone ou non :

    //activation des icones<br />- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem<br />{<br />&nbsp; &nbsp; BOOL enable = NO;<br /><br />  //suppressions<br />&nbsp; &nbsp; if ([[toolbarItem itemIdentifier] isEqualToString:@&quot;RemoveGroupItem&quot;]) {<br />              enable = (([[groupsController selectedObjects] count] &gt; 0)&amp;&amp;<br />                            (![tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0));<br />&nbsp; &nbsp; } else if ([[toolbarItem itemIdentifier] isEqualToString:@&quot;RemoveWebsiteItem&quot;]) {<br />              enable = (([[websitesController selectedObjects] count] &gt; 0)&amp;&amp;<br />                          ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0));<br />&nbsp; &nbsp; } else if ([[toolbarItem itemIdentifier] isEqualToString:@&quot;RemoveServerItem&quot;]) {<br />                enable = (([[serversController selectedObjects] count] &gt; 0)&amp;&amp;<br />                           ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 1));<br />&nbsp; &nbsp; } else if ([[toolbarItem itemIdentifier] isEqualToString:@&quot;RemoveHostItem&quot;]) {<br />          enable = (([[hostsController selectedObjects] count] &gt; 0)&amp;&amp;<br />                             ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 2));<br />&nbsp; &nbsp; <br />  //ajouts<br />  } else if (([[toolbarItem itemIdentifier] isEqualToString:@&quot;AddGroupItem&quot;]) ||<br />                  &nbsp;  ([[toolbarItem itemIdentifier] isEqualToString:@&quot;AddWebsiteItem&quot;]) ||<br />                   &nbsp;  ([[toolbarItem itemIdentifier] isEqualToString:@&quot;AddServerItem&quot;]) ||<br />                    &nbsp;  ([[toolbarItem itemIdentifier] isEqualToString:@&quot;AddHostItem&quot;])) {<br />              enable = YES;<br />&nbsp; &nbsp; }<br /><br />&nbsp; &nbsp; return enable;<br />}
    


    Tout baigne maintenant. Joie.
  • 19:54 modifié #22
    dans 1095975844:

    Oui mais dans ton cas tu as des Return, ce qui fait que ca revient au-même, du moins je pense, non ?  :-\


    Le plus efficient est effectivement de mettre des return. Dans le cas des else if, il est obligé d'évaluer la condition qu'il y a derrière un else if. Si tu en as beaucoup c'est du coup plus lourd. Et tout à  la fin, tu mets simplement return NO; comme "sécurité".
  • TiffTiff Membre
    19:54 modifié #23
    dans 1095961921:

    ok, je sors ... ::)

    T'inquiète, je t'attends à  la sortie ! :boss):
  • muqaddarmuqaddar Administrateur
    19:54 modifié #24
    Et voilà  :

    - (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem<br />{<br />         //suppressions<br />    if ([[toolbarItem itemIdentifier] isEqualToString:@&quot;RemoveGroupItem&quot;]) {<br />                return (([[groupsController selectedObjects] count] &gt; 0)&amp;&amp;<br />                             ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0));<br />    } <br />   if ([[toolbarItem itemIdentifier] isEqualToString:@&quot;RemoveWebsiteItem&quot;]) {<br />              return (([[websitesController selectedObjects] count] &gt; 0)&amp;&amp;<br />                           ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 0));<br />    }<br />    if ([[toolbarItem itemIdentifier] isEqualToString:@&quot;RemoveServerItem&quot;]) {<br />               return (([[serversController selectedObjects] count] &gt; 0)&amp;&amp;<br />                             ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 1));<br />    }<br />   if ([[toolbarItem itemIdentifier] isEqualToString:@&quot;RemoveHostItem&quot;]) {<br />         return (([[hostsController selectedObjects] count] &gt; 0)&amp;&amp;<br />                              ([tabView indexOfTabViewItem:[tabView selectedTabViewItem]] == 2));<br />       }<br />    <br />       //ajouts<br />  if (([[toolbarItem itemIdentifier] isEqualToString:@&quot;AddGroupItem&quot;]) ||<br />         ([[toolbarItem itemIdentifier] isEqualToString:@&quot;AddWebsiteItem&quot;]) ||<br />           ([[toolbarItem itemIdentifier] isEqualToString:@&quot;AddServerItem&quot;]) ||<br />            ([[toolbarItem itemIdentifier] isEqualToString:@&quot;AddHostItem&quot;])) {<br />              return YES;<br />    }<br /><br />    return NO;<br />}
    


    Merci à  vous ! :-)
  • muqaddarmuqaddar Administrateur
    19:54 modifié #25
    Enfin, 2 petites choses pour terminer ma barre d'outils, maintenant que j'ai réussi à  ajouter la recherche dans une NSView qui est appelée dans ma barre d'outils :

    1) Je voulais que le mode des icônes par défaut soit small , j'ai donc écrit :
    [toolbar setSizeMode: NSToolbarSizeModeSmall];

    sans succès... (à  l'initialisation de ma toolbar).

    2) Et je voudrais aussi annuler la possibilité de mettre des grandes icônes qd on cutsomize la barre (la checkbox) et là  je sais pas comment faire ça...
  • cbrandtcbrandt Membre
    19:54 modifié #26
    dans 1096018681:

    1) Je voulais que le mode des icônes par défaut soit small , j'ai donc écrit :
    [toolbar setSizeMode: NSToolbarSizeModeSmall];

    sans succès... (à  l'initialisation de ma toolbar).


    essaie de supprimer ou de regarder dans ton fichier de préférences, car si tu as utilisé [toolbar setAutosavesConfiguration: YES], l'état "icônes grande taille" a été mémorisé dans le fichier de prefs...
  • muqaddarmuqaddar Administrateur
    19:54 modifié #27
    Même s'il est écrit après ?

    [toolbar setAutosavesConfiguration:YES];
    [toolbar setSizeMode: NSToolbarSizeModeSmall];

    ?
  • cbrandtcbrandt Membre
    19:54 modifié #28
    oui...

    par exemple j'ai ça dans un projet:

        NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier: @toolbar] autorelease];
       
        [toolbar setAllowsUserCustomization: YES];
        [toolbar setAutosavesConfiguration: YES];
        [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
        [toolbar setDelegate: self];
       
        [[self window] setToolbar: toolbar];

    eh ben le setDisplayMode: est ignoré car le setAutosavesConfiguration: est à  YES... (sauf bien sûr si le fichier de prefs n'existe pas ou si la clé NSToolbar Configuration toolbar est manquante)
  • muqaddarmuqaddar Administrateur
    19:54 modifié #29
    C'est dommage, parce que moi je voudrais leur donner la possibilité de modifier la barre d'icônes, mais uniquement leur enlever la possibilité de passer en grosse icône... donc j'ai besoin de autoSave à  YES
  • cbrandtcbrandt Membre
    19:54 modifié #30
    il suffit de créer nouvelle classe héritée de NSToolbar et qui dans setSizeMode appellerait super avec systématiquement NSToolbarSizeModeSmall:

    dans MyToolbar.h:

    #import <Cocoa/Cocoa.h>
    @interface MyToolbar : NSToolbar {}
    @end

    et dans MyToolbar.m:

    #import "MyToolbar.h"
    @implementation MyToolbar
    - (void) setSizeMode: (NSToolbarSizeMode) sizeMode
    {
    [super setSizeMode: NSToolbarSizeModeSmall];
    }
    @end

    bien sûr, il faut appeler NSToolbar *toolbar = [[[MyToolbar alloc] initWithIdentifier ... au lieu de NSToolbar, et rajouter #import "MyToolbar.h" dans le window controller... :)
  • muqaddarmuqaddar Administrateur
    19:54 modifié #31
    Super, je vais essayer ça ! ;-)
Connectez-vous ou Inscrivez-vous pour répondre.