Tuesday, July 15, 2008

Drawing Lines

In A Most Basic Graphics App we had the framework of a simple graphics application. We trimmed it down a little, too much really, in Start With a JFrame. The JFrame alone doesn't accomodate graphics as well as we would like. The "window decorations"--the title bar, the frame around the window, close button and so on--all cover part of our drawing area. Likewise, there are other problems that crop up on different JVMs.

So we'll use the BasicPanel.java program from A Most Basic Graphics App to build on now.

We're going to concern ourselves with the part of the program that does the actual drawing:
g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)

In particular, we're going to focus on those four numbers inside the parentheses. What are they? Where do they come from? How can we pick numbers that will let us draw what we want, and what are the limits on what we can put in there?

First, let's look at what our limits are. At the low end, we have the number zero. Computers start counting at zero, and that's the low end number for what we can enter here and expect results. You can put a negative number in here, but unless you do some other things we're not going into here, negative numbers aren't going to do you any good.

For the high number, you can go up to the limits of the type, if you like. In this case we're calling drawLine(int, int, int, int), so we can go up to the limits of an int, or 2147483647, and not cause a problem so far as Java is concerned. We humans like to see our results, though. There's another line of BasicPanel we need to consider. That's this one:
This is setting the size of our JFrame (creatively named "frame") to 200 pixels wide and 200 pixels high. Since the JPanel we're drawing to is inside this JFrame, we know that the highest point we're going to see is less than this. How much less varies. It's based on how wide big the window decorations are on the JFrame, and this varies by operating system, and by the user's settings. But we definitely know that anything over 200 on the high end is going to be invisible. Higher numbers won't affect Java or your computer. You won't have a line that shoots out of its window and across your desktop if you make the numbers too high. You just won't see anything outside the JPanel area on which we're drawing.

We can find out exactly how large our drawing area is by using the getClipBounds() method of the Graphics class. Feel free to experiment with it, but for now let's get back to talking about the four numbers we use with drawLine and what they do. Just saying we have a high limit of 200 on those numbers is good enough for now.

OK, so we can use numbers from 0 to somewhere short of 200 in any of those four locations and expect results.

A Pair of Pairs

The four numbers in drawLine aren't just four numbers, they're two pairs of number. The first two numbers are the first pair, the third and fourth numbers are the second pair. Each pair of numbers is a Cartesian coordinate. If you don't remember or haven't studied this in Geometry class, don't sweat it. We'll suss things out well enough here.
g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)
Notice how in the comment I say we're drawing a line from (10, 10) to (150, 150). Notice the first two numbers in g.drawLine() are 10 and 10, and the second two numbers are 150 and 150. This Means Something. ;)

The first pair marks the starting point for our line, the second pair marks the ending point.

The first number in each pair says how far left or right we want that point. The second number in each pair says how far up or down we want that point.

On left and right, 0 is all the way to the left. The higher the number, the farther over to the right we'll be. In our case, we can go up to 200 (almost.) A number of about 190 will probably take us all the way to the right of our drawing area.

On up and down, 0 is all the way to the top. The higher the number, the lower we'll go. A number of about 185 or so will take us all the way to the bottom of our drawing area.

If we want to draw a line all the way across our drawing area, instead of just partway across, we can replace
g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)
This will actually "go over" the edge of our drawing area, but it won't matter. Open up BasicPanel in your editor, make this change, compile it and run it.

Fine, we've mastered drawing a line from the top left to the bottom right. We're not exactly drawing starships yet, are we?

What if we change the pairs of numbers around? Open up your editor and make this change to the drawLine() statement:
Once you compile and run, what do you see? It looks the same, right? That's because we drew a line between the same two points, we just drew from bottom right to top left this time. OK, I hear you saying "Borrrringgg!" Let's move on.

Horizontal Lines

If we want a line to be horizontal, both the up-and-down numbers need to be the same. This means the second number in each pair, the second and fourth numbers. Add the following line to BasicPanel right after your other drawLine() statement:
Compile and run, and now you have a horizontal line. Notice the second and fourth numbers are the same. If you want to move the horizontal line up or down, change the number in the second and fourth position:
g.drawLine(10,20,200,20); // A higher horizontal line
g.drawLine(0,0,200,200); // A lower horizontal line
The higher the number you put in the second and fourth positions the lower the horizontal line will be. Go ahead and add these lines to your program, one at a time, and compile and run.

Vertical Lines

Now let's try vertical lines. For these, the first and third numbers (the left-right numbers) need to be the same:
g.drawLine(50,0,50,200); // A vertical line.
Change the 50s to some other number to move the vertical line left or right.

Starting and Ending

Now we can draw multiple lines to build up objects. By starting and ending the lines at the same points, we can make them meet up, and use the individual lines to build up objects. using our vertical and horizontal lines, we can make up squares and rectangles, or draw pictures that look like they're off an Etch-a-Sketch. ;)

Open up BasicPanel and replace all the existing drawLine() statements with the following:

g.drawLine(50,20,150,20); // Draw a horizontal line from (50,20) to (150,20)
g.drawLine(150,20,150,150); // Draw a vertical line from (150,20) to (150,150)
g.drawLine(150,150,20,150); // Draw a horizontal line from (150,150) to (20,150)
g.drawLine(20,150,50,20); // Draw a vertical line from (20,150) to (50,20)
Notice how the points we use match up (look at the pairs in the comments.) The last point is the same as the first to close the box.

Now, if we just wanted to draw boxes Java actually has a way to do this more efficiently. But what we're focusing on here is coordinates and how to use them.

Play around with different points and see what effect you get. Try drawing a triangle. Try drawing different sloping lines, both ones that slope down from left to right and ones that slope up. Remember, when you slope up the point on the right is going to have a second (up-down) number lower than the point on the left.

Once you play around for a while, you'll get the hang of it. If you want a larger screen area to play with, enlarge the numbers in the setSize() statement. Try this for a start:
This will give you more room to play it. Now you can take numbers up to about 480 before they go out of view. Try using getClipBounds() to find out just how large a number you can get. If you can't get it, don't sweat it, I'll cover it in a future post, or you can do an internet search to find an example in someone else's program, or jump into a Java newbie forum and ask.