Developing with Graphics/fr: what changed
Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.
| Old | New | Line | |
|---|---|---|---|
| 1 | 1 | Cette page décrit les classes de base et les techniques pour le dessin avec Lazarus. Les questions plus spécifiques sont traitées dans des articles séparés. | |
| 2 | 2 | ||
| 3 | 3 | ## Libraries | |
| 4 | 4 | ||
| 5 | 5 | [[Graphics libraries]] - vous pouvez voir ici la liste des bibliothèques que vous pouvez utiliser pour développer. | |
| 6 | 6 | ||
| 7 | 7 | ## Autres articles sur les graphiques | |
| 8 | 8 | ||
| 9 | 9 | ### Dessin 2D | |
| 10 | 10 | ||
| 11 | 11 | - [[ZenGL/fr|ZenGL]] - Bibliothèque de développement de jeux multiplateformes utilisant OpenGL. | |
| 12 | 12 | - [[BGRABitmap]] - Dessiner des formes et des images avec transparence, accéder directement aux pixels, etc. | |
| 13 | 13 | - [[LazRGBGraphics]] - Un paquet pour de rapides manipulations de pixels et de traitement d'image en mémoire. | |
| 14 | 14 | - [[Double Gradient]] - Dessiner un gradient double et des gradients multiples facilement. | |
| 15 | 15 | - [[Gradient Filler]] - TGradientFiller permet de dessiner des gradients multiples avec Lazarus. | |
| 16 | 16 | - [[PascalMagick]] - une API facile à utiliser pour s'interfacer avec [ImageMagick](http://www.imagemagick.org), une suite libre de logiciel multiplateforme pour créer, éditer, et composer des images bitmap. | |
| 17 | 17 | ||
| 18 | 18 | ### 3D | |
| 19 | 19 | ||
| 20 | 20 | - [[GLScene/fr|GLScene]] - Portage de la librairie graphique visual OpenGL [GLScene](http://www.glscene.org). | |
| 21 | 21 | - [[Castle Game Engine/fr|Castle Game Engine]] - Un moteur libre et multiplateforme pour des jeux 3D and 2D sous FPC/Lazarus ([site officiel](http://castle-engine.sourceforge.net/engine.php)). | |
| 22 | 22 | ||
| 23 | 23 | ### Diagrammes | |
| 24 | 24 | ||
| 25 | 25 | - [[TAChart]] - Composant de diagrammes pour Lazarus | |
| 26 | 26 | - [[PlotPanel]] - Un composant de tracé de diagrammes pour des graphes animés | |
| 27 | 27 | - [[Perlin Noise/fr|Bruit de Perlin]] - Article concernant l'emploi de bruit de Perlin | |
| 28 | 28 | ||
| 29 | 29 | ## Travailler avec TBitmap | |
| 30 | 30 | ||
| 31 | 31 | Sur certains systèmes, les données des images ne sont pas stockées dans la mémoire locale si bien qu'il n'est pas possible d'y accéder directement. Comme Lazarus est fait pour être indépendant de la plateforme, la classe *TBitmap* ne fournit pas de propriété comme *Scanline*. Ce serait possible, mais cela nécessiterait une conversion implicite de l'image. Il y a une fonction *GetDataLineStart*, équivalente à *Scanline*, mais disponible uniquement pour les images en mémoire comme *TLazIntfImage* qui utilise en interne un objet *TRawImage*. | |
| 32 | 32 | ||
| 33 | 33 | En résumé, on ne peut changer une image qu'indirectement, en modifiant une image en mémoire, et ensuite en la convertissant en une image dessinable. Ce processus est bien entendu plus lent. Il y a des librairies qui permettent d'accéder directement à des images, mais elles peuvent utiliser implicitement une conversion lorsqu'on les dessine (voir [[BGRABitmap/fr|BGRABitmap]], [[LazRGBGraphics/fr|LazRGBGraphics]] et peut-être un jour [[Current conversion projects/fr|Graphics32]]). | |
| 34 | 34 | ||
| 35 | 35 | Note : quand vous créez une image, vous devez spécifier une hauteur et une largeur, sinon sa taille sera égale à zéro et rien ne sera dessiné. | |
| 36 | 36 | ||
| 37 | 37 | ### Un exemple de fading | |
| 38 | 38 | ||
| 39 | 39 | Voilà un exemple où l'on fait apparaître progressivement une image (*fade in*). Sous Delphi, vous pouvez le faire ainsi : | |
| 40 | 40 | ||
| 41 | 41 | ``` pascal | |
| 42 | 42 | procedure TForm1.FadeIn(ABitmap: TBitmap); | |
| 43 | 43 | Const NbSteps = 32; //pour simplifier l'instruction 'div' | |
| 44 | 44 | var | |
| 45 | 45 | FadeBmp, CopyBmp: TBitmap; | |
| 46 | 46 | PFade, PCopy: PRGBTriple; | |
| 47 | 47 | x, y: integer; | |
| 48 | 48 | Step: Longword; | |
| 49 | 49 | begin | |
| 50 | 50 | //faire une copie 24-bit de l'image à faire apparaître | |
| 51 | 51 | CopyBmp := TBitmap.Create; | |
| 52 | 52 | CopyBmp.PixelFormat := pf24bit; | |
| 53 | 53 | CopyBmp.Width := ABitmap.Width; | |
| 54 | 54 | CopyBmp.Height := ABitmap.Height; | |
| 55 | 55 | CopyBmp.Canvas.Draw(0,0,ABitmap); | |
| 56 | 56 | ||
| 57 | 57 | //créer une image pour le fading | |
| 58 | 58 | FadeBmp := TBitmap.Create; | |
| 59 | 59 | FadeBmp.PixelFormat := pf24bit; | |
| 60 | 60 | FadeBmp.Width := ABitmap.Width; | |
| 61 | 61 | FadeBmp.Height := ABitmap.Height; | |
| 62 | 62 | ||
| 63 | 63 | for step := 0 to NbSteps do //boucle principale | |
| 64 | 64 | begin | |
| 65 | 65 | for y := 0 to FadeBmp.Height - 1 do | |
| 66 | 66 | begin | |
| 67 | 67 | PCopy := CopyBmp.Scanline[y]; | |
| 68 | 68 | PFade := FadeBmp.Scanline[y]; | |
| 69 | 69 | for x := 0 to FadeBmp.Width - 1 do | |
| 70 | 70 | begin | |
| 71 | 71 | PFade^.rgbtRed := (step * PCopy^.rgbtRed) div NbSteps; | |
| 72 | 72 | PFade^.rgbtGreen := (step * PCopy^.rgbtGreen) div NbSteps; // calcul de fading | |
| 73 | 73 | PFade^.rgbtBlue := (step * PCopy^.rgbtBlue) div NbSteps; | |
| 74 | 74 | inc(PCopy); // aller au pixel suivant | |
| 75 | 75 | inc(PFade); | |
| 76 | 76 | end; | |
| 77 | 77 | end; | |
| 78 | 78 | Form1.Canvas.Draw(0, 0, FadeBmp); | |
| 79 | 79 | Sleep(16); // attendre un cycle d'écran | |
| 80 | 80 | Application.ProcessMessages; // gérer les messages Windows | |
| 81 | 81 | end; | |
| 82 | 82 | ||
| 83 | 83 | FadeBmp.Free; | |
| 84 | 84 | CopyBmp.Free; | |
| 85 | 85 | end; | |
| 86 | 86 | ``` | |
| 87 | 87 | ||
| 88 | 88 | Cette fonction peut être implémentée comme suit avec les bibliothèques incluses dans Lazarus : | |
| 89 | 89 | ||
| 90 | 90 | ``` pascal | |
| 91 | 91 | { Ce code a été copié du projet à l'emplacement $LazarusPath/examples/lazintfimage/fadein1.lpi } | |
| 92 | 92 | uses LCLType, // HBitmap type | |
| 93 | 93 | IntfGraphics, // TLazIntfImage type | |
| 94 | 94 | fpImage; // TFPColor type | |
| 95 | 95 | ... | |
| 96 | 96 | procedure TForm1.FadeIn(ABitMap: TBitMap); | |
| 97 | 97 | var | |
| 98 | 98 | SrcIntfImg, TempIntfImg: TLazIntfImage; | |
| 99 | 99 | ImgHandle,ImgMaskHandle: HBitmap; | |
| 100 | 100 | FadeStep: Integer; | |
| 101 | 101 | px, py: Integer; | |
| 102 | 102 | CurColor: TFPColor; | |
| 103 | 103 | TempBitmap: TBitmap; | |
| 104 | 104 | begin | |
| 105 | 105 | //crée une copie de l'image dans un objet TLazIntfImage | |
| 106 | 106 | SrcIntfImg:=TLazIntfImage.Create(0,0); | |
| 107 | 107 | SrcIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle); | |
| 108 | 108 | //crée une image avec les mêmes dimensions pour faire le fading | |
| 109 | 109 | TempIntfImg:=TLazIntfImage.Create(0,0); | |
| 110 | 110 | TempIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle); | |
| 111 | 111 | ||
| 112 | 112 | //crée un objet Bitmap de destination pour l'affichage | |
| 113 | 113 | TempBitmap:=TBitmap.Create; | |
| 114 | 114 | for FadeStep:=1 to 32 do begin //boucle principale | |
| 115 | 115 | for py:=0 to SrcIntfImg.Height-1 do begin | |
| 116 | 116 | for px:=0 to SrcIntfImg.Width-1 do begin | |
| 117 | 117 | CurColor:=SrcIntfImg.Colors[px,py]; //lire la couleur source | |
| 118 | 118 | CurColor.Red:=(CurColor.Red*FadeStep) shr 5; | |
| 119 | 119 | CurColor.Green:=(CurColor.Green*FadeStep) shr 5; //calcul de fading | |
| 120 | 120 | CurColor.Blue:=(CurColor.Blue*FadeStep) shr 5; | |
| 121 | 121 | TempIntfImg.Colors[px,py]:=CurColor; | |
| 122 | 122 | end; | |
| 123 | 123 | end; | |
| 124 | 124 | //création des handles pour l'image temporaire | |
| 125 | 125 | TempIntfImg.CreateBitmaps(ImgHandle,ImgMaskHandle,false); | |
| 126 | 126 | TempBitmap.Handle:=ImgHandle; | |
| 127 | 127 | TempBitmap.MaskHandle:=ImgMaskHandle; | |
| 128 | 128 | Canvas.Draw(0,0,TempBitmap); //dessin de l'image | |
| 129 | 129 | end; | |
| 130 | 130 | SrcIntfImg.Free; | |
| 131 | 131 | TempIntfImg.Free; | |
| 132 | 132 | TempBitmap.Free; | |
| 133 | 133 | end; | |
| 134 | 134 | ``` | |
| 135 | 135 | ||
| 136 | 136 | En utilisant BGRABitmap, le fading peut être implémenté comme suit : | |
| 137 | 137 | ||
| 138 | 138 | ``` pascal | |
| 139 | 139 | procedure TForm1.FadeIn3(ABitmap: TBitmap); | |
| 140 | 140 | Const NbSteps = 32; | |
| 141 | 141 | var | |
| 142 | 142 | CopyBmp,FadeBmp: TBGRABitmap; | |
| 143 | 143 | PFade, PSource: PBGRAPixel; | |
| 144 | 144 | n, step: Longword; | |
| 145 | 145 | begin | |
| 146 | 146 | //crée une copie de l'image avec accès direct aux pixels | |
| 147 | 147 | CopyBmp := TBGRABitmap.Create(ABitmap.Canvas); | |
| 148 | 148 | ||
| 149 | 149 | //crée une image pour le fading | |
| 150 | 150 | FadeBmp := TBGRABitmap.Create(ABitmap.Width,ABitmap.Height); | |
| 151 | 151 | ||
| 152 | 152 | for step := 0 to NbSteps do //boucle principale | |
| 153 | 153 | begin | |
| 154 | 154 | PSource := CopyBmp.Data; | |
| 155 | 155 | PFade := FadeBmp.Data; | |
| 156 | 156 | for n := 0 to FadeBmp.NbPixels - 1 do | |
| 157 | 157 | begin | |
| 158 | 158 | PFade^.red := (step * PSource^.red) div NbSteps; | |
| 159 | 159 | PFade^.green := (step * PSource^.green) div NbSteps; // calcul de fading | |
| 160 | 160 | PFade^.blue := (step * PSource^.blue) div NbSteps; | |
| 161 | 161 | inc(PSource); // aller au pixel suivant | |
| 162 | 162 | inc(PFade); | |
| 163 | 163 | end; | |
| 164 | 164 | FadeBmp.InvalidateBitmap; // note qu'on a changé par accès direct | |
| 165 | 165 | FadeBmp.Draw(Form1.Canvas,0,0,true); // affiche l'image calculée en mode opaque | |
| 166 | 166 | Sleep(16); // attendre un cycle d'écran | |
| 167 | 167 | Application.ProcessMessages; // gérer les événements | |
| 168 | 168 | end; | |
| 169 | 169 | ||
| 170 | 170 | FadeBmp.Free; | |
| 171 | 171 | CopyBmp.Free; | |
| 172 | 172 | end; | |
| 173 | 173 | ``` | |
| 174 | 174 | ||
| 175 | 175 | ### Tracer des bitmaps avec une couleur transparente | |
| 176 | 176 | ||
| 177 | 177 | Un nouveau dispositif, implémenté avec Lazarus 0.9.11, réside dans les bitmaps en couleurs transparentes. les fichiers Bitmap (*.BMP) ne peuvent stocker aucune information sur la transparence, mais ils peuvent fonctionner comme s'ils en avaient si vous choisissez une couleur sur eux pour représenter le secteur transparent. C'est une astuce courante utilisée dans les applications Win32. | |
| 178 | 178 | ||
| 179 | 179 | L'exemple suivant charge un Bitmap à partir d'une ressource Windows, choisit une couleur pour être transparente (*clFuchsia*) et le dessine ensuite sur le canevas. | |
| 180 | 180 | ||
| 181 | 181 | ``` pascal | |
| 182 | 182 | procedure MyForm.MyButtonOnClick(Sender: TObject); | |
| 183 | 183 | var | |
| 184 | 184 | buffer: THandle; | |
| 185 | 185 | bmp: TBitmap; | |
| 186 | 186 | memstream: TMemoryStream; | |
| 187 | 187 | begin | |
| 188 | 188 | bmp := TBitmap.Create; | |
| 189 | 189 | ||
| 190 | 190 | buffer := Windows.LoadBitmap(hInstance, MAKEINTRESOURCE(ResourceID)); | |
| 191 | 191 | ||
| 192 | 192 | if (buffer = 0) then exit; // Error loading the bitmap | |
| 193 | 193 | ||
| 194 | 194 | bmp.Handle := buffer; | |
| 195 | 195 | memstream := TMemoryStream.create; | |
| 196 | 196 | try | |
| 197 | 197 | bmp.SaveToStream(memstream); | |
| 198 | 198 | memstream.position := 0; | |
| 199 | 199 | bmp.LoadFromStream(memstream); | |
| 200 | 200 | finally | |
| 201 | 201 | memstream.free; | |
| 202 | 202 | end; | |
| 203 | 203 | ||
| 204 | 204 | bmp.Transparent := True; | |
| 205 | 205 | bmp.TransparentColor := clFuchsia; | |
| 206 | 206 | ||
| 207 | 207 | MyCanvas.Draw(0, 0, bmp); | |
| 208 | 208 | ||
| 209 | 209 | bmp.Free; // Release allocated resource | |
| 210 | 210 | end; | |
| 211 | 211 | ``` | |
| 212 | 212 | ||
| 213 | 213 | Notez les opérations de mémoire effectuées avec [[doc:rtl/classes/tmemorystream.html|TMemoryStream]]. Elles sont nécessaires pour assurer le chargement correct de l'image. | |
| 214 | 214 | ||
| 215 | 215 | ### Faire une capture d'image de l'écran | |
| 216 | 216 | ||
| 217 | 217 | Depuis Lazarus 0.9.16, vous pouvez employer la LCL pour faire des captures d'images de l'écran multiplateforme. Le code d'exemple suivant le fait (fonctionne avec gtk2 et win32, mais non gtk1 actuellement) : | |
| 218 | 218 | ||
| 219 | 219 | ``` pascal | |
| 220 | 220 | uses LCLIntf, LCLType; | |
| 221 | 221 | ||
| 222 | 222 | ... | |
| 223 | 223 | ||
| 224 | 224 | var | |
| 225 | 225 | MyBitmap: TBitmap | |
| 226 | 226 | ScreenDC: HDC; | |
| 227 | 227 | begin | |
| 228 | 228 | MyBitmap := TBitmap.Create; | |
| 229 | 229 | ScreenDC := GetDC(0); | |
| 230 | 230 | MyBitmap.LoadFromDevice(ScreenDC); | |
| 231 | 231 | ReleaseDC(ScreenDC); | |
| 232 | 232 | ||
| 233 | 233 | ... | |
| 234 | 234 | ``` | |
| 235 | 235 | ||
| 236 | 236 | ## Graphiques en mouvement - Comment éviter le clignotement | |
| 237 | 237 | ||
| 238 | 238 | Beaucoup de programmes dessinent leur sortie sur le GUI sous forme de graphiques 2D. Si ces graphiques ont besoin de changer rapidement vous ferez face bientôt à un problème : les graphiques changeant rapidement clignotent souvent sur l'écran. Ceci se produit quand les utilisateurs voient parfois des images entières et parfois seulement quand c'est dessiné partiellement. Cela se produit parce que le procédé d'affichage a besoin de temps. | |
| 239 | 239 | ||
| 240 | 240 | Mais comment puis je éviter le clignotement et obtenir la meilleure vitesse de dessin ? Naturellement vous pourriez travailler avec l'accélération matérielle en utilisant OpenGL, mais cette approche est tout à fait lourde pour de petits programmes ou de vieux ordinateurs. Ce tutoriel se concentrera sur la façon de dessiner sur un TCanvas. Si vous avez besoin d'aide avec OpenGL, jeter un coup d'oeil sur l'exemple qui vient avec Lazarus. Vous pouvez également employer le gamepack d'A.J. Venter, qui fourni un canvas à double-tampon et un composant de sprite. | |
| 241 | 241 | ||
| 242 | 242 | Maintenant nous examinerons les options que nous avons pour dessiner un canvas : | |
| 243 | 243 | ||
| 244 | 244 | - Dessiner sur un Timage | |
| 245 | 245 | - Dessiner sur l'evènement OnPaint de la fiche, un contrôle TPaintBox ou un autre | |
| 246 | 246 | - Créer un contrôle à soi qui se dessine lui-même | |
| 247 | 247 | - Employer le gamepack d'A.J. Venter | |
| 248 | 248 | ||
| 249 | 249 | ### Dessiner sur un Timage | |
| 250 | 250 | ||
| 251 | 251 | Un TImage se compose en 2 parts : un TGraphic, habituellement un TBitmap, contenant l'image persistante et l'aire visuelle, laquelle est peinte à chaque OnPaint. Redimensionner le TImage **ne** redimensionne pas le bitmap. Le graphique (ou bitmap) est accessible par l'intermédiaire de Image1.Picture.Graphic (ou Image1.Picture.Bitmap). La canvas est Image1.Picture.Bitmap.Canvas. Le canvas de l'aire visuelle d'une TImage est seulement accessible pendant Image1.OnPaint via Image1.Canvas. | |
| 252 | 252 | ||
| 253 | 253 | **Important** : Ne jamais employer le OnPaint de l'évènement Image1 pour dessiner le graphique/bitmap d'une TImage. Le graphique d'une TImage est en mémoire tampon aussi tout que vous devez faire est de dessiner vers elle de n'importe où et le changement est là pour toujours. Cependant, si vous redessinez constamment, l'image clignotera. Dans ce cas-ci vous pouvez essayer les autres options. Dessin sur une TImage est considéré comme étant plus lent que les autres approches. | |
| 254 | 254 | ||
| 255 | 255 | #### Redimensionner le bitmap d'un TImage | |
| 256 | 256 | ||
| 257 | 257 | Note : Ne pas employer ceci pendant OnPaint. | |
| 258 | 258 | ||
| 259 | 259 | ` with Image1.Picture.Bitmap do begin`\ | |
| 260 | 260 | ` Width:=100;`\ | |
| 261 | 261 | ` Height:=120;`\ | |
| 262 | 262 | ` end;` | |
| 263 | 263 | ||
| 264 | 264 | #### Peindre sur le bitmap d'un TImage | |
| 265 | 265 | ||
| 266 | 266 | Note: Ne pas employer ceci pendant OnPaint. | |
| 267 | 267 | ||
| 268 | 268 | ` with Image1.Picture.Bitmap.Canvas do begin`\ | |
| 269 | 269 | ` // fill the entire bitmap with red`\ | |
| 270 | 270 | ` Brush.Color:=clRed;`\ | |
| 271 | 271 | ` FillRect(0,0,Width,Height);`\ | |
| 272 | 272 | ` end;` | |
| 273 | 273 | ||
| 274 | 274 | Note : À l'intérieur de Image1.OnPaint Image1.Canvas pointe vers l'aire visible volatile. En dehors de Image1.OnPaint l'Image1.Canvas pointe vers Image1.Picture.Bitmap.Canvas. | |
| 275 | 275 | ||
| 276 | 276 | Un autre exemple : | |
| 277 | 277 | ||
| 278 | - | ||
| 279 | - | ||
| 280 | 278 | `procedure TForm1.BitBtn1Click(Sender: TObject);`\ | |
| 281 | 279 | `var`\ | |
| 282 | 280 | ` x, y: Integer;`\ | |
| 283 | 281 | `begin`\ | |
| 284 | 282 | ` // Draws the backgroung`\ | |
| 285 | 283 | ` MyImage.Canvas.Pen.Color := clWhite;`\ | |
| 286 | 284 | ` MyImage.Canvas.Rectangle(0, 0, Image.Width, Image.Height);`\ | |
| 287 | 285 | ` `\ | |
| 288 | 286 | ` // Draws squares`\ | |
| 289 | 287 | ` MyImage.Canvas.Pen.Color := clBlack;`\ | |
| 290 | 288 | ` for x := 1 to 8 do`\ | |
| 291 | 289 | ` for y := 1 to 8 do`\ | |
| 292 | 290 | ` MyImage.Canvas.Rectangle(Round((x - 1) * Image.Width / 8), Round((y - 1) * Image.Height / 8),`\ | |
| 293 | 291 | ` Round(x * Image.Width / 8), Round(y * Image.Height / 8));`\ | |
| 294 | 292 | `end;` | |
| 295 | 293 | ||
| 296 | - | ||
| 297 | - | ||
| 298 | 294 | #### Peindre sur l'aire visuelle volatile de TImage | |
| 299 | 295 | ||
| 300 | 296 | Vous pouvez seulement peindre sur ce secteur pendant OnPaint. OnPaint est éventuellement appellé automatiquement par la LCL quand le secteur a été invalidé. Vous pouvez invalidé manuellement le secteur avec Image1.Invalidate. Ceci n'appellera pas immédiatement OnPaint et vous pouvez appeler Invalidate autant de fois que vous le voulez. | |
| 301 | 297 | ||
| 302 | 298 | ` procedure TForm.Image1Paint(Sender: TObject);`\ | |
| 303 | 299 | ` begin`\ | |
| 304 | 300 | ` with Image1.Canvas do begin`\ | |
| 305 | 301 | ` // paint a line`\ | |
| 306 | 302 | ` Pen.Color:=clRed;`\ | |
| 307 | 303 | ` Line(0,0,Width,Height);`\ | |
| 308 | 304 | ` end;`\ | |
| 309 | 305 | ` end;` | |
| 310 | 306 | ||
| 311 | 307 | ### Dessiner sur l'évênement OnPaint | |
| 312 | 308 | ||
| 313 | 309 | Dans ce cas tout le dessin doit être fait sur l'évênement OnPaint de la fiche. Il ne reste pas sur le tampon, comme sur la TImage. | |
| 314 | 310 | ||
| 315 | 311 | ### Créer un contrôle à soi qui se dessine lui-même | |
| 316 | 312 | ||
| 317 | 313 | Créer un contrôle à soi a l'avantage de structurer votre code, et vous pouvez réutiliser le contrôle. Cette approche est très rapide, mais elle peut toujours produire du clignotement si vous ne dessinez pas sur un TBitmap en premier et dessinez ensuite sur le canvas. Dans ce cas, il n'est pas besoin d'employer l'évènement OnPaint du contrôle. | |
| 318 | 314 | ||
| 319 | 315 | Voici un exemple de contrôle personnalisé: | |
| 320 | 316 | ||
| 321 | - | ||
| 322 | - | ||
| 323 | 317 | `uses`\ | |
| 324 | 318 | ` Classes, SysUtils, Controls, Graphics, LCLType;`\ | |
| 325 | - | ||
| 319 | + | ||
| 326 | 320 | `type`\ | |
| 327 | 321 | ` TMyDrawingControl = class(TCustomControl)`\ | |
| 328 | 322 | ` public`\ | |
| 329 | 323 | ` procedure EraseBackground(DC: HDC); override;`\ | |
| 330 | 324 | ` procedure Paint; override;`\ | |
| 331 | 325 | ` end;`\ | |
| 332 | - | ||
| 326 | + | ||
| 333 | 327 | `implementation`\ | |
| 334 | - | ||
| 328 | + | ||
| 335 | 329 | `procedure TMyDrawingControl.EraseBackground(DC: HDC);`\ | |
| 336 | 330 | `begin`\ | |
| 337 | 331 | ` // Uncomment this to enable default background erasing`\ | |
| 338 | 332 | ` //inherited EraseBackground(DC);`\ | |
| 339 | 333 | `end; `\ | |
| 340 | - | ||
| 334 | + | ||
| 341 | 335 | `procedure TMyDrawingControl.Paint;`\ | |
| 342 | 336 | `var`\ | |
| 343 | 337 | ` x, y: Integer;`\ | |
| 344 | 338 | ` Bitmap: TBitmap;`\ | |
| 345 | 339 | `begin`\ | |
| 346 | 340 | ` Bitmap := TBitmap.Create;`\ | |
| 347 | 341 | ` try`\ | |
| 348 | 342 | ` // Initializes the Bitmap Size`\ | |
| 349 | 343 | ` Bitmap.Height := Height;`\ | |
| 350 | 344 | ` Bitmap.Width := Width;`\ | |
| 351 | 345 | ` `\ | |
| 352 | 346 | ` // Draws the background`\ | |
| 353 | 347 | ` Bitmap.Canvas.Pen.Color := clWhite;`\ | |
| 354 | 348 | ` Bitmap.Canvas.Rectangle(0, 0, Width, Height);`\ | |
| 355 | - | ||
| 349 | + | ||
| 356 | 350 | ` // Draws squares`\ | |
| 357 | 351 | ` Bitmap.Canvas.Pen.Color := clBlack;`\ | |
| 358 | 352 | ` for x := 1 to 8 do`\ | |
| 359 | 353 | ` for y := 1 to 8 do`\ | |
| 360 | 354 | ` Bitmap.Canvas.Rectangle(Round((x - 1) * Width / 8), Round((y - 1) * Height / 8),`\ | |
| 361 | 355 | ` Round(x * Width / 8), Round(y * Height / 8));`\ | |
| 362 | 356 | ` `\ | |
| 363 | 357 | ` Canvas.Draw(0, 0, Bitmap);`\ | |
| 364 | 358 | ` finally`\ | |
| 365 | 359 | ` Bitmap.Free;`\ | |
| 366 | 360 | ` end;`\ | |
| 367 | - | ||
| 361 | + | ||
| 368 | 362 | ` inherited Paint;`\ | |
| 369 | 363 | `end;` | |
| 370 | 364 | ||
| 371 | - | ||
| 365 | + | ...et la manière de le créer dans la fiche. | |
| 372 | 366 | ||
| 373 | 367 | `procedure TMyForm.FormCreate(Sender: TObject);`\ | |
| 374 | 368 | `begin`\ | |
| 375 | 369 | ` MyDrawingControl:= TMyDrawingControl.Create(Self);`\ | |
| 376 | 370 | ` MyDrawingControl.Height := 400;`\ | |
| 377 | 371 | ` MyDrawingControl.Width := 500;`\ | |
| 378 | 372 | ` MyDrawingControl.Top := 0;`\ | |
| 379 | 373 | ` MyDrawingControl.Left := 0;`\ | |
| 380 | 374 | ` MyDrawingControl.Parent := Self;`\ | |
| 381 | 375 | ` MyDrawingControl.DoubleBuffered := True;`\ | |
| 382 | 376 | `end;` | |
| 383 | 377 | ||
| 384 | - | ||
| 378 | + | N'oubliez pas de le détruire : | |
| 385 | 379 | ||
| 386 | 380 | `procedure TMyForm.FormDestroy(Sender: TObject);`\ | |
| 387 | 381 | `begin`\ | |
| 388 | 382 | ` MyDrawingControl.Free;`\ | |
| 389 | 383 | `end;` | |
| 390 | - | ||
| 391 | - | ||
| 392 | 384 | ||
| 393 | 385 | Paramétrer Top et Left à zéro n'est pas nécessaire, puisque c'est la position standard, mais est fait pour renforcer l'endroit où le contrôle sera mis. | |
| 394 | 386 | ||
| 395 | 387 | "MyDrawingControl.Parent := Self;" est très important et vous ne verrez pas votre contrôle si vous ne faites pas ainsi. | |
| 396 | 388 | ||
| 397 | 389 | "MyDrawingControl.DoubleBuffered := True;" est nécessaire pour éviter le clignotement sur Windows. Il n'a aucun effet sur gtk. | |
| 398 | 390 | ||
| 399 | 391 | ### Employer le gamepack d'A.J. Venter | |
| 400 | 392 | ||
| 401 | 393 | L'approche par gamepack est de tout dessiner sur un canvas à double-tampon, lequel se met seulement à jour sur le canvas visible quand vous êtes prêt. Ceci demande beaucoup de code, mais il a l'avantage de pouvoir faire de grandes scènes avec de multiples sprites changeant rapidement. Si vous souhaitez employer cette approche, vous pouvez être intéressés par le A.J. Venter's gamepack, un ensemble de composants pour le développement de jeu dans Lazarus, qui fournit un composant avec une zone de visualisation avec double-tampon ainsi qu'un composant de sprite, conçu pour bien s'intégrer entre eux. Vous pouvez obtenir gamepack via SVN :\ | |
| 402 | 394 | `svn co `[`svn://silentcoder.co.za/lazarus/gamepack`](svn://silentcoder.co.za/lazarus/gamepack) | |
| 403 | 395 | ||
| 404 | 396 | --- | |
| 405 | 397 | *From the Free Pascal wiki, page "Developing with Graphics/fr", as it stood on 2020-02-13 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
