* * *

Author Topic: Drawing lines and primitives  (Read 11408 times)

FreeMind

  • New member
  • *
  • Posts: 16
Drawing lines and primitives
« on: March 30, 2009, 06:51:11 pm »
Here goes my newbyness again:
I can't seem to find this on the net. I create an application with a form. Where could i find the functions to draw simple coloured lines on forms?

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 820
    • Burdjia
Re: Drawing lines and primitives
« Reply #1 on: March 30, 2009, 07:54:41 pm »
You can't draw directly on a form. (Ok, actually you can, but that's not a good idea, trust me).

To draw on a form first add a TPaintBox (at "Additonal" tab), align it to client area. Now use the search to find how to draw on a TPaintBox. ;)
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

FreeMind

  • New member
  • *
  • Posts: 16
Re: Drawing lines and primitives
« Reply #2 on: March 31, 2009, 07:17:57 pm »
Thank you very much.
And now... er... When i draw my lines in the "paint" event, they are refreshed only when i rescale the window. Is there any way to redraw on screen refresh?

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 820
    • Burdjia
Re: Drawing lines and primitives
« Reply #3 on: March 31, 2009, 09:08:53 pm »
I think you should read this document. It will learn you how to use graphics with Lazarus.
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

FreeMind

  • New member
  • *
  • Posts: 16
Re: Drawing lines and primitives
« Reply #4 on: March 31, 2009, 10:41:08 pm »
Still. I didn't find what i needed in that page... Thanks anyway.
The problem remains:

I am drawing a line in the paint event. The line position is random (just to test the refreshing). So, when the program runs, that lines stands still, which means, that the paint event happens only once. Only when i rescale the window, the line starts jumping into random positions.

Is there any way i can make the line refresh whenever i tell it to, for ehample, every two screen refreshes or somethin? I can't see any loops in this code....

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 820
    • Burdjia
Re: Drawing lines and primitives
« Reply #5 on: April 01, 2009, 01:13:47 am »
Is there any way i can make the line refresh whenever i tell it to, for ehample, every two screen refreshes or somethin? I can't see any loops in this code....
So you want to do an animation. That's different. And there are different ways depending on why do you do want to show an animation.

If you want to show an animation on a window you can use a TTimer object (in the "System" tab). Set the Interval in milliseconds and set it's OnTimer event to tell the windows manager you want to redraw the window and all it's content this way:
Code: [Select]
procedure TForm1.Timer1Timer(Sender: TObject);
begin
{ "SELF" means "the current object". }
  SELF.Invalidate;
end;

Actually, there's a loop inside the Run method of the Application object. It's called "the message loop" because it catches messages from the window manager and sends them to the appropriate objects. That loop is different on different platforms (Win32, X11, Cocoa, etc.).

If you're wondering how to do an "old style" animation then you shouldn't use the LCL. You should create a console application and use a different graphic library such as the one included with the Free Pascal compiler (the Graph unit) or install another one, as Allegro.pas.
« Last Edit: April 01, 2009, 01:22:19 am by Ñuño_Martínez »
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

FreeMind

  • New member
  • *
  • Posts: 16
Re: Drawing lines and primitives
« Reply #6 on: April 01, 2009, 01:29:35 pm »
Whoah, you are the best. :)
Anyway, this is redrawing the whole form, right?

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 4903
    • wiki
Re: Drawing lines and primitives
« Reply #7 on: April 01, 2009, 02:00:01 pm »
If you want to force a component (or form) to redraw, you can use the "Invalidate" method. You can call it from within a timer.

Question is why do you want to Paint inside the OnPaint event? If you use a TPaintBox, you can just paint on it, it will refresh on it's own, and your painted data persists.

The OnPaintEvent you only need if you want to interfere with the way a component draws itself. Or if you have a component that doesn't draw itself, and expects you to do so in the Paint event.

FreeMind

  • New member
  • *
  • Posts: 16
Re: Drawing lines and primitives
« Reply #8 on: April 01, 2009, 02:18:15 pm »
Question is why do you want to Paint inside the OnPaint event? If you use a TPaintBox, you can just paint on it, it will refresh on it's own, and your painted data persists.

How do you suggest painting on a Tpaintbox without the paint event? A timer?

Ok, so ive done it like this:
Code: [Select]
procedure TForm1.RedrawTimer(Sender: TObject);

begin

   TheImage := TBitmap.Create;

  TheImage.Height := UVpaint.Height;
  TheImage.Width := UVpaint.Width;
  TheImage.Canvas.Brush.Color :=$000000;
  TheImage.canvas.FillRect( Bounds(0,0,UVpaint.width,UVpaint.height));
  TheImage.Canvas.Pen.Color :=$FFFFFF;
  TheImage.canvas.MoveTo(100, 100);
  TheImage.canvas.LineTo(200, 200+random(20));
  TheImage.canvas.LineTo(100, 200+random(20));
  TheImage.canvas.LineTo(100, 100);

  TheImage.Canvas.Brush.Color :=clblue;
  TheImage.Canvas.FloodFill(110, 120, clwhite, fsBorder);
  UVpaint.Canvas.Draw(0, 0, TheImage);

  TheImage.free;
end;   

It draws and refreshes good. Though it does flicker when i rescale the window. Any tips?

Since the draw event only happens on open and on rescale, i thought i should draw the same bitmap on the draw event... But in that case i have no place to put the "TheImage.free"
« Last Edit: April 01, 2009, 04:33:43 pm by FreeMind »

arnoldb

  • Jr. Member
  • **
  • Posts: 96
Re: Drawing lines and primitives
« Reply #9 on: April 01, 2009, 03:57:26 pm »
You can paint on a TPaintbox anywhere from within your program where the paintbox is in scope.

Try the following - this will draw random lines or circles, depending on which button you click:

Create a new project.  On Form1, put a TPaintbox, a TColorListBox, a Button1 and a Button2.
Change caption for Button1 to 'Random Line', and caption for Button2 to 'Random Circle'.
Assign the following code to the OnClick events of the buttons:

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var x1,y1,x2,y2,c:integer;
    aColor:TColor;
begin
  x1:=random(PaintBox1.Width);
  x2:=random(PaintBox1.Width);
  y1:=random(PaintBox1.Height);
  y2:=random(PaintBox1.Height);
  c:=random(colorlistbox1.Items.Count);
  aColor:=ColorListBox1.Colors[c];
  With Paintbox1 do
  begin
    canvas.pen.Color :=aColor;
    canvas.Line(x1,y1,x2,y2);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var x,y,r,c:integer;
    aColor:TColor;
begin
  x:=random(PaintBox1.Width);
  y:=random(PaintBox1.Height);
  r:=random(PaintBox1.Height div 3);
  c:=random(colorlistbox1.Items.Count);
  aColor:=ColorListBox1.Colors[c];
  With Paintbox1 do
  begin
    canvas.pen.Color :=aColor;
    canvas.Brush.Color := aColor;
    canvas.EllipseC(x,y,r,r) ;
  end;
end;                 

Compile & Run.  Each time you click a button, something will happen on the paintbox.  I was just lazy and used the TColorListBox to get a random range of colours.

You can even add a timer, and in it's OnTimer event add the same.

Not a very practical example, but it might help you.

FreeMind

  • New member
  • *
  • Posts: 16
Re: Drawing lines and primitives
« Reply #10 on: April 01, 2009, 05:14:35 pm »
I guess i found a perfect way of doing it:

Code: [Select]
procedure TForm1.FormCreate(Sender: TObject);
begin
   TheImage := TBitmap.Create;
end;

procedure TForm1.RedrawTimer(Sender: TObject);

begin
  TheImage.free;
  TheImage := TBitmap.Create;

  TheImage.Height := UVpaint.Height;
  TheImage.Width := UVpaint.Width;
  TheImage.Canvas.Brush.Color :=$000000;
  TheImage.canvas.FillRect( Bounds(0,0,UVpaint.width,UVpaint.height));
  TheImage.Canvas.Pen.Color :=$FFFFFF;
  TheImage.canvas.MoveTo(100, 100);
  TheImage.canvas.LineTo(200, 200+random(20));
  TheImage.canvas.LineTo(100, 200+random(20));
  TheImage.canvas.LineTo(100, 100);

  TheImage.Canvas.Brush.Color :=clblue;
  TheImage.Canvas.FloodFill(110, 120, clwhite, fsBorder);
  UVpaint.Canvas.Draw(0, 0, TheImage);



end;


procedure TForm1.UVpaintPaint(Sender: TObject);
begin
  UVpaint.Canvas.Draw(0, 0, TheImage);
end;

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 820
    • Burdjia
Re: Drawing lines and primitives
« Reply #11 on: April 01, 2009, 05:32:48 pm »
Whoah, you are the best. :)
I know...  8) :D
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

Handoko

  • Hero Member
  • *****
  • Posts: 2641
  • My goal: build my own game engine using Lazarus
Re: Drawing lines and primitives
« Reply #12 on: January 22, 2018, 12:40:03 pm »
 Sorry to dig an old thread out. I'm just curious.

Question is why do you want to Paint inside the OnPaint event? If you use a TPaintBox, you can just paint on it, it will refresh on it's own, and your painted data persists.

I don't understand why you avoid to paint inside the OnPaint event. I modified your code to paint inside OnPaint, the result ==> much simpler code:

Code: Pascal  [Select]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Forms, Controls, Graphics, ExtCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Timer1: TTimer;
  16.     uvPaint: TPaintBox;
  17.     procedure Timer1Timer(Sender: TObject);
  18.     procedure uvPaintPaint(Sender: TObject);
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.lfm}
  27.  
  28. { TForm1 }
  29.  
  30. procedure TForm1.Timer1Timer(Sender: TObject);
  31. begin
  32.   uvPaint.Invalidate;
  33. end;
  34.  
  35. procedure TForm1.uvPaintPaint(Sender: TObject);
  36. begin
  37.   with uvPaint.Canvas do begin
  38.     Brush.Color := clBlack;
  39.     FillRect(Bounds(0, 0, Width, Height));
  40.     Pen.Color := clWhite;
  41.     MoveTo(100, 100);
  42.     LineTo(200, 200 + Random(20));
  43.     LineTo(100, 200 + Random(20));
  44.     LineTo(100, 100);
  45.     Brush.Color := clBlue;
  46.     FloodFill(110, 120, clWhite, fsBorder);
  47.   end;
  48. end;
  49.  
  50. end.

Note:
- The screenshot captured when running the program on Linux Gtk2
- FloodFill has issue when running on Gtk2
- The animation runs smoothly, no flicker even when resizing
« Last Edit: January 22, 2018, 12:41:43 pm by Handoko »

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus