voir un dessin se faire à  l'écran ...

macvelottemacvelotte Membre
07:37 modifié dans API AppKit #1
Bonjour à  tous ...

Je dessine point par point un triangle de Sierpinski (triangle fractal). Voici comment est fait le dessin (S1,S2,S3 sont les sommets du triangle) :
<br />-(void)tracer<br />{<br />	NSPoint PC;<br />	long total;<br />	[[NSColor whiteColor] set];<br />	int s;<br />	total=0;<br />	do<br />		{<br />			s = (random() % 3)+1;<br />			switch(s)<br />				{<br />				case 1:<br />					{<br />						PC.x=(S1.x+P0.x)/2;<br />						PC.y=(S1.y+P0.y)/2;<br />						break;<br />					}<br />				case 2:<br />					{<br />						PC.x=(S2.x+P0.x)/2;<br />						PC.y=(S2.y+P0.y)/2;<br />						break;<br />					}<br />				case 3:<br />					{<br />						PC.x=(S3.x+P0.x)/2;<br />						PC.y=(S3.y+P0.y)/2;<br />						break;<br />					}<br />				}<br />			[NSBezierPath strokeLineFromPoint:PC toPoint:NSMakePoint(PC.x+0.1,PC.y+0) ];<br />			P0.x=PC.x;<br />			P0.y=PC.y;<br />			total++;<br />		}<br />	while (total&lt;400000);<br />	<br />}<br />


Il ne se passe rien à  l'écran tant que "tracer" n'est pas terminé, après quoi le triangle apparà®t entièrement dessiné.
J'aimerais voir le triangle apparaà®tre progressivement : est-ce possible ? (ce que je faisais en C, CodeWarrior).

Réponses

  • LeChatNoirLeChatNoir Membre, Modérateur
    07:37 modifié #2
    Slt,
    Après ton [NSBezierPaht stroke...], fais un [maVue setNeedDisplay].

    a+

  • BruBru Membre
    07:37 modifié #3
    dans 1142585287:

    Après ton [NSBezierPaht stroke...], fais un [maVue setNeedDisplay].


    Non, il doit faire un [maVue display] pour un affichage immédiat.
    setNeedDisplay marque la vue comme étant à  redessiner... plus tard (c'est à  dire en fin de boucle d'événement généralement).

    .
  • LeChatNoirLeChatNoir Membre, Modérateur
    07:37 modifié #4
    ah ben ouais d'ac.
    un display tout court  ::)
  • macvelottemacvelotte Membre
    07:37 modifié #5
    Encore une question : quelle définition pour "maVue" ?

    Le dessin se fait dans une "StretchView"  : je dois être à  coté de la plaque ???
  • Eddy58Eddy58 Membre
    mars 2006 modifié #6
    Le problème, c'est que la méthode drawRect va être appelée à  chaque display, et ça risque de pas trop aller...;)
    Il faut donc réadapter le code que je t'avais donné pour faire boucler la méthode drawRect sur l'appel à  la méthode tracer tant que le total de points n'est pas atteint. Encore une fois, le code ci-dessous n'a pas du tout été essayé, donc il y a sûrement de la mise au point à  faire...
    Il faut déclarer les variables d'instances forceDisplay et total dans l'interfaçage.
    [tt]
    -(void)awakeFromNib
    {
         forceDisplay=NO;
         total=0;
         clicksCount=4;
         [self setNeedsDisplay:YES];
    }

    -(void)drawRect:(NSRect)rect
    {
       NSGraphicsContext *contexte;

       if (!forceDisplay)
       {
        if (clicksCount==4) // Pour l'initialisation
        {
            [[NSColor whiteColor] set];
            NSRectFill(NSMakeRect(rect));  // Initialiser la vue
            return;
        }

        if (clicksCount==0)
        {
            [[NSColor whiteColor] set];
            NSRectFill(NSMakeRect(rect));  // Réinitialiser la vue
            S1=posSouris;
            clicksCount=1;
        }
        if (clicksCount==1)
        {
            S2=posSouris;
            clicksCount=2;
        }
        if (clicksCount==2)
        {
            S3=posSouris;
            clicksCount=3;
        }
       
        // Désactivation de l'anti-aliasing
        contexte=[NSGraphicsContext currentContext];
        [contexte setShouldAntialias:NO];
       }

       if (clicksCount<3 && forceDisplay==NO)
       {
            [NSBezierPath strokeLineFromPoint:NSMakePoint(posSouris.x+0.5,posSouris.y) toPoint:NSMakePoint(posSouris.x+0.5,posSouris.y+0.5)];
       }
       else
        {
             clicksCount=0;
             [self tracer]
        }

       if (!forceDisplay)
       {
        // Réactivation de l'anti-aliasing
        contexte=[NSGraphicsContext currentContext];
        [contexte setShouldAntialias:YES];
       }
    }

    -(void)mouseDown:(NSEvent *)event
    {
       if (clicksCount==4)
       {
             clicksCount=0;
       }
       posSouris=[self convertPoint:[event locationInWindow] fromView:nil];
       [self setNeedsDisplay:YES];
       [super mouseDown:event];
    }

    -(void)tracer
    {
       NSPoint PC;
       long total;
       [[NSColor whiteColor] set];
       int s;

       do
          {
             s = (random() % 3)+1;
             switch(s)
                {
                case 1:
                   {
                      PC.x=(S1.x+P0.x)/2;
                      PC.y=(S1.y+P0.y)/2;
                      break;
                   }
                case 2:
                   {
                      PC.x=(S2.x+P0.x)/2;
                      PC.y=(S2.y+P0.y)/2;
                      break;
                   }
                case 3:
                   {
                      PC.x=(S3.x+P0.x)/2;
                      PC.y=(S3.y+P0.y)/2;
                      break;
                   }
                }
             [NSBezierPath strokeLineFromPoint:PC toPoint:NSMakePoint(PC.x+0.1,PC.y+0) ];
             P0.x=PC.x;
             P0.y=PC.y;
             total++;
            if (total<400000)
            {
                 forceDisplay=YES;
                 [self display];
            }
          }
       while (total<400000);

       total=0;
       forceDisplay=NO;
    }[/tt]
  • macvelottemacvelotte Membre
    07:37 modifié #7
    Il faut que je prenne ma tête à  deux mains ...

    quid de "[self display] " ? Cela suppose une "procedure" (j'utilise mal à  propos le langage pascal) du type -(void)display ...?
  • LeChatNoirLeChatNoir Membre, Modérateur
    07:37 modifié #8
    Ben en fait, une classe qui est une sous classe d'une NSView doit implémenter (si besoin de traçage) la méthode DrawRect.
    Cette méthode sera appelé automatiquement lorsque ta vue doit être rafraichie (ex : redimensionnement de fenêtre, passage arrière plan/premier plan de l'appli, etc).

    Donc faire un [self display] dans le DrawRect de ta vue reviendrai à  indiquer qu'il faut appeler le drawRect....
  • macvelottemacvelotte Membre
    07:37 modifié #9
    ...et faire ainsi des DrawRect allonge considérablement le temps d'exécution !

    Question : quel est le rôle de l'anti-aliasing  >:(
  • Eddy58Eddy58 Membre
    mars 2006 modifié #10
    dans 1142848827:

    ...et faire ainsi des DrawRect allonge considérablement le temps d'exécution !

    Ca c'est à  mesurer...et puis si tu as meilleur méthode et bien je suis preneur...;)

    dans 1142848827:

    Question : quel est le rôle de l'anti-aliasing  >:(

    L'anti-aliasing estompe le crénelage en recalculant des couleurs intermédiaires, à  toi de voir si tu veux le laisser actif ou non, mais je trouve qu'il est plus pratique de le laisser désactivé au moins pour le dessin des sommets choisis a la souris. :o
  • macvelottemacvelotte Membre
    07:37 modifié #11
    Non, je n'ai pas de meilleure méthode ... et pour l'instant je n'obtiens pas ce que je cherche ! :'(
  • WIMPWIMP Membre
    07:37 modifié #12
    dans 1142864973:

    Non, je n'ai pas de meilleure méthode ... et pour l'instant je n'obtiens pas ce que je cherche ! :'(


    Une piste à  explorer serait d'utiliser les methodes:
    self window] restoreCachedImage]; //Dessine l&#39;image sauvegardée par cacheImageInRect<br />//Dessiner une ligne<br />[[self window] cacheImageInRect:[self frame; //enregistre l'image

    La difficulté est de les placer dans le bon ordre là  ou il faut...

    Une autre idée à  essayer serait de définir la fenêtre comme nonretained au lieu de buffered, dans IB.
  • macvelottemacvelotte Membre
    07:37 modifié #13
    Une autre idée à  essayer serait de définir la fenêtre comme nonretained au lieu de buffered, dans IB.


    WIMP : c'est la solution ! il n'y a rien à  faire dans le code.

    Merci pour cette géniale idée !
  • Eddy58Eddy58 Membre
    07:37 modifié #14
    Bon, j'ai essayé le principe que j'ai proposé ci-dessus, ça ne fonctionne pas, et en plus c'est plantogène, tout simplement car on appel la méthode drawRect à  l'intérieur de celle-ci alors que son exécution n'est pas terminée....donc joli SIGSEV, j'ai même eu droit à  un kernel panic en insistant un peu. B)

    il n'y a rien à  faire dans le code

    Le non retained est une solution, mais ça demande de gérer soi-même le rafraichissement. Si c'est pour un usage personnel, c'est pas bien grave, mais pour une appli à  diffuser, ça change tout. En non-retained, les coins de la fenêtre sont noirs, et le rafraichissement de toutes les subviews est à  ta charge, et ça peut vite devenir lourd surtout si tu as des contrôles en plus dans la fenêtre. Ca peut se limiter en faisant une espèce de child window customisée non retained comportant une custom subview. Cette child window est liée à  une window bufferisée qui elle comporte tout les contrôles, ensuite il n'a a plus qu'à  assurer le rafraichissement de la child window dans tout les cas de figure, mais encore une fois tout ceci n'est qu'hypothèse... :)
  • macvelottemacvelotte Membre
    07:37 modifié #15
    Mon application ne fait rien d'autre que dessiner le triangle fractal de Sierpinski : je pense que le "non retainde" dans ce cas est tout à  fait suffisant ; je reste doonc dans le cadre d'un simple curiosité mathématique, pour laquelle je n'ai aucune explication ...

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