NSOutlineView : hauteur de ligne variable
skimpy
Membre
Bonjour,
Je viens de créer une NSOutlineView mais j'aimerais définir des hauteurs de lignes différentes : par exemple, tout ce qui est au niveau 0 de l'outline fait X et tout ce qui est de niveau 1 fait Y (le plus concret et de lancer l'application Mail pour voir le résultat).
Dans la doc Apple, j'ai trouvé la méthode setRowHeight: et le delegate outlineView:heightOfRowByItem: mais j'ai l'impression que ça s'adresse uniquement à l'outline complète et pas à une ligne.
Savez-vous comment faire ?
Merci.
Je viens de créer une NSOutlineView mais j'aimerais définir des hauteurs de lignes différentes : par exemple, tout ce qui est au niveau 0 de l'outline fait X et tout ce qui est de niveau 1 fait Y (le plus concret et de lancer l'application Mail pour voir le résultat).
Dans la doc Apple, j'ai trouvé la méthode setRowHeight: et le delegate outlineView:heightOfRowByItem: mais j'ai l'impression que ça s'adresse uniquement à l'outline complète et pas à une ligne.
Savez-vous comment faire ?
Merci.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
[tt]
- (float)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
if (item==unItem)
{
return 14.0f;
}
else
{
return 18.0f;
}
}
[/tt]
Il ne me reste plus qu'à centrer le texte verticalement maintenant (car là , il se situe tout en haut). Vous pensez que je dois descendre au niveau de la cellule pour effectuer ce genre d'opérations ?
[tt]
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
   NSAttributedString *cellAttrString;
   NSDictionary *cellAttrDict;
   float offset=-4.0; // Négatif je pense (à essayer).
   if (item==unItem)
   {
     cellAttrDict=[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:offset] forKey:NSBaselineOffsetAttributeName];
     cellAttrString=[[NSAttributedString alloc] initWithString:[cell stringValue] attributes:cellAttrDict];
     [cell setAttributedStringValue:cellAttrString];
     [cellAttrString release];
   } Â
}
[/tt]
J'ai fait quelques modifications pour être sûr que le code était bien exécuté :
NSColor * txtColor = [NSColor redColor];
NSFont * txtFont = [NSFont boldSystemFontOfSize:14];
cellAttrDict=[NSDictionary dictionaryWithObjectsAndKeys:txtFont, NSFontAttributeName, txtColor, NSForegroundColorAttributeName, [NSNumber numberWithFloat:offset] forKey:NSBaselineOffsetAttributeName, nil];
Le texte s'affiche bien en rouge et en taille plus grosse mais je n'ai pas de centrage. J'ai essayé des valeurs positives et négatives pour offset mais ça n'y change rien.
Tu peux toujours ajouter la ligne ci-dessous après le release pour essayer, mais je pense pas que ça fasse grand chose.
[tt]
[outlineView updateCell:cell];
[/tt]
Sinon, je vois rien d'autre, à part surcharger la méthode de dessin de la cell et donc prendre tout son tracé en charge.
Salut, si je ne me trompe pas, NSImageAndTextCell dérive de NSTextFieldCell, et l'affichage du texte est pris en compte par un appel à [super drawWithFrame:cellFrame inView:controlView] dans -(void) drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView;
De ce fait, pour centrer ton texte, tu pourrais modifier le cellFrame pour le décaler vers le bas, genre avec
Tu nous tiens au courant ?
+
Chacha
[edit]
Tiens, y avait des problèmes de copier/coller dans mon post. Corrigé
[/edit]
Pour les personnes qui auraient un jour besoin du code, il faut mettre :
[super drawWithFrame:textFrame inView:controlView];
Par contre Chacha, comme je débute, est-ce que tu pourrais m'expliquer le cellFrame ? Il s'agit d'un cadre contenu dans une cellule ? Concrètement, le texte est placé dans un cadre (le cellFrame) qui lui même se situe dans une cellule de la NSOutlineView ?
Encore merci !
En lisant la doc, j'ai compris la même chose ! Pas grand chose à rajouter, donc...
Bonne continuation
+
Chacha
Effectivement ça change tout ! :P
Je trouvais curieux que ça ne fonctionne pas. C'est normal la méthode de dessin de la cell est surchargée (sans prendre tout les cas en compte). Quand tu utilises des classes autres que celles du framework Cocoa, il faut le spécifier sinon ça met carrément dedans.
Là , je viens de supprimer toutes les références à imageAndTextCell pour voir si le paramètre NSBaselineOffsetAttributeName est pris en compte mais ce n'est pas le cas (seules la taille et la couleur sont modifiées).
Il faut peut-être comme tu le précises surcharger la méthode de dessin.
Maintenant, si je veux vraiment être dans le look Apple, il faut que je fasse un dégradé quand une ligne est selectionnée et je comptais également mettre dans la colonne de droite, un chiffre encadré d'une forme ovale (comme lorsque Mail indique le nombre de message non lu). Pour le dégradé, je pense savoir comment faire, mais pour la forme ovale encadrant le texte, je ne vois pas. Vous auriez une piste ?
Encore merci pour votre précieuse aide.
Pour le dégradé, voici un code sympa , pour le rond, voici un début de réponse que tu peux adapter.
+
Chacha
Pas de l'image lors du drag&drop...
Je pencherai pour la même solution que NSImageAndTextCell. Reprend cette classe et ajoutes ton image à droite dans le DrawRect de la cell. Tu compose ton image avec ton ovale (soit tracer en live, soit une image) dans laquel tu compose ton texte (donc ton compteur) via un drawTextMachinChose (entre un lockFocus/unlockFous).
Enfin, y a peut être plus simple....
a+
2 solutions (qui nécessitent toutes les 2 une cell perso):
- tu rajoutes une colonne avec le numéro
- pour la cell perso que tu crées, tu rajoutes une variable d'instance qui représente le numéro que tu veux indiquer, que tu peux modifier lors de l'appel de la méthode de delegate suivante: [tt]outlineView:willDisplayCell:forTableColumn:item:[/tt]
Les 2 sont tout aussi valables, mais présentent des avantages et des inconvénients: pour faire simple, la première est plus simple à mettre en ½uvre que la seconde, mais c'est moins joli (à condition de faire la seconde dans les règles, genre si le texte est trop long et qu'il n'y a pas de numéro à indiquer, faire en sorte que le texte puisse déborder dans la zone normalement réservée au numéro).
Dans les 2 cas, tu dois faire une cell perso et surcharger la méthode [tt]drawInteriorWithFrame:inView:[/tt] et dessiner le numéro dans la forme de ton choix, dans le premier cas à partie de la intValue de la cell et dans le second à partir de la variable d'instance que tu auras rajouté.
Il n'est pas nécessaire que le texte soit dans l'image. Il peut d'abord rajouter le fond (que ce soit une image ou une courbe de bezier, qu'il peut choisir en fonction de la longueur) et dessiner le texte directement au dessus (avec le méthode [tt]drawAtPoint:attributes[/tt] de NSString) - et donc pas besoin de s'ennuyer avec les lockFocus/unlockFocus.
Par contre, une fonction essentielle et je voulais savoir si je faisais juste : quand je sélectionne un élément dans la NSOutlineView, il faut que je déclenche une fonction (pour charger des données dans une NSTableView). Pour intercepter le clic dans la NSOutlineView, il faut bien que j'utilise outlineViewSelectionIsChanging ? Est-ce qu'il est possible aussi d'intercepter un double clic sur un élément de la NSOutline (par exemple que la table ne soit chargée que s'il y a eu 2x clic sur l'élément de l'Outline).
Merci.
Je crois qu'un simple
- (void)setDoubleAction:(SEL)aSelector
suffit.
Il faut sous classer ton NSOutlineView et que celle ci ne soit pas éditable mais ca semble être le cas.
a+
Oui, alors pour les delegates et notifications, il faut faire attention aux temps des verbes qui composent les noms de méthodes. Dans le cas de outlineViewSelectionIsChanging, c'est au présent, donc le changement est en cours, le bouton de la souris est appuyé. Pour outlineViewSelectionDidChange, c'est du passé, donc le clique a été effectué. A toi de voir quelles méthodes utiliser selon tes besoins.
dans mon awakeFromNib, j'ai rajouté :
[outlineView setTarget:self];
[outlineView setDoubleAction:@selector(loadTable)];
Et si j'ai bien saisi, le outlineViewSelectionDidChange suffit amplement lorsqu'un simple clic a été effectué.
Eddy58, merci pour tes précisions sur les temps employés dans les delegates ; est-ce que tu pourrais également m'éclaicir sur les delegate avec des noms en should et will (ils arrivent à prévoir le futur ?)
Pour should et will, c'est assez simple.
Imaginons que tu sélectionnes un item de ton outlineView.
Dans l'ordre, l'outline envoie à son delegate :
* selectionWillChange : ca le prévient que le click a été déclenché et que la sélection va changer.
* selectionShouldChange : le delegate est informé que la sélection va changer et décide si oui ou non, l'action doit se faire,
* selection isChanging : on est en train de le faire,
* selectionDidChange : a y est, c'est fait.
Bon il y a bien d'autres notifications et cet exemple est bidon car pour une tableView, je crois pas qu'il y ait de selectionWillChange.
Mais c'était pour illustrer.
Tu as aussi par exemple un WillDisplayCell qui est envoyé au delegate lorsque la table va afficher une de ses cellules. Tu peux alors, dans le delegate, interagir juste avant l'affichage.
a+
Tu cliques et paf, l'action est appelée. Même si tu cliques sur un item déjà sélectionné.
outlineViewSelectionDidChange n'est appelé que si tu changes d'item je pense.
Par exemple, si tu changes programatiquement d'item ou peut être aussi via les touches (flèches haut/bas), SelectionDidChange sera appelée. Mais la méthode que tu as indiquée dans le setAction, non.
Mais on commence à s'éloigner du sujet initial là ... Faudrait peut être refaire un topic sur les outlines et tablesView...
a+
Sinon j'ai bien saisi grâce à ton explication la différence entre le delegate et le setAction.
Merci.