Forum > LCL
Painting on a control - 3 questions: OnPaint, ImageList, program logic
majolika:
Hello!
I have three newbies question about painting on a control.
For the educational purposes I'm programming a mine sweeper game.
1st question: OnPaint
When I click on a start buttion I show a mine field and fill it with squares. Then I click on the mine field and show a mine. But the mine field fully repaint and my squares is gone. Why?
2nd question: ImageList
ImageList is very usefull control but I found one strange thing: when I'm drawing an same image with ImageList and with Canvas.Draw it gives me different results. Why?
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---ImageList1.Resolution[24].Draw(Bevel1.Canvas, x, y, 0, True);
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---MineField.Canvas.Draw(x, y, Picture_Loaded_From_TImage_Placed_On_The_Form);
I attached screenshot to show the difference: left, brighter mine field — ImageList, right, darker — Canvas.Draw
3rd question: program logic
First click on the start button works well but the second doesn't work at all. Why?
Here's the minimal proof-of-concept code:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit test_unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Bevel1: TBevel; Button1: TButton; ImageList1: TImageList; procedure Bevel1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Bevel1Paint(Sender: TObject); procedure Button1Click(Sender: TObject); private public end; var Form1: TForm1; BoxSize: Integer = 24; FieldRow: integer = 10; FieldCol: integer = 10; Button1Clicked: Boolean = False; DrawABomb: Boolean = False; CoordX, CoordY: Integer; implementation {$R *.lfm} procedure TForm1.Button1Click(Sender: TObject);begin Button1Clicked := True; Bevel1.Width := FieldCol * BoxSize; Bevel1.Height := FieldRow * BoxSize; Bevel1.Show;end; procedure TForm1.Bevel1Paint(Sender: TObject);var x, y: Integer;begin if Button1Clicked then begin for x := 0 to FieldCol - 1 do begin for y := 0 to FieldRow - 1 do begin ImageList1.Resolution[24].Draw(Bevel1.Canvas, (x * BoxSize), (y * BoxSize), 0, True); end; end; Button1Clicked := False; end; if DrawABomb then begin ImageList1.Resolution[24].Draw(Bevel1.Canvas, CoordX, CoordY, 1, True); DrawABomb := False; end;end; procedure TForm1.Bevel1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);begin if Button = mbLeft then begin DrawABomb := True; CoordX := X; CoordY := Y; Bevel1.Repaint; end;end; end.
ASerge:
--- Quote from: majolika on January 22, 2025, 04:55:52 pm ---1st question: OnPaint
When I click on a start buttion I show a mine field and fill it with squares. Then I click on the mine field and show a mine. But the mine field fully repaint and my squares is gone. Why?
--- End quote ---
It is better to use TPaintBox.
In the OnPaint handler, assume that all the content is corrupted and incorrect. Based on this, build the logic of rendering.
majolika:
--- Quote from: ASerge on January 22, 2025, 05:36:36 pm ---It is better to use TPaintBox.
--- End quote ---
Thanks! I'll try and be back later to say if it works for me.
majolika:
--- Quote from: ASerge on January 22, 2025, 05:36:36 pm ---It is better to use TPaintBox.
--- End quote ---
No, if I simply replace TBevel with TPaintBox it's not working. Attached pics demonstrates three steps with TBevel (show mine) and PaintBox (show no mine).
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit test2_unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls; type TForm1 = class(TForm) Button1: TButton; ImageList1: TImageList; PaintBox1: TPaintBox; procedure Button1Click(Sender: TObject); procedure PaintBox1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure PaintBox1Paint(Sender: TObject); private public end; var Form1: TForm1; BoxSize: Integer = 24; FieldRow: integer = 10; FieldCol: integer = 10; Button1Clicked: Boolean = False; DrawABomb: Boolean = False; FieldWidth, FieldHeight: Integer; implementation {$R *.lfm} procedure TForm1.Button1Click(Sender: TObject);begin Button1Clicked := True; PaintBox1.Width := FieldCol * BoxSize; PaintBox1.Height := FieldRow * BoxSize;end; procedure TForm1.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);begin if Button = mbLeft then begin DrawABomb := True; PaintBox1.Repaint; end;end; procedure TForm1.PaintBox1Paint(Sender: TObject);var x, y: integer;begin if Button1Clicked then begin for x := 0 to FieldCol - 1 do begin for y := 0 to FieldRow - 1 do begin ImageList1.Resolution[24].Draw(PaintBox1.Canvas, (x * BoxSize), (y * BoxSize), 0, True); end; end; Button1Clicked := False; end; if DrawABomb then begin ImageList1.Resolution[24].Draw(PaintBox1.Canvas, x, y, 1, True); DrawABomb := False; end;end; end.
--- Quote from: ASerge on January 22, 2025, 05:36:36 pm ---In the OnPaint handler, assume that all the content is corrupted and incorrect. Based on this, build the logic of rendering.
--- End quote ---
I found a simplistic clone of MS Paint on Github. It seems that author creates a bitmap in memory, in OnMouseUp/Down/Move draws something on top of this bitmap and then in OnPaint just put the whole bitmap on the PaintBox. But it's kinda wierd solution. Why are the things so complicated?!
ASerge:
--- Quote from: majolika on January 22, 2025, 07:23:14 pm ---It seems that author creates a bitmap in memory, in OnMouseUp/Down/Move draws something on top of this bitmap and then in OnPaint just put the whole bitmap on the PaintBox. But it's kinda wierd solution. Why are the things so complicated?!
--- End quote ---
It just caches a lot of drawings on a separate bitmap. To speed up. But the principle remains the same - redraw each time.
Navigation
[0] Message Index
[#] Next page