NSRect et images

muqaddarmuqaddar Administrateur
23:32 modifié dans API AppKit #1
Salut,

J'ai un truc bizarre ici :

/<br />- (void)drawRect:(NSRect)rect<br />{<br />	[[NSColor clearColor] set];<br />	NSRectFill([self frame]);<br />NSLog(@&quot;img : %@&quot;, img);<br />	[img compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];<br />}<br /><br /><br />- (void)afficheFrame: (NSTimer *)myTimer<br />{		<br />	img = [[customFramesArray objectAtIndex: lastImg] retain];<br />	[self setNeedsDisplay:YES];<br />	NSLog(@&quot;img : %@&quot;, img);<br />	[img release];<br />		<br />	lastImg++;<br />	<br />	if (lastImg == [defaultFramesArray count]) {<br />		[timer invalidate];<br />		[timer release];<br />	}<br />}


Alors, j'ai un timer qui appelle afficheFrame, elle même qui appelle drawRect.
img est une variable d'instance.

Le NSLog de afficheFrame me renvoie bien l'image, mais pas celui de drawRect, pourtant img est bien var d'instance, et je la release après setNeedDisplay...

Le pire c'est que ça marchait avant... :(
Une idée ?

Réponses

  • fouffouf Membre
    23:32 modifié #2
    Met ton release avant le retain :
    - (void)afficheFrame: (NSTimer *)myTimer<br />{<br />[img release];<br />img = [[customFramesArray objectAtIndex: lastImg] retain];<br />[self setNeedsDisplay:YES];<br />NSLog(@&quot;img : %@&quot;, img);<br /><br />lastImg++;<br /><br />if (lastImg == [defaultFramesArray count]) {<br />[timer invalidate];<br />[timer release];<br />}<br />}
    
  • mpergandmpergand Membre
    23:32 modifié #3
    [grilled par fouf]

    fastoche la gestion mémoire en ObjC hein ?  ;D
  • muqaddarmuqaddar Administrateur
    23:32 modifié #4
    dans 1109868003:

    Met ton release avant le retain :
    - (void)afficheFrame: (NSTimer *)myTimer<br />{<br />[img release];<br />img = [[customFramesArray objectAtIndex: lastImg] retain];<br />[self setNeedsDisplay:YES];<br />NSLog(@&quot;img : %@&quot;, img);<br /><br />lastImg++;<br /><br />if (lastImg == [defaultFramesArray count]) {<br />[timer invalidate];<br />[timer release];<br />}<br />}
    



    Pareil... y'a un truc qui m'échappe, le NSLog de drawRect me renvoie un seul (null) alors que afficheFrame est appelé 30 fois, donc drawrect aussi par le biais de setNeedDisplay...
  • muqaddarmuqaddar Administrateur
    23:32 modifié #5
    dans 1109868291:

    [grilled par fouf]

    fastoche la gestion mémoire en ObjC hein ?  ;D


    C'est pas hyper dur une fois qu'on a pigé les grands principes. ;)
  • mpergandmpergand Membre
    mars 2005 modifié #6
    mais pourquoi tu fais un retain/release ?
    les images sont retenus par ton tableau

    C'est pas hyper dur une fois qu'on a pigé les grands principes

    T'as raison !  ;D :)
  • muqaddarmuqaddar Administrateur
    23:32 modifié #7
    dans 1109868548:

    mais pourqoui tu fais un retain/release ?
    les images sont retenus par ton tableau


    Oui, tu as raison, j'en ai pas besoin apparemment.
    Néanamoins le pb persiste. drawRect est appellée une seule fois !! alors que afficheFrame 30 fois.
  • VeillardVeillard Membre
    23:32 modifié #8
    Moi, j'ai utilisé ceci sans retain / release et ça marche...

    alarmASCicn = [NSImage imageNamed: @&quot;alarmeASC&quot;];<br />	<br />[alarmASCicn compositeToPoint: NSMakePoint(X, y), operation: NSCompositeSourceOver];<br />
    


    Je ne sais pas si ça répond à  ta question
  • ChachaChacha Membre
    23:32 modifié #9
    dans 1109868340:

    Pareil... y'a un truc qui m'échappe, le NSLog de drawRect me renvoie un seul (null) alors que afficheFrame est appelé 30 fois, donc drawrect aussi par le biais de setNeedDisplay...


    Excuse-moi, j'ai une question bête, qui n'a rien à  voir avec la mémoire, mais setNeedsDisplay:YES ne provoque pas l'affichage, il le marque simplement comme nécessaire au prochain runloop de l'interface ?

    Donc si afficheFrame est appelé 30 fois dans une boucle for(...) quelconque, et bien le réaffichage ne sera pas fait 30 fois, mais une seule, après que la boucle for a terminé et qu'on repasse au runloop du programme.
    Il faudrait rajouter un [self displayIfNeeded] après le [self setNeedsDisplay:YES], non ?

    +
    Chacha
  • mpergandmpergand Membre
    23:32 modifié #10
    moi je ferais [self display]

  • ChachaChacha Membre
    23:32 modifié #11
    dans 1109869641:

    moi je ferais [self display]


    Oui, ou alors [self display], et l'on n'a plus besoin du [self setNeedsDisplay:YES];
  • muqaddarmuqaddar Administrateur
    23:32 modifié #12
    dans 1109869793:

    dans 1109869641:

    moi je ferais [self display]



    Oui, ou alors [self display], et l'on n'a plus besoin du [self setNeedsDisplay:YES];


    Et non, img n'est tjs pas reconnu ds drawRect... :(
  • ChachaChacha Membre
    23:32 modifié #13
    dans 1109870409:

    Et non, img n'est tjs pas reconnu ds drawRect... :(


    Une idée en passant : ta NSView est-elle subView d'autre chose (NSBox, NSScrollView...) ? je crois qu'une fois j'ai eu un problème similaire d'affichage récalcitrant, et que je m'en étais sorti en faisant un setNeedsDisplay (et un displayIfNeeded) sur les superviews !
    Si tu es une sous-vue de NSBox, essaye
    [self setNeedsDisplay:YES];
    [[self superview] displayIfNeeded:YES];

    et si tu es sous-vue de NSScrollView:
    [self setNeedsDisplay:YES];
    [[[self superview] superview] displayIfNeeded:YES];

    Je en me rappelle pas le contexte dans lequel j'ai fait cela, mais au final ce code avait disparu, donc avait dû être résolu d'une autre manière. Mais si ça peut aider...

    +
    Chacha
  • muqaddarmuqaddar Administrateur
    23:32 modifié #14
    C'est une subclass de NSView tout simplement.
    Cette classe est initialisée depuis ma classe controlleur... si ça peut être une piste...
  • mpergandmpergand Membre
    mars 2005 modifié #15
    essaye d'aller au plus simple, pour tester:

    <br />/<br />- (void)drawRect:(NSRect)rect<br />{<br />    NSImage* img=[customFramesArray objectAtIndex: lastImg];<br />	[img compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];<br />}<br />- (void)afficheFrame: (NSTimer *)myTimer<br />{		<br />	[self display];<br />		<br />	lastImg++;<br />	<br />	if (lastImg == [defaultFramesArray count]) {<br />		[timer invalidate];<br />		[timer release];<br />	}<br />}
    
  • Eddy58Eddy58 Membre
    23:32 modifié #16
    Essaie d'encadrer ton traçage par un lockFocus et un unlockFocus : :)
    [tt]
    - (void)afficheFrame: (NSTimer *)myTimer
    {
    [self lockFocus];
    img = [[customFramesArray objectAtIndex: lastImg] retain];
    [self setNeedsDisplay:YES];
    [self unlockFocus];
    [/tt]
  • muqaddarmuqaddar Administrateur
    23:32 modifié #17
    dans 1109871596:

    Essaie d'encadrer ton traçage par un lockFocus et un unlockFocus : :)
    [tt]
    - (void)afficheFrame: (NSTimer *)myTimer
    {
    [self lockFocus];
    img = [[customFramesArray objectAtIndex: lastImg] retain];
    [self setNeedsDisplay:YES];
    [self unlockFocus];
    [/tt]


    Il appécie pas du tout :

    2005-03-03 18:41:18.838 iApp[11634] *** NSTimer discarding exception 'NSInternalInconsistencyException' (reason 'lockFocus sent to a view whose window is deferred and does not yet have a corresponding platform window') that raised during firing of timer with target 350b60 and selector 'afficheFrame:'
    2005-03-03 18:41:18.878 iApp[11634] *** Assertion failure in -[MyView lockFocus], AppKit.subproj/NSView.m:2746
  • Eddy58Eddy58 Membre
    23:32 modifié #18
    Oui je comprend pas pourquoi il bronche comme ça, ta méthode afficheFrame: est pourtant dans ta sous-classe de NSView non ? ???

    Avant le [self unlockFocus], tu peux aussi mettre :
    [tt]
    [[NSGraphicsContext currentContext] flushGraphics];
    [/tt]
  • mpergandmpergand Membre
    23:32 modifié #19
    Non !

    <br />- (void)afficheFrame: (NSTimer *)myTimer<br />{<br />[self lockFocus];<br />img = [customFramesArray objectAtIndex: lastImg];<br />[self drawRect:[self bounds];<br />[self unlockFocus];<br /><br />
    
  • Eddy58Eddy58 Membre
    mars 2005 modifié #20
    Normalement on ne peut pas appeler la méthode drawRect comme bon nous semble. Oxitan peut toujours essayer, sinon je propose aussi ceci : :)
    [tt]
    (void)afficheFrame: (NSTimer *)myTimer
    {
    [self lockFocus];
    img = [customFramesArray objectAtIndex: lastImg];
    [[NSColor clearColor] set];
    NSRectFill([self frame]);
    tt]Le flushGraphics va normalement forcer le tracé de ta view.
  • muqaddarmuqaddar Administrateur
    23:32 modifié #21
    Alors le [self drawRect:[self bounds];
    fait son effet et drawRect est bien appelé en boucle.

    Par contre mon image s'affiche pas...
    ;Les focus plantent en revanche...Je vais faire d&#39;autres tests.
  • Eddy58Eddy58 Membre
    23:32 modifié #22
    Essaie de faire simplement un flushGraphics derrière le setNeedsDisplay.... :)
    [tt] 
    -(void)afficheFrame: (NSTimer *)myTimer
    {
    img = [customFramesArray objectAtIndex: lastImg];
    [self setNeedsDisplay:YES];
    [[NSGraphicsContext currentContext] flushGraphics];
    [/tt]
  • muqaddarmuqaddar Administrateur
    23:32 modifié #23
    Ouep !
    Mes images apparaissent, mais le pb c'est que maintenant elles écrasent pas les anciennes. Elles apparaissent toutes mais comme j'ai un canal alpha, et bien, elles se montent les unes sur les autres...

    Pourtant ça :

    [[NSColor clearColor] set];
    NSRectFill([self frame]);

    C'est bien fait pour nettoyer le drawRect non ?
  • Eddy58Eddy58 Membre
    23:32 modifié #24
    clearColor fournie une couleur avec toutes les composantes à  0. Donc il est normal que ton fond ne soit pas effacé. Il faut que tu mettes la couleur que tu veux en fond, mais essaies déjà  avec un whiteColor pour voir si ça marche correctement. :)
  • fouffouf Membre
    23:32 modifié #25
    Je pensais, au lieu de NSRectFill([self frame]); utiliser
    [NSBezierPath fillRect:[self frame]];
  • mpergandmpergand Membre
    23:32 modifié #26
    le problème est que si NSRectFill([self frame]) marche, c'est un coup de bol  :)

    essaye plutôt NSRectFill([self bounds])

    et pourquoi pas NSRectFill(rect);

  • fouffouf Membre
    23:32 modifié #27
    C'est vrai. frame, c'est pas vraiment ce que l'on cherche.
  • Eddy58Eddy58 Membre
    23:32 modifié #28
    dans 1109879928:

    Je pensais, au lieu de NSRectFill([self frame]); utiliser
    [NSBezierPath fillRect:[self frame]];

    Il n'y a aucune différences, je n'ai jamais eu l'honneur de voir le code de cette fonction, mais je pense qu'elle se contente juste d'appeler NSBezierPath. :)
  • muqaddarmuqaddar Administrateur
    23:32 modifié #29
    Bonsoir,

    Bon, merci à  vous, j'ai compris mon erreur.
    J'ai définie ma sous-classe de NSView dans IB sur une customView et je créais aussi une instance depuis mon controlleur !!! ça se montait dessus, c'était le bordel. En plus j'instanciais init et non initWithFrame.

    Encore merci de vos réponses réactives.
Connectez-vous ou Inscrivez-vous pour répondre.