HOME - - / - - / - - LAZARUS/ DELPHI TUTORIALS
LAZARUS/ DELPHI COURSE - - / - - / - - Other material for programmers

Lazarus and Delphi Course: "Proper" graphics

Page URL: Graph2.htm

This page is information rich, and a has search button at the bottom of the page.

Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!



You will probably find the text easier to read if you make your browser window much narrower than usual. You may also want to change your browser's zoom level, to enlarge the text. Opera (at least) lets you change zoom level easily. The text will adapt nicely to the settings you decide give the best results for your needs!

The lines of sample Lazarus/ Delphi code in these pages will not "wrap". I.e., if a line is too long to show in the width you have set your browser too, parts of the line will be "off the page". Those lines will still copy/paste properly, at least in Opera. Please feel free to send feedback on the choices I've made! (Will you forgive me for not forcing upon you a column of links on the left and a column of ads on the right?)

This is just one exercise in a series of Lazarus / Delphi exercises. You will probably be best served by doing them in sequence... each assumes some prior knowledge. Material © TK Boyd, sheepdogsoftware.co.uk, 4/05-6/20.

Heavily re-worked, June 2020, to bring it up to date for Windows 10/ Lazarus 2.0.0 Based on earlier Delphi page. Probably still useful to Delphi programmers, too.


In the first lesson on graphics, we made pretty patterns, but crudely. In this lesson, you make an application which draws pictures of much higher resolution.

You should learn about....
--- "Boiling down" stuff

Pascal: the language behind both Lazarus and Delphi:
--- For ... := ... To ... Do ...
--- Begin ... End
--- Inc



Lazarus/ Delphi built in procedures:
--- MoveTo
--- LineTo
This lesson will produce several small applications which draw pretty patterns on the screen. I hope they will inspire you to tweak the applications, vary the patterns.. or maybe even come up with some totally new ones!

One of the great joys and opportunities in programming is the chance to be creative. Make sure you can do the things described in the lesson, but also explore the "I wonder if I can...?" ideas which I hope you will have. Look for some, if they don't come by themselves!

Start a new application. Put an image component on the form. (It's on the "additional" tab of the component palette.) Rename the form graph2f1. Save the unit as graph2u1.pas. Save the project as graph2.dpr

Make the form fill at least 500 pixels wide, and at least 300 high. (You can use the Object Inspector to do it quickly, easily.

Make the image fill most of the form.



Double click somewhere on the form not on the memo, and not on the title bar. This should start code for the form's OnCreate event handler. Make it...
procedure Tgraph2f1.FormCreate(Sender: TObject);
var bmapMain:TBitmap;(*Provide a suitable variable*)
begin(*main of OnCreate*)
bmapMain:=TBitmap.create;(*Create a bitmap object*)
Image1.width:=400;
Image1.height:=100;
bmapMain.width:=400;(*Assign dimensions*)
bmapMain.height:=100;
bmapMain.canvas.pen.color:=clWhite;//Lazarus only
bmapMain.canvas.rectangle(0,0,
   Image1.width,Image1.height);//Lazarus only
Image1.Picture.Graphic:=bmapMain;(*Assign the bitmap to the image component*)
end;//FormCreate
Believe it or not, I'm not going to go into every detail of the above! Don't try to figure it all out, at this stage. Suffice it to say that we need a TBitMap object, and a TImage object to hold and display it.

I do need to point out and explain two lines. Near the end, see the two with the "//Lazarus only" rems? Those are only needed if you are using Lazarus.

One simple point: You should not be frightened by....
bmapMain.width:=400
... as it is merely assigning a value to a property of an object. You've seen such assignments before.

The program should run at this stage, but it won't do anything very interesting.

Add a button. Name it buVertRed. Make it's caption 'Vertical Red'. Make it's OnClick handler....
procedure Tgraph2f1.buVertRedClick(Sender: TObject);
begin
Image1.Picture.Bitmap.canvas.pen.color:=clRed;
   (*Have a look at the canvas Help to see all the properties*)
Image1.Picture.Bitmap.canvas.moveto(10,10);
Image1.Picture.Bitmap.canvas.lineto(10,90);
end;//buVertRed
Add another button. Call it buHoriBlu. (HoriBlu, not Horrible. Ha ha.) Make it's caption 'Horizontal Blue'. Make it's OnClick handler....
procedure Tgraph2f1.buHoriBluClick(Sender: TObject);
begin
Image1.Picture.Bitmap.canvas.pen.width:=8;
Image1.Picture.Bitmap.canvas.pen.color:=$FF0000;
Image1.Picture.Bitmap.canvas.moveto(10,10);
Image1.Picture.Bitmap.canvas.lineto(250,10);
end;//buHoriBluClick


Run the application. Click the "Vertical Red" button. Click the "Horizontal Blue" button. Look closely at the result.

Quit the application. Restart it. Click the "Horizontal Blue" button. Click the "Vertical Red" button. Do you see the difference?

Skip down when ready to be told difference.....





- - - - v v v v - - - -





- - - - v v v v - - - -





- - - - v v v v - - - -





- - - - v v v v - - - -

The first time, you got a thin red line, and a fat blue line. The second time, you got a fat blue line and a fat red line. To always get a thin red line, add...
Image1.Picture.Bitmap.canvas.pen.width:=1;
at the start of buVertRed's OnClick handler.


So far, so good? That's the hard and boring stuff done. What follows may look "hard", but it really isn't. It just looks a little messy.

Add another button to the form. Call it buOther; caption it 'Other'. Make its OnClick handler...
procedure Tgraph2f1.buOtherClick(Sender: TObject);
var iCount:integer;
begin
iCount:=0;
repeat
   Image1.Picture.Bitmap.canvas.moveto(random(400),random(100));
   Image1.Picture.Bitmap.canvas.lineto(200,100);

   iCount:=iCount+1;
until iCount>100;
end;//buOtherClick
Computer draws 100 lines pretty quickly, doesn't it?!


That's it! Enough fun for the moment. Now you have to work.

Seriously: There are some very important things in what follows. Don't be tempted to skip them.


Remember in an earlier lesson we talked about object hierarchies, and the "dot" notation? The statement....
Image1.Picture.Bitmap.Canvas.Pen.Width:=8;
... is a pretty extreme example! But there's nothing fundamentally different going on.


The first time we started to draw a line, we used....
Image1.Picture.Bitmap.Canvas.MoveTo(10,10);;
(That's 10 pixels to the left, and 10 down from the top, by the way. Almost everything in Windows is done from the upper left corner of things.)

The next time we drew a line, we used....
Image1.Picture.Bitmap.Canvas.MoveTo(random(400),random(100));
What you need to see is that MoveTo has two things inside the brackets following it. In the first case, it is 10 and 10... pretty easy to see. In the second case, we still just have two things that "boil down" to numbers. When the application encounters random(400), it picks an integer from 0 to 399, inclusive. You will need to develop your skills at "seeing" how things "boil down".

Consider the line....
iCount:=iCount+1;
That "boils down" to: A variable's name
The assignment symbol :=
and something that "boils down" to a value.

In this case, as the variable was an integer-type variable, the stuff after the := boiled down to an integer. It might be very complex in some cases, but it will still boil down to a single integer.

This "boiling down" stuff has other manifestations, but we'll leave them for another time.


We've been using....
iCount:=iCount+1;
... to add 1 to what's in iCount. This is something programmers do so often that those nice people at Borland gave us another way. The following has the same effect:
inc(iCount);
("Inc" came from "increment".)


We've made use of "repeat" and "until" for loops. There's nothing wrong with that, and for some jobs they are the best way. However, there are many cases where the following is easier, once you are used to it. Change buOtherClick to the following:
procedure Tgraph2f1.buOtherClick(Sender: TObject);
var iCount:integer;
begin
for iCount:=0 to 100 do begin
   Image1.Picture.Bitmap.Canvas.MoveTo(random(400),random(100));
   Image1.Picture.Bitmap.Canvas.LineTo(200,100);
   end; // of "for"'s begin
end;//buOtherClick
There are two things going on here.

First note the for ... := ... to do part. All the code above is doing is causing something just like our earlier repeat ... until loop. Work out what things are doing. Try changing the numbers, and see if you get the results your understanding of for... do... would suggest.

The second thing is less obvious, but more important.

After the do of the for statement, there may be one or many further lines in the program. How many of them should be done multiple times?

The rule is simple... but there's a trick. The rule is that only the first "thing" after the do is done repeatedly. The trick is that any lines (note the s) enclosed between a begin and an end count as one "thing". Thus, in this case, the MoveTo and the LineTo are both done 100 times.


Here's a third alternative for buOther's OnClick code handler. Try it...
procedure Tgraph2f1.buOtherClick(Sender: TObject);
var iCount,iX,iY:integer;
    clThisOne:TColor;
begin
for iCount:=0 to 100 do begin
   iX:=random(399);
   iY:=random(99);
   clThisOne:=random(9);
   if clThisOne=0 then clThisOne:=clRed;
   if clThisOne=1 then clThisOne:=clBlue;
   if clThisOne=2 then clThisOne:=clGreen;
   if clThisOne=3 then clThisOne:=clAqua;
   if clThisOne=4 then clThisOne:=clMaroon;
   if clThisOne=5 then clThisOne:=clYellow;
   if clThisOne=6 then clThisOne:=clTeal;
   if clThisOne=7 then clThisOne:=clSilver;
   if clThisOne=8 then clThisOne:=clBlack;
   //Color chosen... now add a square in that color to the graphic...
   Image1.Picture.Bitmap.Canvas.Pixels[iX,iY]:=clThisOne;
   Image1.Picture.Bitmap.Canvas.Pixels[iX+1,iY]:=clThisOne;
   Image1.Picture.Bitmap.Canvas.Pixels[iX,iY+1]:=clThisOne;
   Image1.Picture.Bitmap.Canvas.Pixels[iX+1,iY+1]:=clThisOne;
   end; // of "for"'s begin
end;//buOtherClick
Rather pretty, don't you think?

Most of what is going on is, I hope, fairly obvious? Here are the details, just in case. And some things to particularly notice....

The four "pixels:=" lines near the end of the subroutine cause a group of four pixels to be put on the screen. (A single pixel on a modern screen is hard to see... deciding its color is well neigh impossible.)

clRed, clBlue, etc, the values for the "pen" used, are built into Delphi. You can see the full list by using the help system. Look up "color constants", and then drill down to "color constants for all other..."

You can specify colors another way. If instead of clRed, you put $0000FF, you would get red pixels. Put $00FF00 and you'd get green pixels. Put $FF0000, and you'd get blue pixels. The pairs of digits in, e.g. $0000FF specify how much blue, green and red there will be in your color. I said "blue, green, red" deliberately, because that it the order of them on the string of characters

Use 00 for none of the color for that position. Use 40, 80, C0 or FF for increasing amounts of the color. So, for a mix of a little blue, modest amounts of green, and as much red as possible, use $4080FF. Congratulations! You've been working with hexadecimal numbers. You'll do it again, and in more depth, if you follow this course to the end!


Here's yet another possible set of instructions for buOther's OnClick handler"
procedure Tgraph2f1.buOtherClick(Sender: TObject);
var iCount,iX,iY:integer;
    clThisOne:TColor;
begin
   iX:=0;
   iY:=50;
for iCount:=0 to 400 do begin
   inc(iX);
   iY:=iY+Random(17)-8;
   if iX>400 then iX:=0;
   if iY>100 then iY:=0;
   if iY<0 then iY:=0;
   Image1.Picture.Bitmap.Canvas.Pixels[iX,iY]:=clBlue;
   end; // of "for"'s begin
end;//buOtherClick
Just a bit of fun. Write some of your own!



Search just this site without using forms,
Or... again to search just this site, use...

Powered by FreeFind

Site search Web search

The search engine merely looks for the words you type, so....
  *!  Spell them properly   !*
  Don't bother with "How do I get rich?" That will merely return pages with "how", "do", "I", "get" and "rich".



I have other sites...
   SheepdogSoftware site.
   My site at Arunet.


Ad from page's editor: Yes.. I do enjoy compiling these things for you... I hope they are helpful. However.. they don't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated.
Click here to visit editor's Sheepdog Software freeware, shareware page.
Link to Tutorials main page Link to Lazarus/ Delphi Course index

To email this page's editor, Tom Boyd.... Editor's email address. Suggestions welcomed! Please cite "Graph2.htm".

Click for W3.org HTML validity test Page has been tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes.

AND passes... Click to check CSS validity


One final suggestion: Be sure you know all you need to about spyware.

. . . . . P a g e . . . E n d s . . . . .