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

Delphi Course: "Proper" graphics

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 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?)

You may find typos and rough edges in this. None-the-less, the basic information should be accurate. If something seems wrong, or if you find I've assumed knowledge without explaining it in a previous lesson, please let me know. Please forgive matters of typos, etc. for now. I am not inherently sloppy! The blemishes will be dealt with later.




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

Delphi language:
--- For ... := ... To ... Do ...
--- Begin ... End
--- Inc



--> Delphi built in procedures:
--- MoveTo
--- LineTo
This lesson will produce several small applications which draw pretty patterns on the screen. I hope you will be "inspired" to tweak the applications to vary the pattern. 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 graph1u1.pas. Save the project as graph1.dpr

Make the form fill at least 1/3 of the screen vertically and horizontally. 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;
Image1.Picture.Graphic:=bmapMain;(*Assign the bitmap to the image component*)
end;
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. In addition: one simple point: You should not be frightened by....
bmapMain.width:=400
... as it is merely assiging 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;
Add another button. Call it buHoriBlu. 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;


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 VertRed'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;
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 heirarchies, and the "dot" notoation? 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 want'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 more often used:
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;
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.


Try the following replacement code for buOther's OnClick handler....
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;
   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;
Most of what is going on is, I hope, fairly obvious.

There are four "pixels:=" lines to color groups of four pixels at a time. (The color of a single pixel is hard to see.)

The values for the colors, clRed, clBlue, etc, 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 $FF0000, youy would get blue pixels. Put $00FF00 and you'd get green pixels. Put $0000FF, and you'd get red pixels. The pairs of digits in, e.g. $0000FF speicify how much blue, green and red there will be in your color. 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. Congratualtions! 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 another possible set of instructions for buOther's OnClick handler"
procedure Tgraph2f1.buOtherClick(Sender: TObject);
var iCount,iX,iY:integer;
    clThisOne:TColor;
begin
   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;
Just a bit of fun. Write some of your own!




Click here if you're feeling kind! (Promotes my site via "Top100Borland")
   Search this site or the web        powered by FreeFind
 
  Site search Web search
Site Map    What's New    Search
Ad from page's editor: Yes.. I do enjoy compiling these things for you... I hope they are helpful. However.. this doesn'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 (tm) freeware, shareware page.

Link to Tutorials main page Link to Delphi Course index
Here is how you can contact this page's author, Tom Boyd.


Valid HTML 4.01 Transitional Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org


If this page causes a script to run, why? Because of things like Google panels, and the code for the search button. Why do I mention scripts? Be sure you know all you need to about spyware.

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