Graphics Prog, PolyLinesAssignment 3by Mike Roam. Rev.24 nov 2004. | ![]() |
We're going to draw series of lines from point1 (x,y) to point2 (x2,y2) to point3 and so on.
Create a class called "Point2D" so that we can hold two numbers (x and y) inside ONE variable.
There should be fields for (double) x, and y...
There should be some constructors: one constructor that receives nothing and makes a default point (0,0); another constructor that receives two doubles and makes a corresponding point, and finally a constructor that receives a "Point2D" and copies its x and y into our own x and y. Here's an example of the second constructor:
/** * constructor receives 2 doubles */ public Point2D( double newX, double newY ) { x = newX; y = newY; } // constructor() There should be a nice "public String toString( )" method which merely reports back the contents of the point2D:
return "(" + x + "," + y + ")";
Finally, there should be "getters" and "setters" (also known as "accessor" methods) for both x and y. Here's an example for x.
public int getX() { return x;} // getX( )public void setX(int newX) { this.x = newX;} // setX( ) Note: technically, because this little dinky class has no limits on the values of x and y, it doesn't really need x and y to be privatewith setters and getters, but this is good practice.
Now we can create an array of points. For now assume that there will never be more than 10 points. (Later we'll use some "Collection" thing that can hold any number of points.)
These points have to come from somewhere. Let's add a "JTextArea" to your user interface (which is in that separate class called "DrawController" that you built in assignment 2) so that you can read in multiple points. Here is a way to have a "JTextArea" with scrollbars. (JTextAreas can have multiple lines, while the JTextFields we've used so far could only have one line.)Put the following 2 lines near where you've declared all your other buttons and fields...
JTextArea myNumberZone=new JTextArea(/*rows, how tall */ 8, /* cols */15); JScrollPane theScroller = new JScrollPane( myNumberZone ); /* put the text area inside scroll bars */
The following is a line that puts theScroller (which is scrollbars with your JTextArea inside them) onto the screen. Put this line with all the other lines that actually put buttons and fields onto the screen. (Probably in your DrawController constructor, (or in init(), Greg).)
getContentPane().add( theScroller );
(Note: while we haven't set up key listeners for copying and pasting from the JTextArea, you can "drag&drop" into it from the desktop and out of it onto the desktop. Reading from a text file would be even nicer, but don't bother if you don't know how. If you sort of know how, there's a sample file called "file_io_latest" in our class assignments folder that you can use as a model. You'll have to have a button (with listener) which gets things going.)
Your numbers will look something like this:
23, 89.7
-105.7, 92.34
etc. (Note that there are commas, spaces, returns, -'s and .'s)
Now you've got a place for the user to put numbers. Next we need a button and listener that grab the numbers and do something useful with them. (Remember that there are sample listeners which you built in assignment 2. Copy one and change it into a DrawPolygonLsr listener.) The first thing your new listener will do is put the contents of the field (or file) into a String:
String theNumStr = myNumberZone.getText();
(Now let's see if you're paying attention. Read the following but don't write the code until you see the secret shortcut later on. What you're about to read now is the old-fashioned hard way of extracting numbers one at a time by painstakingly looking for commas and white space (return, blank, tab) and handing back whatever you find between them. We're not going to use this technique unless you really want a challenge, but I insist upon you reading and thinking about it.)
First (when doing things the hard way) you need to find where commas are, which you can do by saying
int whereFirstComma = theNumStr.indexOf(",");
To find subsequent commas (or end-of-line "\n"), you can tell the "indexOf()" method where it should start looking from (starting at pos 23 in the following example):
int whereSecondComma = theNumStr.indexOf("," , 23 );
Watch out: indexOf( ) returns -1 if it can't find the char anywhere.
Note: you should be able to look for "\n" or "\r" (newline or carriage feed).
You can (must!) pull substrings out of the big string by saying
String littleStr = theNumStr.substring(2,5); /* If theNumStr is "lotsofdata" then you'll get chars 2,3, & 4: "tso" */ /* Don't forget, the string starts at char zero! */
So the hard way would be to start from the front of the string, find out where the first comma is, pluck out the substring from start to comma and turn that substring into a number. THEN, find where the next number is (between a comma and a return), pluck that number out, and so on.
But wait, people must want to split groups of words or numbers all the time, so there must be an easier way to do this. There is, and now you can see the shortcut hinted at earlier: the "split" command (working sample with source):
String inString = "this is a test 203.7, 14, -345";String[] result = inString.split("[,\\s]+"); /* note: "[,\\s]+" is a regular expression meaning "comma or any white space" (note the "," which means comma and the "\\s" which means (white) space. Also note the "+" which means "one or more". In English, "split.[,\\s]+" means "(split at) any group of one or more commas and spaces". */for (int x=0; x<result.length; x++) { System.out.println(result[x]);) }/* result will be "this" "is" "a" "test" "203.7" "14" "-345" */
The split command is how were going to break your string into an array of separate strings, broken apart at every comma and space and return-character. See if you can make sense of the example above, and include it in your DrawPolyLsr listener which you'll attach to a DrawPoly button.
Note: once you've gathered all the numbers into an array of STRINGS, you've still got to convert them to doubles (you can use the strToDouble( ) method from lesson 2), and it will be useful to combine every PAIR of numbers into a Point2D object. (Array elements 0 and 1 go together as x and y, elements 2 and 3 go together as x2,y2, while elements 4 and 5 are x3,y3 and so on.) The code might look something like the following:
Point2D[] manyPoints = new Point2D[10]; /* note: array that can hold 10 points 0..9 */int howManyNums = result.length;int howManyPoints = howManyNums/2;...Point2D p4 = new Point2D( strToDouble( result[6] ), strToDouble( result[7] ) );manyPoints[3] = p4;...manyPoints[4] = new Point2D( strToDouble( result[8] ), strToDouble( result[9] ) );
Or, even better, let's use the Java "Collections" class, which has "magic arrays" called ArrayLists that can be stretched (and sorted) [even better than the "mildly magic" arrays known as "Vectors", which are also outmoded].
Collection manyPoints = new ArrayList( ); // like vector, but not synchronized//note: be sure to "import java.util.*" at the top of your code...Point2D p4 = new Point2D( strToDouble( result[6] ), strToDouble( result[7] ) );manyPoints.add( p4 );...manyPoints.add( new Point2D( strToDouble( result[8] ), strToDouble( result[9] ) ));...
Now, in that same listener, you can tell the drawgrid to draw lines from point1 to point2 to point3, etc. Don't automatically draw back to point 1: if the user wants that they can repeat point one at the end of the list. The code might look something like the following (if you're using arrays):
Point2D p4 = manyPoints[3];Point2D p5 = manyPoints[4];myDrawGrid.drawLine( p4.x, p4.y, p5.x, p5.y );/* or ... */myDrawGrid.drawLine( manyPoints[3].x, manyPoints[3].y, manyPoints[4].x, manyPoints[4].y );/* or if you have a drawLine method that can handle Point2D's: */myDrawGrid.drawLine( manyPoints[3], manyPoints[4] );
or (if you're using cool Collections):
Point2D prevPoint = null; // just to get startedPoint2D nextPoint = null; // just to get startedfor (Iterator i = manyPoints.iterator(); i.hasNext(); prevPoint = nextPoint) { nextPoint = i.next(); if (prevPoint == null) { prevPoint = nextPoint }; /* Yeah, first "line" is from point1 to itself, but even if there's only one point, we'll still get a line! */ myDrawGrid.drawLine( prevPoint.x, prevPoint.y, nextPoint.x, nextPoint.y );}
(Note: we're not using StringTokenizer because it is outmoded: "a legacy class that is retained for compatibility reasons although its use is discouraged in new code") but we could try StreamTokenizer:
Reader r = new BufferedReader(new InputStreamReader(is));StreamTokenizer st = new StreamTokenizer(r); // orString myString = "here is something to parse";Reader r2 = new StringReader( myString );StreamTokenizer st2 = new StreamTokenizer(r2); Final note: this information is available on our internal web site. Just fire up Safari (on the desktop of most machines): the home page has a link to the Java "API" which has a great index.
If all of these basics are working, go on to assignment 4 in which you try to draw wireframes in 3d!
last modified wednesday 24 nov 2004, by mjr.