Une cell redessinée

muqaddarmuqaddar Administrateur
05:17 modifié dans API AppKit #1
Salut,

Tiens, ça fait un moment que j'ai pas posté moi. ;-)

Bon, voilà , je veux personnaliser un NSPopUpButtonCell.
Je dois dessiner dans la méthode :

- (void)drawIAppBorderAndBackgroundWithFrame:(NSRect)cellFrame inView:(NSView *)controlView

Je dispose de 3 images pour remplir la cellFrame. La gauche, la droite, et celle du milieu qui doit de répéter en X.

Déjà , ce code :

[[NSColor colorWithPatternImage:[NSImage imageNamed:@&quot;imagePattern&quot;]] set];<br />	[NSBezierPath fillRect:cellFrame];


me donne des résultats pas terribles, l'image est répétée en Y aussi (logique), mais n'est pas calée en Y (ni en haut ni en bas).

Ensuite pour les images des côtés, j'ai fait un bête :

NSImage *leftImgNormal = [NSImage imageNamed:@&quot;imageLeft&quot;];<br />	[leftImgNormal compositeToPoint:NSMakePoint(cellFrame.origin.x, cellFrame.origin.y) operation:NSCompositeSourceOver];


qui n'affiche rien...

Un peu d'aide me ferait du bien, pour bien caler mes images dans cette vue. (car en fait, c'est une vue ds IB, même si ça hérite de NSPopUpButtonCell...)

Réponses

  • BruBru Membre
    05:17 modifié #2
    dans 1151507959:

    Déjà , ce code :
    [[NSColor colorWithPatternImage:[NSImage imageNamed:@&quot;imagePattern&quot;]] set];<br />	[NSBezierPath fillRect:cellFrame];
    

    me donne des résultats pas terribles, l'image est répétée en Y aussi (logique), mais n'est pas calée en Y (ni en haut ni en bas).


    Normal.
    L'utilisation d'une pattern color ne peut pas être utilisée dans ton cas.
    Les motifs sont toujours aligné par rapport à  l'écran, et non par rapport au conteneur qui les affiche.

    Tu dois utiliser :
    - une boucle pour dessiner x fois ton image de fond
    - une image "redimensionnée horizontalement" pour remplir la cell (idéal si l'image à  répéter fait 1 pixel de large, style un dégradé par exemple).



    dans 1151507959:

    Ensuite pour les images des côtés, j'ai fait un bête :
    NSImage *leftImgNormal = [NSImage imageNamed:@&quot;imageLeft&quot;];<br />	[leftImgNormal compositeToPoint:NSMakePoint(cellFrame.origin.x, cellFrame.origin.y) operation:NSCompositeSourceOver];
    

    qui n'affiche rien...


    C'est bête mais ça devrait marcher... Y'a trop peu de code, ou d'explication pour trouver le problème.



    dans 1151507959:

    Un peu d'aide me ferait du bien, pour bien caler mes images dans cette vue. (car en fait, c'est une vue ds IB, même si ça hérite de NSPopUpButtonCell...)


    Je pige pas ce que tu dis.
    NSPopUpButtonCell dérive de NSCell, qui dérive de NSObject.
    IB ou une vue (NSView ?) n'ont rien à  voir là  dedans !

    .
  • muqaddarmuqaddar Administrateur
    juin 2006 modifié #3
    Salut mon Bru,

    Si j'ai bien compris, il faut créer une image de la hauteur et largeur de la cellFrame en répétant mon image de 1 pxl de large en X. Puis faire un compositeToPoint de cette image dans la cellFrame.

    Pour le deuxième point, je suis dans une sous-classe de NSPopUpButtonCell (et NSPopupButton car en fait j'ai 2 classes surchargées). Seulement, dans IB, quand je mets ma custom class au popup, il ne change pas (bizarrement, il passe juste en UI graphite !). Or si je mets une petite NSView, et que je lui mets ma custom class NSPopUpButtonCell, là , ça dessine bien dedans...
    Je ne sais pas pkoi ça ne marche pas ds le premier cas.
  • muqaddarmuqaddar Administrateur
    juin 2006 modifié #4
    J'ai modifié mon code pour que ce soit plus clair :

    <br />- (void)drawIAppBorderAndBackgroundWithFrame:(NSRect)cellFrame inView:(NSView *)controlView<br />{<br />	NSImage *patternImage = [NSImage imageNamed:@&quot;hud_popupFill-N&quot;];<br />	NSColor *patternColor = [NSColor colorWithPatternImage:patternImage];<br />	<br />    // create temporary image for pattern<br />	NSImage *tempPatternImg = [[NSImage alloc] initWithSize:NSMakeSize(cellFrame.size.width, cellFrame.size.height)];<br />    [tempPatternImg lockFocus];<br />    [patternColor set];<br />    NSRectFill(NSMakeRect(0, 0, [tempPatternImg size].width, [tempPatternImg size].height));<br />    [tempPatternImg unlockFocus];<br />	<br />	[tempPatternImg drawInRect:cellFrame<br />					  fromRect:NSMakeRect(0, 0, <br />										[tempPatternImg size].width, <br />										[tempPatternImg size].height) <br />				   operation:NSCompositeSourceOver <br />					fraction:1.0];
    

    }

    Mais j'ai toujours mon colorWithPatternImage... donc le même problème.

    Je trouve que ça fait un peu bidouille d'utiliser une boucle pour répéter l'image ! Y'a vraiment pas mieux ?
    Ce genre de chose :

    for (i=0; i<(int)cellFrame.size.width; i++)
    {
    [patternImage compositeToPoint:NSMakePoint(((cellFrame.origin.x) + i), cellFrame.origin.y) operation:NSCompositeSourceOver];
    }
  • BruBru Membre
    05:17 modifié #5
    dans 1151565702:

    Pour le deuxième point, je suis dans une sous-classe de NSPopUpButtonCell (et NSPopupButton car en fait j'ai 2 classes surchargées). Seulement, dans IB, quand je mets ma custom class au popup, il ne change pas (bizarrement, il passe juste en UI graphite !). Or si je mets une petite NSView, et que je lui mets ma custom class NSPopUpButtonCell, là , ça dessine bien dedans...
    Je ne sais pas pkoi ça ne marche pas ds le premier cas.


    C'est tout à  fait normal comme comportement.

    Dans IB quand tu déposes un popupButton dans une vue, grosso-modo, cela va instancier un objet de type NSPopupButton et, mécaniquement, ça va aussi instancier un NSPopupButtonCell.

    Or si tu changes bien la classe de ton popupButton, la NSCell NSPopupButtonCell, elle, ne change pas de classe. D'où un affichage bizarre.

    Par contre, si tu déposes une NSView puis que tu change sa classe, IB réinstancie tous les objets nécessaires (dans ton cas, et ton pupButton, et sa cell personnalisée).

    .
  • BruBru Membre
    05:17 modifié #6
    dans 1151566068:

    Je trouve que ça fait un peu bidouille d'utiliser une boucle pour répéter l'image ! Y'a vraiment pas mieux ?
    Ce genre de chose :

    for (i=0; i<(int)cellFrame.size.width; i++)
    {
    [patternImage compositeToPoint:NSMakePoint(((cellFrame.origin.x) + i), cellFrame.origin.y) operation:NSCompositeSourceOver];
    }


    Ce n'est pas de la bidouille, c'est de la prog, mon cher...
    Soit dit en passant, la boucle que tu as fait est (sans doute) utilisée aussi dans les moteurs HTML quand il s'agit d'interprêter les ordres CSS du style [tt]background-repeat:repeat-x[/tt].

    Tu peux aussi utiliser la 2ème astuce : si le fond à  répéter est une image de 1 pixel de large, tu peux agrandir cette image horizontalement pour lui donner la même largeur que l'intérieur de la NSCell que tu composes.

    .
  • muqaddarmuqaddar Administrateur
    juin 2006 modifié #7
    OK.
    Voilà  où j'en suis, toujours sans succès...
    Rien ne se dessine ds la vue, or tout est OK ds le debugueur (coordonnées, image...)

    <br />	NSPoint newPoint = NSMakePoint([controlView frame].origin.x, [controlView frame].origin.y);<br />	<br />	[controlView lockFocus];<br />	for (i=0; i&lt;(int)cellFrame.size.width; i++)<br />	{<br />		[patternImage compositeToPoint:newPoint operation:NSCompositeSourceOver];<br />		newPoint.x++;<br />	}<br />	[controlView unlockFocus];<br />
    


    C'est bon, j'avais juste un problème en Y, il manquait :
    newPoint.y += cellFrame.size.height;
  • muqaddarmuqaddar Administrateur
    05:17 modifié #8
    Bon voilà  les gars le résultat.
    Merci !!!

    Sinon, une dernière chose, comment on peut savoir qu'un menu est cliqué (enfin ouvert) ?

    [Fichier joint supprimé par l'administrateur]
  • BruBru Membre
    05:17 modifié #9
    dans 1151575199:

    Sinon, une dernière chose, comment on peut savoir qu'un menu est cliqué (enfin ouvert) ?


    En surchargeant les méthodes attachPopUpWithFrame:inView: et dismissPopUp de ta NSCell, tu peux positionner une variable d'instance à  YES ou NO, variable que tu pourras intérroger par la suite.

    <br />- (void)attachPopUpWithFrame:(NSRect)cellFrame inView:(NSView *)controlView<br />{<br />&nbsp; &nbsp; _menuIsOpen=YES;<br />&nbsp; &nbsp; [super attachPopUpWithFrame:cellFrame inView:controlView];<br />}<br /><br />- (void)dismissPopUp<br />{<br />&nbsp; &nbsp; _menuIsOpen=NO;<br />&nbsp; &nbsp; [super dismissPopUp];<br />}<br />
    


    La variable d'instance est _menuIsOpen.

    .
  • muqaddarmuqaddar Administrateur
    05:17 modifié #10
    dans 1151578753:

    dans 1151575199:

    Sinon, une dernière chose, comment on peut savoir qu'un menu est cliqué (enfin ouvert) ?


    En surchargeant les méthodes attachPopUpWithFrame:inView: et dismissPopUp de ta NSCell, tu peux positionner une variable d'instance à  YES ou NO, variable que tu pourras intérroger par la suite.

    <br />- (void)attachPopUpWithFrame:(NSRect)cellFrame inView:(NSView *)controlView<br />{<br />    _menuIsOpen=YES;<br />    [super attachPopUpWithFrame:cellFrame inView:controlView];<br />}<br /><br />- (void)dismissPopUp<br />{<br />    _menuIsOpen=NO;<br />    [super dismissPopUp];<br />}<br />
    


    La variable d'instance est _menuIsOpen.

    .


    C'est génial. ça marche nikel. Un grand merci mon Bru. Toujours au top ! :-)
  • muqaddarmuqaddar Administrateur
    05:17 modifié #11
    Me revoilà  à  la charge.

    J'ai brodé un NSBouton du même accabi en surchargeant 2 classes, NSButton, et NSButtonCell.
    Le setType du button est NSMomentaryChange...

    Quand je clique sur mon bouton, il me dessine l'autre couleur grâce à  son state (NSOffState, NSOnState)... seulement, je n'arrive pas à  avoir le comportement d'un momentaryChange (comme si j'étais ds un mouseDown quoi...).

    J'ai aussi remarqué que
    - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
    qui s'occupe du dessin, est appellé 3 fois à  chaque clic...

    Une petite idée ou une bidouille pour revenir au mode normal après le lâché de clic serait la bienvenue.

    J'ai bien essayé ceci :
    if ([self state] == NSOnState)
    {
    [self setState:NSOffState];
    [self drawIAppBorderAndBackgroundWithFrame:cellFrame inView:controlView];
    }

    mais le momentaryChange est bien trop bref...
Connectez-vous ou Inscrivez-vous pour répondre.