[Résolu]NSOutlineView : couleurs différentes selon le niveau dans l'arborescence

mybofymybofy Membre
janvier 2014 modifié dans API AppKit #1

Bonjour


 


Je sais changer la couleur de tous les items d'une arborescence dans un NSoutlineView.


 


Est-il possible d'avoir une couleur pour les items de niveau 0, une autre pour les items de niveau 1, etc.


C'est utile pour différencier, par exemple, un descendant d'un item par rapport à  un item qui n'a pas de descendant.


 


J'ai essayé :



- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
if ([tableColumn dataCellForRow:0]) {
NSColor *txtColor = [NSColor redColor];
NSFont *txtFont = [NSFont boldSystemFontOfSize:14];
NSDictionary *txtDict = [NSDictionary dictionaryWithObjectsAndKeys:
txtFont, NSFontAttributeName, txtColor, NSForegroundColorAttributeName, nil];
NSAttributedString *attrStr = [[NSAttributedString alloc]
initWithString:[item stringValue] attributes:txtDict];
[[item cell] setAttributedStringValue:attrStr];
[item updateCell:[item cell]];
}
return nil;
}

Mais ça ne donne rien.


 


Une piste ?


Réponses


  • Il faut utiliser :


    outlineView:willDisplayCell:forTableColumn:item:


     


    Déjà  dit à  de nombreuses reprises sur ce forum, par ex ici:


    http://forum.cocoacafe.fr/topic/1728-changer-la-couleur-du-fond-dune-cellule-dans-une-nstableview/


  • Merci.


     


    J'avance un peu, mais pas de résultat.



    #import "DataModel.h"
    #import "OutlineDelegate.h"
    @interface OutlineViewCtrl : NSViewController
    @property (weak) IBOutlet NSOutlineView *outlineView;
    @property (strong) OutlineDelegate *outlineDelegate; @implementation OutlineViewCtrl
    @synthesize outlineView=_outlineView;
    @synthesize outlineDelegate=_outlineDelegate;
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
    [DataModel dataModel];
    [_outlineView setDelegate:_outlineDelegate];
    }
    return self;
    }
    @end @interface OutlineDelegate : NSObject <NSOutlineViewDelegate> @implementation OutlineDelegate

    -(void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
    NSLog(@outlineView);
    }

    Aucun message dans le Debug Area.


     


    Où est l'erreur ?


  • AliGatorAliGator Membre, Modérateur
    Bah tu affectes le delegate de ton OutlineView dans le initWithNibName. Or à  ce stade ta propriété "outlineDelegate" est certainement "nil" car pas encore instancié/affecté... donc forcément tu ne vas pas aller loin si ton delegate est nil ;)
  • D'accord.


     


    Maintenant, je fais :



    _outlineViewCtrl = [[OutlineViewCtrl alloc] initWithNibName:@OutlineViewCtrl bundle:nil];
    _outlineDelegate = (id<NSOutlineViewDelegate>)[NSObject new];
    [[_outlineViewCtrl outlineView] setDelegate:_outlineDelegate]; #import "DataModel.h"
    @interface OutlineViewCtrl : NSViewController
    @property (weak) IBOutlet NSOutlineView *outlineView; @implementation OutlineViewCtrl
    @synthesize outlineView=_outlineView;
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
    [DataModel dataModel];
    }
    return self;
    }
    @end @interface OutlineDelegate : NSObject <NSOutlineViewDelegate> @implementation OutlineDelegate

    -(void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
    NSLog(@outlineView);
    }


    Je n'ai toujours pas de message. !?


  • CéroceCéroce Membre, Modérateur
    janvier 2014 modifié #6
    Normal, si tu mets un NSObject en délégué.
    C'est un OutlineDelegate que tu dois instancier.
  • Dans



    @interface OutlineDelegate : NSObject <NSOutlineViewDelegate>

    j'ai remplacé NSObject par NSOutlineView.


     


    et j'ai remplacé



    _outlineDelegate = (id<NSOutlineDelegate>)[NSObject new];


    par



    _outlineDelegate = [OutlineViewDelegate new];


    Rien ne change.

     

    En fait, je ne comprends pas comment "-(void)outlineView:..." est appelé.

     

    En lisant Using an Outline View Delegate, j'ai l'impression qu'il faut quelque part une sorte d'événement qui déclenche  "-(void)outlineView:...". Mais ce n'est pas clair pour moi, d'autant que mon anglais est très limité.

    Est-ce que l'événement déclencheur est la prise en charge des données l'une après l'autre?

     

    Dans SideBar, "-(void)outlineView:..." est appelé automatiquement, pour chaque item me semble-t-il. J'ai ajouté un NSLog et j'ai bien les messages attendus. SideBar met tout dans le AppDelegate et ce n'est pas la première fois que j'ai du mal à  transposer.

     

    Je tourne en rond.

  • Les données  sont dans NSUserDefaults via un NSTreeController. NSOutlineView récupère les données via  le NSTreeController. Tout cela est réalisé par des bindings dans XIB.


     


    J'imagine que dès que l'instance de NSOutlineView est créée, elle récupère les données dans NSUserDefaults via le NSTreeController.


     


    Dès lors, le delegate de NSOutlineView n'a plus d'effet, puisqu'il est associé après que les données sont chargées lors de la création de l'instance.


     


    Non ?


     


    Il faudrait associer le delegate avant que NSOutlineView récupère les données dans le XIB. Mais comment faire ?


  • Après pas mal d'heures à  essayer des tas de choses (exemples de NSOutlineView sur le net), à  lire la doc, à  tenter de deviner comment ça fonctionne, j'ai trouvé une solution.


     


    J'ai créé deux objets : OutlineViewDelegate et OutlineViewDataSource, avec les protocoles associés.


     


    La méthode de mpergand ne peut pas marcher, puisqu'il s'agit de cell et que de toute façon l'item est constant. Elle permet de modifier la couleur du fond de la cell, mais pas celle du texte. Sa réponse m'a bien aidé pourtant, car elle m'a guidé vers la solution.


     


    Une chaà®ne NSString porte en elle des attributs de présentation, très pauvres. Et si on veut aller plus loin, il faut utiliser NSAttributeString ou la version mutable de celle-ci.


     


    C'est donc au niveau de la source de données qu'il faut utiliser des NSAttributeString au lieu des NSString.


     


    Ceux qui veulent voir comment j'ai fait : https://github.com/mybofy/AppOutline 


    Ce n'est sans doute pas un modèle de programmation mais ça marche !


     


    Grand merci à  tous.




  • Elle permet de modifier la couleur du fond de la cell, mais pas celle du texte.




     


    As-tu pensé à  regarder du coté de NSTextFieldCell ?


     


    ;)

  • J'ai jeté un coup d'oeil, et j'avoue m'être un peu perdu: y a-t-il une raison pour ne pas utiliser une window de IB et y ajouter tes vues? Tu crées ta fenêtre par code, puis tu lui ajoutes trois vues issues de xib différents, par un "windowcontroller" qui, lui, n'a pas de xib dédié... Ton schéma MVC est plutôt flou. Tu as une fenêtre de document, elle devrait contenir tout ce qu'il te faut. Et tu la fais apparaà®tre avec la commande Fichier:Nouveau document.


     


    Résultat, au milieu de ces objets qui nécessitent des dizaines de lignes de code qui (re)font probablement ce que tu as gratuitement avec AppKit, j'ai de la peine à  voir qui est delegate de qui, et... à  vrai dire comment tout ça fonctionne.


     


    Peut-être qu'en reprenant tout ça, tu verras ton code fondre et se résumer à  l'essentiel: colorer certaines lignes d'une outlineView.


     


    Cela dit, si tu faisais une view-based NSOutlineView, tu accéderais à  l'objectValue.textField dans la datasource et tu pourrais colorer ta ligne...




  • As-tu pensé à  regarder du coté de NSTextFieldCell ?




     


    Oui.

    Mais si je ne me trompe pas, cela change la couleur du texte de toutes les cellules de l'arborescence.

    Je souhaite avoir des couleurs différentes selon le niveau.

     

    Pour berfis (je me suis encore planté dans l'usage des multi-citations)



    "J'ai jeté un coup d'oeil, et j'avoue m'être un peu perdu: y a-t-il une raison pour ne pas utiliser une window de IB et y ajouter tes vues? Tu crées ta fenêtre par code, puis tu lui ajoutes trois vues issues de xib différents, par un "windowcontroller" qui, lui, n'a pas de xib dédié... Ton schéma MVC est plutôt flou. Tu as une fenêtre de document, elle devrait contenir tout ce qu'il te faut. Et tu la fais apparaà®tre avec la commande Fichier:Nouveau document.




    Résultat, au milieu de ces objets qui nécessitent des dizaines de lignes de code qui (re)font probablement ce que tu as gratuitement avec AppKit, j'ai de la peine à  voir qui est delegate de qui, et... à  vrai dire comment tout ça fonctionne.


    Peut-être qu'en reprenant tout ça, tu verras ton code fondre et se résumer à  l'essentiel: colorer certaines lignes d'une outlineView."


    Il s'agit d'un extrait d'une application qui comporte 18 fenêtres correspondant à  une fonctionnalité différente. Chacune de ces fenêtres comporte plusieurs vues changeant selon le choix effectué par un clic sur un bouton.


    J'utilise ces extraits pour mettre au point des fonctionnalités difficiles.

    Il est plus facile, pour moi, de générer tout ça par programmation, plutôt que d'avoir à  gérer 18x4 XIB. ça fait moins de code au final et il n'y a plus d'erreurs de positionnement.

     

     




    Cela dit, si tu faisais une view-based NSOutlineView, tu accéderais à  l'objectValue.textField dans la datasource et tu pourrais colorer ta ligne...




     


     


    Tu fais sans doute allusion à  la méthode :



    - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)theColumn byItem:(id)item {


    Elle renvoie des item de la classe __NSCFConstantString, autrement dit NSString.

    Il n'y pas de méthode objectvalue pour cette classe, ni pour NSObject dont elle dérive.

  • - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
    {
    int level=[outlineView levelForItem:item];

    [cell setTextColor:[NSColor blackColor]];

    if(level>0)
    [cell setTextColor:[NSColor redColor]];

    }


  • Ce qui est sûr, c'est que je n'aurais pas trouvé tout seul.


     


    Aussi bien, cela m'a permis de découvrir les NSAttributedString que je vais utiliser ailleurs, par exemple dans mes NSComboBox.


    À moins que tu aies une solution de la même sorte pour ces derniers ?


     


    Merci.


  • Tu veux faire quoi, modifier la couleur du texte d'un ComboBox ?


    La méthode setTextColor existe pour tous les objets dérivant de NSTextField, ce qui est le cas de NSComboBox.


  • J'ai bien compris ça.


     


    En fait, j'ai plusieurs listes de NSString que j'utilise aussi bien :


    dans des outlineview,


    dans des combobox, dans la liste interne et dans le textfield,


    dans des textfield,


    etc.


    Avec des listes de NSAttributedString je n'ai plus à  me préoccuper de gérer les couleurs localement, puisqu'elles sont un des attributs de chaque texte.


     


    La couleur des textes est importante pour moi car elle permet d'identifier le type des objets : en terme de taxonomie ordre (noir), famille (bleu), espèce (vert).


     


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