Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1547 connectés 

  FORUM HardWare.fr
  Programmation
  C#/.NET managed

  [C#] GDI : Redessiner une partie de la fenêtre sur OnPaint

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[C#] GDI : Redessiner une partie de la fenêtre sur OnPaint

n°1295228
Arjuna
Aircraft Ident.: F-MBSD
Posté le 30-01-2006 à 23:09:24  profilanswer
 

Je suis en train de découvrir GDI avec C#. Ca m'a l'air assez simple d'utilisation, même si je ne suis pas sûr de tout comprendre le fonctionnement :D
 
J'ai en mémoire un array de 4 cases.
 
Sur "onpaint", je dessine 4 images correspondant aux trois cases.
Vu qu'à terme la zone définie par le tableau sera bien plus grande que la zone d'affichage, j'ai fait de l'optimisation de la mort qui tue, c'est à dire que si je vois qu'une cases n'est pas dans le tableau, je ne la dessine pas (super non ? ;))
 
Et j'aimerais bien vérifier que ça marche... Et c'est là que ça va plus !
 
Dans le coin suppérieur gauche de la fenête, je dessine un compteur indiquant combien j'ai dessiné de cases.
 
Lorsque je redimensionne ma form, OnPaint se lance bien, et le code qui est dedans aussi.
A priori, l'optimisation marche bien d'après mes tests sauf que... mon compteur ne se redessine pas !
De ce que je pense avoir compris du fonctionnement du bignou, même si dans OnPaint je redéfini l'affichage de toute la fenête, il ne relatte les modifications que sur la partie qui a bel et bien bougé, je me trompe ?
Alors comment lui dire de redessiner mon compteur qui n'est pas dans la zone redessinée ???

mood
Publicité
Posté le 30-01-2006 à 23:09:24  profilanswer
 

n°1295232
Arjuna
Aircraft Ident.: F-MBSD
Posté le 30-01-2006 à 23:13:49  profilanswer
 

Voivi le bout de code qui coince :

Code :
  1. protected override void OnPaint(PaintEventArgs e)
  2.         {
  3.             Graphics g = e.Graphics;
  4.             int cpt = 0;
  5.             for (Int64 i = 0; i < world.height; i++)
  6.             {
  7.                 if (i * 51 > this.ClientSize.Width)
  8.                 {
  9.                     break;
  10.                 }
  11.                 else
  12.                 {
  13.                     for (Int64 j = 0; j < world.width; j++)
  14.                     {
  15.                         if (j * 51 > this.ClientSize.Height)
  16.                         {
  17.                             break;
  18.                         }
  19.                         else
  20.                         {
  21.                             g.DrawImage(Image.FromFile("pictures/terrains/" + world.lands[i, j].terrain.pictureName), i * 51, j * 51);
  22.                             cpt++;
  23.                         }
  24.                     }
  25.                 }
  26.             }
  27.             g.DrawString(cpt.ToString(), new Font("Verdana", 10), Brushes.White, 10, 10);
  28.         }


Message édité par Arjuna le 30-01-2006 à 23:48:33
n°1295234
Arjuna
Aircraft Ident.: F-MBSD
Posté le 30-01-2006 à 23:15:16  profilanswer
 

PS: je suppose que parmi les améliorations possibles je devrais créer un array d'Image qui contiennent toutes les images possible non ? Là il fait réellement un accès disque pour chaque image, ou s'il est intelligent et se rappelle qu'il a déjà chargé l'image le coup d'avant ?

n°1295244
Arjuna
Aircraft Ident.: F-MBSD
Posté le 30-01-2006 à 23:47:36  profilanswer
 

Chais pas si il faisait un accès au disque ou pas, mais en tout cas, il me laissait un handle exclusif sur le disque, ce qui ne me plaisait pas. Corrigé en foutant mes images dans un tableau, puis aussi en recopiant chaque image dans un memorystream que j'utilise alors comme source pour l'image au final.
 
Et du coup, afin d'optimiser un peu la vitesse, en mémoire je peux gérer l'image en BMP au lieu de PNG, ce qui évite un re-décodage de mes images à chaque OnPaint. J'ai bon ou je suis totalement à la ramasse ?
 
PS: pour ce qui est du réaffichage de mon compteur, ben ça marche toujours pas :D C'est un comble, c'est un truc de débug qui m'empêche d'avancer lol

n°1295245
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 30-01-2006 à 23:48:18  profilanswer
 

faut faire un Invalidate() pour forcer le redessin complet de la fenêtre


---------------
J'ai un string dans l'array (Paris Hilton)
n°1295246
Arjuna
Aircraft Ident.: F-MBSD
Posté le 30-01-2006 à 23:51:15  profilanswer
 

Harkonnen a écrit :

faut faire un Invalidate() pour forcer le redessin complet de la fenêtre


ok... sauf que là je vais avoir un soucy :) si je le fait dans le "OnPaint" ça sent le crash non ? :D
 
en fait, même si la solution de mettre le invalidate dans le "OnResize" marcherait, j'aimerais savoir si je ne peux pas tout simplement dire de réafficher un bout de la fenêtre en particulier.
 
-- Edit :
Euh... invalidate peut prendre un rectangle en paramètre. merci ! :jap:

Message cité 1 fois
Message édité par Arjuna le 30-01-2006 à 23:52:42
n°1295247
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 30-01-2006 à 23:57:13  profilanswer
 

Arjuna a écrit :

ok... sauf que là je vais avoir un soucy :) si je le fait dans le "OnPaint" ça sent le crash non ? :D


surtout pas malheureux [:totoz]
tu places un Invalidate() après avoir réalisé le tracé de ton compteur
 

Arjuna a écrit :


en fait, même si la solution de mettre le invalidate dans le "OnResize" marcherait, j'aimerais savoir si je ne peux pas tout simplement dire de réafficher un bout de la fenêtre en particulier.


y'a une surcharge qui permet de spécifier un rectangle à redessiner ;)
 
edit: il a édité [:pingouino]


Message édité par Harkonnen le 30-01-2006 à 23:57:32

---------------
J'ai un string dans l'array (Paris Hilton)
n°1295257
Arjuna
Aircraft Ident.: F-MBSD
Posté le 31-01-2006 à 00:32:57  profilanswer
 

ze soucy, c'est que le compteur est recalculé lors du repaint dans mon code ;)
 
mais c'est pas grave, j'ai mis le code du truc (c'est clair :D) dans le onresize et ça marche bien :)
 
j'ai ajouté un handler sur le "isinputchaisplusquoi" et je peux maintenant bouger un gif transparent par dessus mon "monde" avec le clavier :)
 
Allez, dans deux jours j'ai recodé civilization à ma sauce :D


Message édité par Arjuna le 31-01-2006 à 00:33:35
n°1295258
Arjuna
Aircraft Ident.: F-MBSD
Posté le 31-01-2006 à 00:36:17  profilanswer
 

par contre, je suis en train de réfléchir que dans le onpaint je devrais peut-être gérer seulement la partie à réafficher... parcequ'actuellement, je recalcule l'image de toute la partie visible de la fenêtre... sauf que de toute façon il n'affiche les modifs que dans la partie qui a effectivement bougé :D du coup non seulement je traîte trops de trucs, mais en plus ils servent à rien :D

Message cité 1 fois
Message édité par Arjuna le 31-01-2006 à 00:36:42
n°1296364
_Mose_
Lonesome coder
Posté le 01-02-2006 à 14:16:39  profilanswer
 

Arjuna a écrit :

par contre, je suis en train de réfléchir que dans le onpaint je devrais peut-être gérer seulement la partie à réafficher...

C'est la sagesse même :)

Arjuna a écrit :

parcequ'actuellement, je recalcule l'image de toute la partie visible de la fenêtre... sauf que de toute façon il n'affiche les modifs que dans la partie qui a effectivement bougé :D du coup non seulement je traîte trops de trucs, mais en plus ils servent à rien :D

Bon j'ai pas tout compris à la problématique, mais je te suggèrerai bien d'utiliser le double buffering :

Code :
  1. // Ton double buffer dans lequel tu fais le dessin
  2. private Bitmap _doublebuffer = null;
  3. // flag pour resetter le dessin si besoin
  4. private bool _reset = false;
  5. // Si le control est resizé
  6. protected override void OnResize(EventArgs e)
  7. {
  8. // si le double buffer n'est pas null
  9. if(this._doublebuffer != null)
  10. {
  11.  // le supprimer
  12.  this._doublebuffer.Dispose();
  13.  this._doublebuffer = null;
  14. }
  15. // réallouer le buffer
  16. this._doublebuffer = new Bitmap(this.Width, this.Height);
  17. // faire reset :)
  18. this._reset = true;
  19. }
  20. // A appeler si la valeur de ton compteur change
  21. protected override void OnResize(EventArgs e)
  22. {
  23. // reset le dessin
  24. this._reset = true;
  25. }
  26. /// Paint the control
  27. protected override void OnPaint(PaintEventArgs e)
  28. {
  29. base.OnPaint (e);
  30. // si le buffer n'est pas nul (par précaution, mais normallement, le OnResize est toujours appelé avant)
  31. if(this._doublebuffer != null)
  32. {
  33.  // si le dessin est resetté
  34.  if(this._reset)
  35.  {
  36.   // faire le dessin
  37.   this.DrawControlIntoBuffer();
  38.   // disable the reset flag
  39.   this._reset = false;
  40.  }
  41.  // coller le dessin dans ta fenêtre
  42.  using(Graphics gc = this.CreateGraphics())
  43.   gc.DrawImage(this._doublebuffer, 0, 0);
  44. }
  45. }


---------------
Tout est normal, suffit de comprendre pourquoi.
mood
Publicité
Posté le 01-02-2006 à 14:16:39  profilanswer
 

n°1296457
Arjuna
Aircraft Ident.: F-MBSD
Posté le 01-02-2006 à 15:13:20  profilanswer
 

si dans ma fenêtre j'ai un "invalidate" sur le rectangle "(10, 10), (20, 20)"
 
En 0, 0 j'ai un carré rouge
 
Dans le "onpaint", je change le carré rouge en carré vert.
 
Ben même après appel du invalidate le carré reste rouge : le onpaint ne redessine que la zone spécifiée dans la zone à redessiner, même si on redessine tout (enfin, c'est ce que j'ai compris d'après mes tests)

n°1296461
Arjuna
Aircraft Ident.: F-MBSD
Posté le 01-02-2006 à 15:16:17  profilanswer
 

sinon, pas tout pigé au double buffer :D ça fait quoi ça marche comment ?
 
ça va résoudre le problème de clignotement ?

n°1296592
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 01-02-2006 à 16:24:48  profilanswer
 

t'as une explication du double buffering sur ce magnifique topic qu'on devrait classer R+ :o
http://forum.hardware.fr/forum2.ph [...] =0#t517627


---------------
J'ai un string dans l'array (Paris Hilton)
n°1296620
_Mose_
Lonesome coder
Posté le 01-02-2006 à 16:38:37  profilanswer
 

Ouaip, ça va résoudre tes problèmes de clignotement.
Avec ça tu ne fais qu'une seule opération sur le Graphics associé à ta fenêtre, donc ça tourne du feu de dieu.
Je fais des animations avec ce principe.
 
Je comprend pas ton problème avec ton Invalidate. Ce que tu dit semble logique : s'il redessine la zone 10x10, 20x20, il ne redessine pas ce qui se trouve en 0x0. Avec le code que je t'ai filé, j'ai pas pris en compte le ClipRectangle : je redessine tout à chaque fois. Mais si tu veux ne redessiner qu'une partir, tu peux : il suffit de passer le ClipRectangle en paramètre de la méthode 'DrawControlIntoBuffer'.
 
Ensuite, j'ai une interrogation déontologique (si si !) : pourquoi tu décides de changer un carré rouge en vert dans ton OnPaint ? Il est là pour dessiner, pas pour choisir si il faut que ce soit vert ou rouge. Pour métaphorer (oulàlàlà) : le OnPaint c'est le colleur d'affiche. Bah c'est pas à lui de décider si le texte doit être en vert ou en noir. C'est au créatif :)    Bon c'est ptet moi qui ai pas compris ton bp en fait...


---------------
Tout est normal, suffit de comprendre pourquoi.
n°1296675
Arjuna
Aircraft Ident.: F-MBSD
Posté le 01-02-2006 à 17:08:22  profilanswer
 

_Mose_ a écrit :

Ouaip, ça va résoudre tes problèmes de clignotement.
Avec ça tu ne fais qu'une seule opération sur le Graphics associé à ta fenêtre, donc ça tourne du feu de dieu.
Je fais des animations avec ce principe.
 
Je comprend pas ton problème avec ton Invalidate. Ce que tu dit semble logique : s'il redessine la zone 10x10, 20x20, il ne redessine pas ce qui se trouve en 0x0. Avec le code que je t'ai filé, j'ai pas pris en compte le ClipRectangle : je redessine tout à chaque fois. Mais si tu veux ne redessiner qu'une partir, tu peux : il suffit de passer le ClipRectangle en paramètre de la méthode 'DrawControlIntoBuffer'.
 
Ensuite, j'ai une interrogation déontologique (si si !) : pourquoi tu décides de changer un carré rouge en vert dans ton OnPaint ? Il est là pour dessiner, pas pour choisir si il faut que ce soit vert ou rouge. Pour métaphorer (oulàlàlà) : le OnPaint c'est le colleur d'affiche. Bah c'est pas à lui de décider si le texte doit être en vert ou en noir. C'est au créatif :)    Bon c'est ptet moi qui ai pas compris ton bp en fait...


ok pour le double buffering :) vais tester ça ce soir :)
 
sinon, pour le problème du clip rectangle, j'ai pas de souci, c'est juste qu'au départ :
-> sur un resize, un onpaint est déclenché pour les zones modifiée. hors moi je voulais affiche un petit compteur dans la zone d'affichage, et j'avais beau le modifier, il ne se mettait pas à jour lors de l'affichage.
d'où :
- ma question du départ sur la façon de forcer le redessin d'une zone particulière (avec invalidate)
- et le fait que j'ai compris que ça servait à rien que je redessine dans mon graphics toute la zone d'affichage, puisque seule la zone du cliprectangle était effectivement redessinée, d'où ma recherche d'optimisation pour ne redessiner que la zone qui va bien :)

n°1296746
_Mose_
Lonesome coder
Posté le 01-02-2006 à 17:56:37  profilanswer
 

Okidoki.
Je pense que tu vas apprécier le double buffering :)
Et si t'as des questions pour moi, c'est demain ou dans deux mois et demi. Après demain je me casse loin... très loin...


---------------
Tout est normal, suffit de comprendre pourquoi.
n°1296816
Arjuna
Aircraft Ident.: F-MBSD
Posté le 01-02-2006 à 19:08:49  profilanswer
 

Harkonnen a écrit :

t'as une explication du double buffering sur ce magnifique topic qu'on devrait classer R+ :o
http://forum.hardware.fr/forum2.ph [...] =0#t517627


Lu :) En fait, je savais déjà ça. Moi c'était la façon de le coder que je m'attendais à trouver expliquée ;) Car en fait, j'ai un peu rien compris à ce qu'à posté _Mose_ :ange:

n°1296908
Arjuna
Aircraft Ident.: F-MBSD
Posté le 01-02-2006 à 20:20:49  profilanswer
 

En attendant de maîtriser le fonctionnement du double buffer, j'ai avancé sur la gestion des mouvements des unités dans mon monde.
 
Pour résumer :
- Le monde est défini par un tableau à deux dimensions de "cLand".
- cLand est un objet contenant un "cTerrain" qui indique les propriétés du terrain, et un tableau à une dimension de "cUnit" qui contient les unités qui se trouvent sur ce terrain.
 
Bon, avec tout mon joyeux bordel qui commence à être bordelique, j'arrive à balader une pièce dans ce petit monde.
 
Par contre, pour parcourir les unités (genre pour trouver l'unité suivante après la fin du mouvement de l'unité en cours de mouvement), c'est un peu pas évident.
 
Du coup, j'ai l'idée de rajouter un tableau à une dimension de "cUnitLocation" dans l'objet du monde (au même niveau que le array de "cLand" ) contenant des liens vers toutes les unités qui se trouvent dans le monde avec associée, la position x,y dans on array de "cLand".
 
Seulement, là je vais avoir un petit problème. C# ne sait pas faire de tableaux redimensionnables. Et utiliser un ListArray, je ne suis pas sûr que ce soit une bonne solution si je veux que ce soit tout bien optimisé.
 
Me reste alors une autre solution bien batarde, qui consiste à dimensionner mon array à 65535 lignes initialisées à <null> et remplir au fur et à mesure avec mes unités... Et remettre <null> quand une unité est par exemple détruite. Je ne suis pas certain que ce soit vraiment mieu, puisque je vais passer mon temps à me balader dans ce grand tableau, et en plus c'est pas super propre...
 
Reste la solution de recopier mon tableau dans un tableau plus grand ou plus petit à chaque fois qu'une unité est crée ou détruite, mais là je crois que c'est ce qu'il y a de pire ! C'est ce que j'ai opté pour le array de "cUnit" qui est dans "cLand" lorsqu'une unité se déplace, parceque le nombre d'unités sur une même case ne devrait jamais être grand, mais là, si je fait ça pour toutes les unités du monde, ça va être bonbon...
 
C'est quoi la meilleur solution ? Y'en a d'autres mieux ?


Message édité par Arjuna le 01-02-2006 à 20:21:10
n°1297313
_Mose_
Lonesome coder
Posté le 02-02-2006 à 12:59:02  profilanswer
 

* Pour les ArrayList, perso j'utilise beaucoup, maintenant niveau perf j'en sais rien, c'est pas ça qui fait des ralentissements chez moi. Ca a le mérite d'être simple et rapide à utiliser, et ça peut se transformer en tableau sur demande (ToArray)
* La solution du gros tableau statique est pas très pratique : si tu passes ton temps à enlever des unités et à en remettre, tu vas devoir chercher des places libres quand tu créé une nouvelle unité.
* Sinon tu peux coder ta propre liste chaînée (http://fr.wikipedia.org/wiki/Liste), mais je crois que niveau perf avec C# c'est pas forcément mieux que les ArrayList.
 
M'enfin comme on dit souvent dans le métier : "Eviter d'optimiser trop tôt". En gros, je serais toi, je commencerais avec le plus simple, et je verrais à améliorer après.
Si tu veux profiter pleinement de la puissance de l'objet et pouvoir faire tes modif plus tard sans avoir à repasser dans tout ton code, je te conseille de faire une classe vide 'MonTableauRedimensionnable' qui hérite de ArrayList. Comme ça le jour où tu changes, tu n'auras qu'une seule classe à refaire, et en attendant d'avoir des pb de perf, tu peux avancer !


---------------
Tout est normal, suffit de comprendre pourquoi.
n°1297403
Arjuna
Aircraft Ident.: F-MBSD
Posté le 02-02-2006 à 14:41:58  profilanswer
 

c pas faux ça :D

n°1303279
Profil sup​primé
Posté le 10-02-2006 à 21:17:02  answer
 

Salut Harkonnen
 
Simple question : le GDI avec C# c'est plus simple qu'avec les MFC ou c'est aussi chiant ?

n°1303294
Mackila
Posté le 10-02-2006 à 22:01:40  profilanswer
 

Spa con ct'histoire de double buffering, rajouterai ca (dans 10 jours, la je suis en vacances  :sol:  ) dans le projet du taff pour éviter le clignotement lors du raffraichissement...
 
Sinon, pour répondre à ProblemSomewhere, ca fait pas longtemps que je fais du GDI+/MFC, mais je trouve ca assez sympa à utiliser (en même temps, c'est la première fois que j'ai à dessiner des trucs moi même sur une interface windows...).

n°1303335
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 11-02-2006 à 02:11:10  profilanswer
 


Salut,
c'est largement plus simple à utiliser. les classes de .NET étant bien mieux faites que les MFC, c'est un régal de faire du GDI+ en .NET


---------------
J'ai un string dans l'array (Paris Hilton)
n°1303549
Profil sup​primé
Posté le 11-02-2006 à 19:32:24  answer
 

C'est bon à savoir.  
 
Je vais pouvoir me former sur mon temps libre (de chômeur). Vue la demande (quasi exclusivement destinées aux BAC+4/5) mettant en oeuvre UML/.NET/J2EE/Web services, ça ne sera probablement pas une mauvaise idée. ;)
 
Il faut que je me mette à Eclipse aussi. :o


Message édité par Profil supprimé le 11-02-2006 à 19:33:20
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C#/.NET managed

  [C#] GDI : Redessiner une partie de la fenêtre sur OnPaint

 

Sujets relatifs
[C++] La fenêtre est "attirée" par le bord de l'écran (comme WinAmp)Transparence d'une fenetre
delphi lancer une fenêtre doscomment vider la fenetre
Rafraichissement fenetre video windows media playerPartie privée
[Java] Extraire une partie d'imageréférence d'une partie d'un code dans une page
hyperlien qui ferme une fenêtre en htmlgriser la fermeture d'une fenetre
Plus de sujets relatifs à : [C#] GDI : Redessiner une partie de la fenêtre sur OnPaint


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR