Pages

Sunday 26 June 2011

Lecture 22
Lecture 21
Lecture 20
Lecture 19
Lecture 18
Graphics Contest
Graphics Contest
Debugging
Array List
Array List
Section Handout 7

Mehran Sahami Handout #39 CS 106A November 14, 2007

Mehran Sahami Handout #39
CS 106A November 14, 2007
Assignment #6—NameSurfer
Due: 3:15pm on Wednesday, November 28th
The NameSurfer assignment was created by Nick Parlante and further revised by Patrick Young and Eric Roberts
This assignment has two primary goals. The first is to give you an opportunity to use Java interactors to create an application that looks more like a modern interactive program complete with buttons, text fields, and a resizable graphical display. The second goal is to pull together the various facilities you have learned about so far to create an interesting application that—unlike Breakout, Hangman, and Yahtzee—is not a game but rather a useful program that presents data on some fascinating sociological questions.
Overview of the NameSurfer project
Against all bureaucratic stereotypes, the Social Security Administration, provides a neat web site showing the distribution of names chosen for children over the last 100 years in the United States (http://www.ssa.gov/OACT/babynames/). The Social Security Administration provides data that shows the 1000 most popular boy and girl names for children at 10 year intervals. The data can be boiled down to a single text file that looks something like this:
NamesData.txt
. . .
Sam 58 69 99 131 168 236 278 380 467 408 466
Samantha 0 0 0 0 0 0 272 107 26 5 7
Samara 0 0 0 0 0 0 0 0 0 0 886
Samir 0 0 0 0 0 0 0 0 920 0 798
Sammie 537 545 351 325 333 396 565 772 930 0 0
Sammy 0 887 544 299 202 262 321 395 575 639 755
Samson 0 0 0 0 0 0 0 0 0 0 915
Samuel 31 41 46 60 61 71 83 61 52 35 28
Sandi 0 0 0 0 704 864 621 695 0 0 0
Sandra 0 942 606 50 6 12 11 39 94 168 257
. . .
Each line of the file begins with the name, followed by the rank of that name in each of the 11 decades since 1900, counting the current one: 1900, 1910, 1920, and so on up to 2000. A rank of 1 indicates the most popular name that year, while a rank of 997 indicates a name that is not very popular. A 0 entry means the name did not appear in the top 1000 names for that year and therefore indicates a name that is even less popular. The elements on each line are separated from each other by a single space. The lines happen to be in alphabetical order, but nothing in the assignment depends on that fact.
As you can see from the small excerpt from the file, the name Sam was #58 in the first decade of the 1900s and is slowly moving down. Samantha popped on the scene in the 1960s (possibly because the show Bewitched, which had a main character names Samantha ran on television during those years) and is moving up strong to #7. Samir barely appears in the 1980s (at rank #920), but by the current decade is up to #798. The database counts children born in the United States, so trends in particular names tend to reflect the evolution of ethnic communities over the years.
– 2 –
Figure 1. Sample run of the NameSurfer program (with names "Sam" and "Samantha")
The goal of this assignment is to create a program that graphs these names over time, as shown in the sample run in Figure 1. In this diagram, the user has just typed Samantha into the box marked ―Name‖ and then clicked on the ―Graph‖ button, having earlier done exactly the same thing for the name Sam. Whenever the user enters a name, the NameSurfer program creates a new plot line showing how that name has fared over the decades. Clicking on the ―Clear‖ button removes all the plot lines from the graph so that the user can enter more names without all the old names cluttering up the display.
To give you more experience working with classes that interact with one another, the NameSurfer application as a whole is broken down into several separate class files, as follows:
• NameSurfer—This is the main program class that ties together the application. It has the responsibility for creating the other objects and for responding to the buttons at the bottom of the window, but only to the point of redirecting those events to the objects represented by the other classes.
• NameSurferConstants—This interface is provided for you and defines a set of constants that you can use in the rest of the program simply by having your classes implement the NameSurferConstants interface, as they do in the starter files. The NameSurferConstants interface therefore has the same role that YahtzeeConstants did in Assignment #5.
– 3 –
• NameSurferEntry—This class ties together all the information for a particular name. Given a NameSurferEntry object, you can find out what name it corresponds to and what its popularity rank was in each decade.
• NameSurferDataBase—This class keeps track of all the information stored in the data files, but is completely separate from the user interface. It is responsible for reading in the data and for locating the data associated with a particular name.
• NameSurferGraph—This class is a subclass of GCanvas that displays the graph of the various names by arranging the appropriate GLine and GLabel objects on the screen, just as with the various graphical programs you’ve written this quarter.
Even though the class structure sounds complicated, the NameSurfer application code is about the same size as Yahtzee. Even if the scale of the project is comparable to the last assignment, the wise course is to start on the assignment soon and keep up with the milestones described in this handout.
Milestone 1: Assemble the GUI interactors
If you look at the bottom of Figure 1, you will see that the region along the SOUTH edge of the window contains several interactors: a JLabel, a JTextField, and three JButtons. Since putting up interactors is something you haven't done in previous assginments, you probably want to work on this step before it becomes complicated with all the other parts of the assignment. Thus, your first milestone is simply to add the interactors to the window and create an implementation for the actionPerformed method that allows you to check whether you can detect button clicks and read what’s in the text field.
The simplest strategy to check whether your program is working is to change the definition of the NameSurfer class so that it extends ConsoleProgram instead of Program, at least for the moment. You can always change it back later. Once you have made that change, you can then use the console to record what’s happening in terms of the interactors to make sure that you’ve got them right. For example, Figure 2 shows a possible transcript of the commands used to generate the output from Figure 1, in which the user has just completed the following actions:
1. Entered the name Sam in the text field and clicked the Graph button.
2. Entered the name Samantha in the text field and then typed the ENTER key.
3. Clicked the Clear button.
The hard part about reaching this milestone is understanding how interactors work. Once you do, writing the code is quite straightforward – it's only 10 to 15 lines of code.
Figure 2. Illustration of Milestone 1
– 4 –
Milestone 2: Implement the NameSurferEntry class
The starter file for the NameSurferEntry class appears in full as Figure 3 on the following page. As with the other files supplied with this assignment, the starter file includes definitions for all of the public methods we expect you to define. The method definitions in the starter files, however, do nothing useful, although they occasionally include a return statement that gives back a default value of the required type. In Figure 3, for example, the getRank method always returns 0 to satisfy the requirement that the method returns an int as defined in its header line.
Methods that will eventually become part of the program structure but that are temporarily unimplemented are called stubs. Stubs play a very important role in program development because they allow you to set out the structure of a program even before you write most of the code. As you implement the program, you can go through the code and replace stubs with real code as you need it.
The NameSurferEntry class encapsulates the information pertaining to one name in the database. That information consists of two parts:
1. The name itself, such as "Sam" or "Samantha"
2. A list of 11 values indicating the rank of that name in each of the decades from 1900 to 2000, inclusive
The class definition begins with a constructor that creates an entry from the line of data that appears in the NamesData.txt file. For example, the entry for Sam looks like this:
Sam 58 69 99 131 168 236 278 380 467 408 466
The idea behind the design of this constructor is that it should be possible to read a line of data from the file and then create a new entry for it using code that looks like this:
String line = rd.readLine();
NameSurferEntry entry = new NameSurferEntry(line);
The implementation of the constructor has to divide up the line at the spaces, convert the digit strings to integers (using Integer.parseInt), and then store all of this information as the private state of the object in such a way that it is easy for the getName and getRank methods to return the appropriate values.
The last method in the starter implementation of NameSurferEntry is a toString method whose role is to return a human-readable representation of the data stored in the entry. For example, if the variable entry contains the NameSurferEntry data for Sam, you might want entry.toString() to return a string like this:
"Sam [58 69 99 131 168 236 278 380 467 408 466]"
Defining toString for a class has the wonderful advantage that it makes it possible to print out objects of that class using println, just as you do for primitive values. Whenever Java needs to convert an object to a string, it always calls its toString method to do the job. The default definition of toString in the Object class doesn’t supply much useful information, and you will find that your debugging sessions get much easier if you can look easily at the values of your objects.
– 5 –
To show that you’ve got NameSurferEntry implemented correctly, you might want to write a very simple test program that creates an entry from a specific string and then verifies that the other methods work as they are supposed to.
Figure 3. Starter file for the NameSurferEntry class
/*
* File: NameSurferEntry.java
* --------------------------
* This class represents a single entry in the database. Each
* NameSurferEntry contains a name and a list giving the popularity
* of that name for each decade stretching back to 1900.
*/
import acm.util.*;
import java.util.*;
public class NameSurferEntry implements NameSurferConstants {
/**
* Creates a new NameSurferEntry from a data line as it appears
* in the data file. Each line begins with the name, which is
* followed by integers giving the rank of that name for each
* decade.
*/
public NameSurferEntry(String line) {
// You fill this in //
}
/**
* Returns the name associated with this entry.
*/
public String getName() {
// You need to turn this stub into a real implementation //
return null;
}
/**
* Returns the rank associated with an entry for a particular
* decade. The decade value is an integer indicating how many
* decades have passed since the first year in the database,
* which is given by the constant START_DECADE. If a name does
* not appear in a decade, the rank value is 0.
*/
public int getRank(int decade) {
// You need to turn this stub into a real implementation //
return 0;
}
/**
* Returns a string that makes it easy to see the value of a
* NameSurferEntry.
*/
public String toString() {
// You need to turn this stub into a real implementation //
return "";
}
}
– 6 –
Milestone 3: Implement the NameSurferDataBase class
The next step in the process is to implement the NameSurferDataBase class, which contains two public entries:
• A constructor that takes the name of a data file and uses that to read in the entire set of data from the file into internal data structures that allow the class to keep track of all the records as a database.
• A findEntry method that takes a name, looks it up in the stored database, and returns the NameSurferEntry for that name, or null if that name does not appear.
The code for this part of the assignment is not particularly difficult. The challenging part lies in figuring out how you want to represent the data so that you can implement the findEntry method as simply and as efficiently as possible.
To test this part of the program, you can add a line of code or two to the NameSurfer program so that it creates the NameSurferDataBase and then change the code for the button handlers so that clicking the ―Graph‖ button looks up the current name in the data base and then displays the corresponding entry (using its toString method), as shown in Figure 4 below.
Figure 4. Illustration of Milestone 3
Milestone 4: Create the background grid for the NameSurferGraph class
The next step in the process is to begin the implementation of the NameSurferGraph class, which is responsible for displaying the graph in the window by building the underlying model. The starter code for the NameSurferGraph class appears in Figure 5 on the next page.
– 7 –
Figure 5. Starter file for the NameSurferGraph class
/*
* File: NameSurferGraph.java
* --------------------------
* This class is responsible for updating the graph whenever the
* list of entries changes or the window is resized.
*/
import acm.graphics.*;
import java.awt.event.*;
public class NameSurferGraph extends GCanvas
implements NameSurferConstants, ComponentListener {
/**
* Creates a new NameSurferGraph object that displays the data.
*/
public NameSurferGraph() {
addComponentListener(this);
// You fill in the rest //
}
/**
* Clears the list of name surfer entries stored inside this class.
*/
public void clear() {
// You fill this in //
}
/**
* Adds a new NameSurferEntry to the list of entries on the display.
* Note that this method does not actually draw the graph, but
* simply stores the entry; the graph is drawn by calling update.
*/
public void addEntry(NameSurferEntry entry) {
// You fill this in //
}
/**
* Updates the display image by deleting all the graphical objects
* from the canvas and then reassembling the display according to
* the list of entries. Your application must call update after
* calling either clear or addEntry; update is also called whenever
* the size of the canvas changes.
*/
public void update() {
// You fill this in //
}
/* Implementation of the ComponentListener interface */
public void componentHidden(ComponentEvent e) { }
public void componentMoved(ComponentEvent e) { }
public void componentResized(ComponentEvent e) { update(); }
public void componentShown(ComponentEvent e) { }
}
– 8 –
There are a couple of important items in the NameSurferGraph starter file that are worth noting:
1. This class extends GCanvas, which means that every NameSurferGraph object is not only a GCanvas but also an instance of all the superclasses of the GCanvas class. GCanvas is a subclass of Component in the standard java.awt package and therefore is part of the hierarchy of classes that can be added to the display area of a program. Moreover, it means we can call any of the GCanvas methods, such as adding or removing GObjects, from within NameSurferGraph.
2. The starter file includes a tiny bit of code that monitors the size of the window and calls update whenever the size changes. This code requires only a couple of lines to implement, but would be hard to explain well enough for you to implement on your own. Writing a page of description so that you could add a couple of lines seemed like overkill, particularly given that the strategy is easiest to learn by example.
To start the process of adding the graphing code, go back to the NameSurfer class and change its definition so that it extends Program rather than the temporary expedient of extending ConsoleProgram (if you were using that for debugging). At the same time, you should remove the various println calls that allowed you to trace the operation of the interactors in the earlier milestones.
Now, you'll need to declare a NameSurferGraph private instance variable in your main NameSurfer class:
private NameSurferGraph graph;
You should then change the constructor of the NameSurfer class so that it creates a new NameSurferGraph object and adds that object to the display, as follows:
graph = new NameSurferGraph();
add(graph);
If you run the program with only these changes, it won’t actually display anything on the screen. To create the graph, you need to implement the update method, which will almost certainly involve defining private helper methods as well. As a first step, write the code to create the background grid for the graph, which consists of the vertical line separating each decade, the horizontal lines that provide space for the top and bottom borders (which are there to ensure that the text labels stay within the window bounds), and the labels for the decades. As with all the graphical applications you’ve written, the lines and labels are represented using GLine and GLabel objects, which you add to the graph in the appropriate positions.
– 9 –
Milestone 5: Complete the implementation of NameSurferGraph class
In addition to creating the background grid, the update method in NameSurferGraph also has to plot the actual data values. As you can see from Figure 5, the NameSurferGraph class includes two methods for specifying what entries are displayed on the screen. The addEntry method adds a new NameSurferEntry to a list of values that are currently on the display. The clear method deletes all of the entries in that list so as to clear the graph.
It is important to note that neither addEntry or clear actually changes the display. To make changes in the display, you need to call update, which deletes any existing GObjects from the canvas and then assembles everything back up again. At first glance, this strategy might seem unnecessary. It would, of course, be possible to have addEntry just add all of the GLines and GLabels necessary to draw the graph.
The problem with that approach is that it would no longer be possible to reconstruct the entire graph. In this example, you need to do just that to create a new graph whenever you change the size of the display. By storing all of the entries in an internal list, the NameSurferGraph class can redraw everything when update is invoked from the componentResized method.
There are a couple of points that you should keep in mind while implementing this part of the program:
• To make the data easier to read, the lines on the graph are shown in different colors. In the sample applet on the web site, the first data entry is plotted in black, the second in red, the third in blue, and the fourth in magenta. After that, the colors cycle around again through the same sequence.
• The fact that rank 1 is at the top of the window and rank 1000 is at the bottom means that it can sometimes seem confusing that rank 0—which means that the name does not appear in the top 1000 values for that year—appears at the bottom. To reduce the apparent discontinuity between rank 1 and rank 0, the entries for names that are absent from the data for a decade are listed with an asterisk instead of a numeric rank. You can see several examples of this convention in the data for Samantha in Figure 1.
Possible extensions
There are a lot of things that you could do to make this program more interesting. Here are just a few possibilities:
• Add features to the display. The current display contains only lines and labels, but could easily be extended to make it more readable. You could, for example, put a dot at each of the data points on the graph. Even better, however, would be to choose different symbols for each line so that the data would be easily distinguishable even in a black-and-white copy. For example, you could use little circles for the first entry, squares for the second, triangles for the third, diamonds for the fourth, and so on. You might also figure out what the top rank for a name is over the years and set the label for that data point in boldface.
– 10 –
• Allow deletion as well as addition. Because the screen quickly becomes cluttered as you graph lots of names, it would be convenient if there were some way to delete entries individually, as opposed to clearing the entire display and then adding back the ones you wanted. The obvious strategy would be to add a ―Delete‖ button that eliminated the entry corresponding to the value in the ―Name‖ box. That approach, however, has a minor drawback given the design so far. If you added a bunch of entries to the graph and then deleted the early ones, the colors of the later entries would shift, which might prove disconcerting. Can you redesign the color-selection strategy so that displayed entries retain their color even if other entries are removed?
• Try to minimize the overprinting problem. If the popularity of a name is improving slowly, the graph for that name will cross the label for that point making it harder to read. You could reduce this problem by positioning the label more intelligently. If a name were increasing in popularity, you could display the label below the point; conversely, for names that are falling in popularity, you could place the label above the point. An even more challenging task is to try to reduce the problem of having labels for different names collide, as they do for Sam and Samantha in Figure 1.
• Adjust the font size as the application size changes. One of the wonderful features of this program is that it redraws itself to fill the available space if you change the size of the window. If you make it too small, however, the labels run together and become unreadable. You could eliminate this problem by choosing a font size that allows each label to fit in the space available.
• Rewrite the application to use the model/view/controller pattern. The NameSurfer prorgam turns out to be an ideal application for the model/view/controller pattern described in Chapter 14. If you finish the standard assignment, you might try to reimplement it so that it maintains a separate model that can support multiple viewers. If you made this change, you could, for example, add a ―Table‖ button to the application that would add a second viewer to the application, which would display the results in tabular rather than graphical form.

Programming Methodology-Lecture22 Instructor (Mehran Sahami):

Programming Methodology-Lecture22
Instructor (Mehran Sahami): Howdy! So welcome back to yet another fun-filled,
exciting day of CS106a. We’re getting close to that Thanksgiving recess, which is always
a good time. In the days of yore, it used not be a whole week. It used to be you got like
one or two days off. You got like Thursday and Friday, which means you would have
gotten only one day off from this class and now you get a whole week to mellow in style
or catch up on all your other work as the case may be.
So there’s one handout today. It’s Assignment No. 6, which is the next assignment, name,
circle, watch. They talk a lot about that assignment in this class today. As a matter of fact,
we’re very fortunate for coming today because I will give you so much gratuitous
information that presents that assignment. It’s just almost laughable.
And then Assignment No. 5, as you know, is due today, so we can do painful to see how
much time it actually took you. Just wondering, I heard from my little sources that exist
was that last night, a lot of people were at the Lair and the computers at the Lair. Just
wondering how many people were at the Lair last night. A fair number. And some of the
computers at the Lair just mysteriously didn’t have Eclipse anymore. Anyone run into
that problem? One person, okay.
Yeah, there was some reimaging that went on, which I had nothing to do with and didn’t
know about until some of the section leaders said, hey, Eclipse is missing on these
machines and, you know, so I sent a very anxious email, I should say, to academic
computing, and there had been some mix up and Eclipse is now reinstalled on all the
machines, so I’m glad it didn’t affect too many people, but if it affected you, I apologize,
although we really didn’t have anything to do with it, but I’m sorry that you had to
experience that pain.
So in terms of the painful, how much time it actually should give you the assignment on
the Yahtzee assignment? Just wondering, how many of you actually liked the Yahtzee
assignment? Just a quick show of hands. And how many thought it was just more pain
than it was worth? Anyone? You folks, all right. And that’s good to know. I always try to
– actually try to gauge these things.
So anyone in the zero to two-hour category? You just did it and it worked and life was
good. Two to four? A couple people; that’s always good to see. Four to six? A reasonable
contingent. Six to eight? Good times. Eight to ten? Wow, pretty healthy distribution
there. Ten to twelve? Okay, we’re falling off a bit. Twelve to fourteen? You folks.
Fourteen to sixteen? Maybe a couple. Sixteen to eighteen? Eighteen plus? Taking a late
day? Yeah.
As you may have read – I should refresh your memory because it pertains to Assignment
No. 6, but as you may have read on Assignment – on Handout No. 1 at the very
beginning of class, because Assignment No. 7 is due the last day of the quarter, you can’t
use late days on that assignment. So if you have late days and you’re like, hey, I was just
saving them up for No. 7, well, seven’s due the last day so there’s no classes beyond
seven and you don’t say, hey, I’m taking a late day. That gives me an infinite amount of
time to turn it in because there are no more classes. No, it doesn’t work like that.
So Assignment No. 7 you can’t use late days on. So again, I would discourage you from
using your late days, but should you have them and you’re like, hey, I really wanna use
my late days, Assignment No. 6 is kind of your last chance to actually use your free late
days. Again, not that I would encourage you to use them, but just so you know up here
that you don’t get Assignment 7 and say, hey, I thought I could use my late days for this.
You’re getting plenty of advanced warning that you actually can’t.
One other quick announcement; CS Career Panel is today, so after today, I’ll stop
mentioning it because I believe most of you can’t actually time travel, so today, 5:30 p.m.
in Packard 101. Be there. We have a stellar panel of folks from academia, from industry,
a lot of people who actually – every one is a computer science major and four of the five
people graduated from Stanford’s department. The fifth is actually a faculty member here
that didn’t graduate from my department, but is a faculty member here.
And you’ll actually see there’s a very broad range of stuff to do. Out of those five people,
though, actually, I think only one, maybe one and a half who actually do programming as
their sort of fulltime job. But all of them are computer science undergraduates, so you get
sort of a breadth of what computer sciences can do.
So I’m so happy to see the fifth region. You’ll see the variance gets larger, right. As the
quarter goes on, that kind of happens, but it’s good to see that the mean is still where we
generally want it to be.
So now it’s time to talk a little bit about your next assignment. You just turned in your
last assignment. You’re like, no, no, it’s not time to talk about the next assignment. I’m
still working on the last assignment. Well, just pay attention.
Here’s what you’re going to do for your next assignment. It’s a little program called
NameSurfer, okay? And the idea of this program is it turns out that the government
actually keeps track of statistics of the popularity of names over time, okay. So every
decade when they do the census, they kind of keep track of the number of names and they
rank the top 1,000 names in terms of popularity for boys’ names and for girls’ names, and
they actually make this data available. We thought wouldn’t it be cool if you actually
were to display names to the user in terms of how that popularity changed over time.
So that’s what NameSurfer does. Here’s the program. What it does is it shows you the
decades. You can notice that this is a graphics, or involves graphics, right, has the
decades from 1900 up to 2000 and so relatively recent date up to the last census. And
what we can do is we can type in a name and then click graph, and what it will do is it
will show the rank of that name over time, on a decade-by-decade basis. So let’s try Fred,
for example. If you graph Fred, you can see Fred real popular at the turn of the prior
century and then Fred just had this quick decent into oblivion, where now he’s the 974th
most popular boys name, at least in the last Census 2000. We can do multiple graphs on
here, so if I type in someone else – so one thing that’s also interesting is you’ll notice
popular culture comes in, and so if I type in Britney, the alternative non-traditional
British spelling, it didn’t exist until 1980, in which case it totally shot up to like the top
100 and maybe with the most recent things that are going on, it’s dropped a little bit.
But through this whole region, what we have in our data, and I’ll show you the data in
just a second, is that Britney did not rank in the top 1,000 until the 1980’s and then it
jumped up. Because it started ranking in the top 1,000 in the 1980’s, it still shows up in
our data file because at some point it started ranking higher than that. And it turns out that
there are some people who just have names that, well, are not so popular. So we do
Mehran and nothing comes up because contrary to popular opinion, Mehran is not in the
top 1,000 most popular names. In a few years, you can change that if you have children.
Your choice. Not that I would advocate it, man. It’s a rough childhood. Mehran, doesn’t
that sound like moron? Yeah, I haven’t heard that one in the last two hours. Yeah, I
know. I’m just – rough childhood. Not that it affected me at all. So in terms of actually
doing this assignment, you might say, oh, that’s kind of interesting. Now there are a
couple of things going on. You might look at that and say, yeah, I could do that, Mehran.
I could do that in the zero to two-hour category, right, except for one little thing and the
one little thing is check out this bad boy. Whoa. As I resize the window – I will continue
to resize the window until I get you in a hypnotic trance – everything in the graphics
display automatically resizes to display for that window size, okay? And what you’re
going to find out today is how do you actually do this kind of thing to keep track of as the
windows resizing, how do you get events that come to your program that tell you, hey,
some resizing happened. I need you to redisplay what’s going on.
The other thing that’s interesting about this is I cannot only when I resize, it keeps track
of all the information that’s on there, Fred and Britney. If I ask someone else like, oh, my
son, William, who’s always been a popular choice – ah ha ha – just like in the top ten
dips briefly over here because maybe it was getting over used and then it comes back up.
Keeps them all. They’re in different colors. The color sort of cycles, so if we add
someone else, like Ethel – Ether, Ethel – yeah, Ethel, sorry, not so popular anymore.
When Lucille Ball – when “I Love Lucy” was on or earlier, it was a popular time. The
cycles of colors eventually will go back to black, so if we put in something like Bob, it
goes back to black. Then you’ll see red again, then blue, then magenta. That’s all given to
you in the handout.
If you hit clear, everything goes away, except for the gridlines, and you can sort of go
again from there, like here’s George and you can see George has a slight decline. Here’s
four back here and now he’s like somewhere in the hundreds. It’s okay if it goes off the
window occasionally, okay? But the resizing is kind of the key to this and that’s what
we’re going to – one of the things we’re gonna look at today. Okay.
So that’s what you want to keep in mind for the assignment, resizing, because the demo
that’s on the website because it runs in a web browser, doesn’t resize and it sort just has it
as the little warning down at the bottom. It just shows you how the program actually
works so you can try out typing in different names and see the behavior. But it doesn’t
resize because its size it stuck by the browser and changing the browser window doesn’t
actually change the size of the applet. That’s just life in the city, okay? But that’s the way
NameSurfer works.
So what we wanna think about is actually building programs that have this kind of
property and to understand how programs that have this kind of property work, what we
need to think about is something known as a component and related to that is a container.
So first of all, I’ll show you all the classes in Java that pertain to the components and
containers. Not all of them, but a good number of them. So here’s the classes in the
component hierarchy and some of these will look familiar to you. So programs of which
Console program and Graphics program that you’ve been using the whole time are japplet,
which is an applet, which is a panel, which is a container, which is a component.
So somewhere all the way up the food chain, right, the food chain before we didn’t go
that high. We just went up to applet when we showed you sort of this picture before.
Turns out all your programs are components and containers. Every component is a
container, or every container is a component. And so you may ask, well, what are
containers and components? So the way you wanna think about this is at some generic
level, a component is anything that can appear in a window. It’s anything that can in
some sense be displayed. So your programs are appearing in a window that’s getting
displayed. That’s why they’re components, okay? Now, that also means that a graphics
program and a console program are also components because they’re subclasses of
program. Now at the same time, there’s a notion of a container. What’s a container? A
container is simply something that contains other components, so a container just
contains a set of components and you might say, hey, Mehran, that’s really weird. A
container is a component, but you’re telling me it contains a set of components? What’s
that all about? And the simplest way to think about it is it’s this, okay? This is a
component, this bag. It turns out this bag is also a container because it contains things and
it’s perfectly fine for something to be a container and also to be a component.
So here’s what I mean, right. Your programs, as it turns out, are all components, which
means they display in the screen, but they’re also containers because your programs
contain other things. For example, in the display of your program, it may contain a
button. Right? It may also contain, say, a text field. And the other thing that it may
contain, if you have a graphics program besides these kind of components, which buttons
and text fields are also components – I’ll show you an example of that in just a second –
it may contain another container. And it’s perfectly fine for containers to contain
containers. As a matter of fact, you’ve been using them for the whole time. Your graphics
program, especially if you have a graphics program that has some interactors on it. It
could have buttons. It could have text fields. It could have a G-canvas, and gee, guess
what? A G-canvas is a container and a component. Because it’s a component, it can be
contained inside some other container, and because it itself is a container, it may have
certain things in it.
Oh, like here’s our friend, the frog image from the mid-term. Yeah, that was just
something that was in another container, okay? So there’s no reason why something that
is a container can’t be a component, which means it can be contained in some other
container, that’s fine, and all containers themselves are components, so they can be stuck
in somewhere else. That’s the basic idea. You should think of it as bags and you can put
bags inside of other bags, and bags contain things. So even though you see the hierarchy
this way, the concept itself is not actually that difficult. Now, the thing you wanna think
about this is I just mentioned to you your programs are actually components and
containers. G-canvas is a container and a component, but components that we talked
about before, j-components, like our friends, say, oh, j-button – you actually saw this
slide a couple classes ago, j-button or j-label or j-combo box, all these things you saw
before – are actually j-components. They all are subclasses of j-component, which means
by being subclasses of j-component, they were also containers, strangely enough, and
they are also components. We just think of them generally as components and we try to
put them in other containers, like we put them inside the display for a program and that’s
its container. But that’s the general idea that’s kinda going on here. So when you wanna
think about containers and components, what you also wanna think about is that these
components themselves, before we thought about like action listeners, right, like
something happens like I click on some component and some particular event happens,
like I clicked on it, something like that. We can think of the whole component as also
listening for other events because a component is something that display stuff on the
screen.
Stuff can happen to be components, like they can be resized and when a component’s
resized, some event can get generated and sent to that component that says, hey, guess
what? You got resized. You need to do something. Like the canvas that shows all the
graphics, it can get some event that says, hey, canvas, yeah, you were just resized. Do
whatever you wanna do. Up until now, you didn’t do anything. Someone came and
resized your canvas. You said, yeah, you’re resizing my canvas. All of the pieces I have
in my canvas stay where they are. Nothing’s changing. Now what you’re going to get is
the ability to have the canvas be told, hey, you got resized or something else happened to
you. You can respond to it however you want, which means you can redraw everything
that’s in your canvas, so that, for example, you can have all the layout come out just fine
when people resize your window. So what does that actually mean in terms of these
components and containers? What it means is that we can have listeners in the same way
that you kinda thought about listeners from mouse events and listeners for j-components.
You can have listeners for components, okay, like we talked about resizing the window.
Now, here’s a little simple example of something that can go on with one of these
components. So I’ll come back to Eclipse, I’ll run a little program here – I gotta compile
– and I’ll show you the very sort of simple program that makes use of this concept of a
component having a listener and being able to get certain events. So it’s just called My
Programming. Here’s what my program does. It draws a square. That’s all it does is it
draws in a filled-in square. You’re like why are you showing me this, Mehran? I could’ve
done this in the first week of class and I would say, no, you were doing terrible in the first
week of class. And then you say, no, I could’ve done this in the second week of class and
be like, okay, but could you do this? Oh. Yeah, when you did this before, that square just
stayed where it was and the size of the window changed. Nothing happened. Now the
square always remains in the center of the window no matter how I resize. It’s super
small. It’s still in the center. Super big, yeah. Another one of those things good for about
20 seconds. But that’s the idea. How does it know when the window’s getting resized that
it needs to do something to update its display? So the way this is going to work, in terms
of having this square that recenters itself, is we wanna think about having a program that
is a container. And so, up until now, you had console programs and graphics programs,
and they were containers and what they did for you automatically for console
programming, it created a console for you and put it in your container so that anything
you printed showed up in that console.
And for a graphics program, it created a G-canvas for you and put it in the container and
anything you drew showed up on that canvas. And now, what you’re going to do is
you’re going to create your own program that’s not a graphics program or a console
program, but to which you’re going to create your own canvas and add it. And so the way
that would look is you would say something like “Public Class” and give it the name,
whatever name you want, so I call this “My Program” and this is gonna extend just the
generic program. It’s not gonna extend console or graphics program. It’s just gonna
extend program. And so inside here, it’s still gonna have some init method, like you’ve
come to know and love in other programs. And inside init, what we’re gonna do is say
I’m gonna create a new canvas. But the canvas I’m going to create is a canvas that is a
new object I’m going to create myself to define what that canvas is, rather than the basic
G-canvas. So I’m gonna call this My Canvas. I’m going to do top down design. My
canvas is a class that doesn’t exist yet, all right? It’s not a built-in class. It’s my canvas.
It’s something that I’m gonna write the code for in just a second and I’m gonna have
some object called “canvas,” which is off top My Canvas and I will create a new My
Canvas. At this point, you should be getting a little bit worried unless you’ve internalized
top down design. If you’ve internalized top down design, you say, yeah, I’m just gonna
go create My Canvas when it’s time for me to write that code. For right now, I’m just
going to assume it exists.
And then what I’m gonna do is I’m going to add this canvas to my container. When I do
an add of something that is a component, in this case, canvas will be a component –
you’ll see why it’s a component in just a second – it says, hey, program, add this
particular element to yourself, and program says, hey, I’m a container, right? I don’t
already have a canvas. I don’t already have a console, but I’m a container. You’re giving
me a canvas, whoosh, the canvas goes up into my container, and if it’s the only thing in
my container, its size will expand to fill up the whole screen. Kind of like you saw last
time. And that’s it. So what I’ve don’t in this program is said, hey, I’m gonna have a
program. I’m gonna create a canvas where all the action isn’t gonna happen in that
canvas, and I’m going to add that canvas to the display and then I’m gonna let the canvas
do all the work. Is there any questions about this, just creating the canvas? So now we
can actually sort of define what is My Canvas and I’ll show you that on the computer
because it’s a little bit more involved. And you don’t need to worry about writing this all
down. Actually, on Friday, I’ll give you a handout that has all this code in it. I just didn’t
want to give it to you now because then you wouldn’t pay attention to what’s going on on
the screen, okay? So what I’m gonna do is I’m gonna have a class My Canvas. And My
Canvas is going to be a G-canvas, so it’s going to be an extension of a G-canvas. It’s
gonna extend G-canvas. So all My Canvases are G-canvases. Because it’s a G-canvas,
that means it’s a component. Because it’s a component, I can add it to a container. So
that’s why add works there.
Now, what am I gonna do with this thing? The other thing I wanna do is I wanna say,
hey, this is a component that’s gonna listen for stuff, and so the way I do this is rather
than doing add mouse listeners like I did before, or add action listeners, which look at
actions of things like buttons, the way a component actually listens is it implements the
component listener interface. So when you wanna have some component that is actually
gonna get events that it’s listening for, component events, the way you do that is when
you create the class, you say it implements component listener. That’s just the way you
say it, so it’s going to implement the interface. There’s some set of methods it needs to
provide that implement that interface and I’ll show you the list of methods real quickly.
They’re just down here. These four methods here, component resize, component hidden,
component moved, and component shown are the methods that comprise that interface,
the component listener interface. So anything that implements the component listener
interface needs to provide these four methods. In a lot of cases, you won’t necessarily
care that something happened and so, for example, if the component is hidden, which
means some other window comes over it, the component is moved, or the component is
shown, you’re like, yeah, whatever, like I don’t care. Those are good things. I need to
have methods that correspond to those things because in order to implement the interface,
I need to provide methods that correspond to all the methods that the interface is
expecting, so I need to have these. But in three of these four cases, I’m not going to do
anything, right? It’s just open brace, close brace.
Someone comes along and says, hey, guess what? You know you were occluded.
Someone hid you, so your component’s hidden, and you’re like, yeah, that’s cool. You’re
like, aren’t you going to do anything? No, I like hiding. And it’s like, oh, look, your
component was moved. Someone came along and moved your window. Aren’t you
gonna do something? And you’re like, no. No, I’m cool with that. That’s fine. You
moved me, all right? I won’t get into the music, but if you can think of that, what that
reference actually is, it’s not that difficult. Louie, Louie. Component shown, again,
definitely, so the only time we actually care about doing something is when we’re resized
because when we’re resized, we wanna say, hey, our component was resized. Let me
move that square to wherever the new center is of that window. So whenever my
component’s resized, I’m gonna get the component resized method called and I’m just
gonna call the method called Update. And what’s Update gonna do? Update’s right up
here. All Update says is remove all, so who’s the remove all message being sent to? It’s
being sent to myself because I’m not specifying any particular object to send this
message to. So when I say remove all, I’m sending it to My Canvas. Well, My Canvas is
a G-canvas, which means remove all, removes everything that’s on the canvas. It clears
the canvas, which means wherever the square was before, it just got cleared.
And what I’m gonna do is I’m gonna add some rectangle, and I’ll show you the rectangle.
It’s pretty simple. So what I have is I have a private G-rect that I call rect. It’s just gonna
be some private variable that I keep track of. In the constructor for my class, what I’m
going to do is I’m gonna – before I tell you what add component listener this does, I’m
going to create a new rectangle, who’s width and height are whatever I specify as
constants is the box width and box height. They’re just constants, not a big deal. And I set
it to be filled. So what I get is a filled square. I created this rectangle as a filled square. I
haven’t done anything yet with it other than create it, but I’ve created it and I have some
variable rect that refers to it. So all Update does is it says, hey, you know what? Remove
the square if it was anywhere on the screen before and now add that rectangle back at the
center location of the square, right? What’s the center location of this point? You should
be good, real good, with figuring out how to center stuff on the screen. You take the
width of the screen, subtract off the width of the object you’re displaying, and divide by
two. That’s the x location. You take the height of the screen, subtract off the height and
divide by two. That’s the y location. And this get width and get height will get the current
size of the component, which means when the components been resized, this update
method gets called, it closed the screen, and it gets rid of the old box and draws a new
box at wherever the new center of the screen is because this gets called, which means
Update gets called after the component’s been resized. So that way it’s gonna redraw the
square always in the center of the screen.
The only other thing about this program that you need to know is in the constructor for
My Canvas, My Canvas implements the component listener, so you not only need to say,
hey, I implemented the component listener, but you need to let the – you need to actually
say, hey, you know what? I am a component listener, so add me to the component listener
list, and the way it does that is you just call add component listener and you pass this,
which means myself. So somewhere, I say, hey, you know what? Add me to the list of
component listeners. I’m giving you a parameter to myself so you know who I am, so
when something happens to me, you can call my component resize method to get resized.
And that part up there, that Add Component Listener, is just a broiler plate, but it’s
gonna, for example, show up in your NameSurfer assignment because guess what? In
your NameSurfer assignment, when your component gets resized, you’re going to do
something very similar to this. You’re gonna find out what the new dimensions of the
screen are and redraw everything that should actually be on the screen, which means you
need to have some way of being able to keep track of the stuff that’s on the screen. So
any questions about this? All righty, so that’s the basic notion of this idea of a component
listener, okay, and what we wanna think about next is how do I create a larger program
with these kind of things. So this is just the simple hint. Now I’m gonna give you
something that’s even a bigger hint to what’s going on in NameSurfer.
And so what I’m gonna do is one thing that’s real popular these days is kind of like
music, right, like online music and albums and the whole deal. So what I wanna do is
implement a program that keeps track of data related to music and at best, I’m gonna
have a little music store, the program for the music score. And the basic idea here is that a
lot of what – well, I shouldn’t say a lot, but so far you’ve been – I don’t know. You did a
lot of games in this class and games are great and I totally encourage games, and I’m a
big fan of games. I got into computer science because of games. It’s a good time. But a
lot of what computers are actually used for as well, like when you go to some .dot com
site or whatever to like buy music, and I won’t name a particular one because I might get
sued, you know, it’s doing data management, right. For them, when you go to their site,
all they really care about are what are the songs they’re providing, do they – you know,
like you’re buying a physical CD, do they have it stock? Sometimes you just get stuff
downloaded that’s all digital. And the other thing they worry about is stuff like prices and
inventory management and stuff like that. But that’s really all that whole side is doing is
doing management of data.
So we’re gonna write a little program that does management of data, and the basic idea
here is someone comes along and gives us a data file called Music Data and the idea of
this data file is it’s a very simple format. And the basic format – I’ll just draw it out here
– is every line of the file contains information about one album that’s in the inventory and
the basic idea is there’s a bracket, here’s the name of the album, right. We can’t just use
spaces in this case because there might be spaces in the name of the album, but we kind
of assume there’s no brackets in the names of albums. So there’s the name. And then
there’s a space and a bracket, and then the band’s name that actually produced that
album, and then there’s an integer over here, which is the number in stock of that
particular album. So we have ten copies of Snakes and Arrows. Any Rush fans in here?
No? There’s like two? Times have changed, I’ve gotta say. All right. There’s not gonna
be any fans of this. Dokken? Anyone? Yeah, I would not advise it. And Smashing
Pumpkins. There might be a few – yeah, it’s a good time. It’s a good time. Old stuff a
little better than the new stuff, but that’s not important right now. What is important is
that we’re gonna have some data and our program is basically gonna manage this data.
It’s gonna read in this data file and allow someone to ask questions about for different
kinds of albums, do we have that album in stock, and how many of that album do we
have in stock. And do some nice little graphic display on it to make use of some of the
graphics concepts that we’ve actually shown.
So what I wanna do in this program – let me actually show you the program in operation
so you can see what’s kinda going on with the whole display and resizing the display and
why it’s the coolest thing ever. So when we run the program, I’m just gonna call this
program Music Shop. When I run Music Shop, what I get is basically a blank screen that
asks me for an album name, so I can come along and say, oh, do you have any copies of
Plans by Death Cab for Cutie – any Death Cab fans? It’s a strange name for a band. What
it does, it might be difficult to see, but it writes that album Plans by Death Cab for Cutie,
ten in stock, and it writes out little squares to indicate that there’s ten. It writes out ten
squares and you might say, okay, Mehran, that’s not the greatest display in the world, and
it’s not. This display I wrote in a half an hour last night, but what’s kind of cool is, ah,
look, it centers this way. And here’s the other cool thing. Look at the size of the boxes.
They get smaller and they expand, so they always have the same spacing, but as I expand
out or get smaller, they resize. The fonts don’t resize. They just recenter. I could, for
example, put in perhaps one of the greatest albums of all time, “So” by Peter Gabriel.
There’s 20 copies in stock as everyone should own a copy, and if you don’t, that’s okay.
It’s perfectly fine. And sometimes I might type in a band that doesn’t exist or an album
that doesn’t exist, like I might type in – I don’t know – cow, which is – there’s probably
an album out there called Cow. I don’t know why I always pick Cow. I just do. In which
case, it definitely disappears. Like we don’t have that in stock. Just back off, man.
So that’s what’s going on in this program. So we need to be able to resize the bars and we
need to vertically center the stuff we display in the screen. How do we actually do that?
So one thing we wanna keep track of is you wanna go back to the data, right? You
actually wanna say if I need to do this, in order to display anything, the first thing I need
to do is figure out some information about the data that I wanna store. So what data do I
wanna store? Well, I probably wanna store some information about albums because that’s
what I have in my data file. So if I think about my data file and wanting to encapsulate all
the information about one album, okay, I wanna do something on a per album basis
because every album is gonna have, for example, an album name. It’s gonna have some
band name that produced that album. And some number that’s in stock, like Num
Stocked. Oh, and this is a string and this is a string and this is an int and it’s good to put
semicolons at the end of them and it’s probably a real good idea to take this whole thing
and turn it into a class that’s gonna encompass all this because what I want to have is
modularity in terms of my data. If there’s a whole bunch of data I wanna manage, the
first question I wanna ask myself is what’s the basic element of data that I want to have?
In this case, the base element is one album. I’m gonna have a bunch of albums, but the
basic idea is one album and an album’s gonna contain an album name, a band name, and
a Num Stock, which are, for example, gonna be private fields of that album.
So one of the things I might wanna do and I’ll just show this to you real quickly, is I
would create album.java, which is just some class. It doesn’t extend anything. It’s just
gonna be a class to keep track of data and what it’s gonna do is it’s gonna have some
private instance variables, album name, band name, and Num Stock, that’s gonna keep
track of the information from one album. And then it’s gonna have some other methods.
One of the methods it’s gonna have is the Constructor. What does the Constructor do? It
says, hey, you want an album object? Give me a name for the album, a name for the
band, and a number of stock. I’ll set all my internal variables to those things. I’ll do a
little annoying pop-up on the screen and what you’ll get from your constructor is you’ll
get an album object that encapsulates that information. Now, I made all this stuff private,
right, album name, band name, and Num Stock, because what I wanna do is when you
create the album, you say, hey, this album’s in stock. I don’t want you to go back and
say, hey, no, no, no, the name of that album changed. That’s not what happens, right?
When an album’s released, the name stays the same, generally. We won’t talk about
special cases. So in order to get the information out of an album object, I need to have
some getters. I can potentially have setters as well, but here I have some getters. Get
album name, get band name, and get Num Stock. Pretty straightforward getters. You’ve
seen getters in the past; not a whole lot of excitement going on there.
The only other thing I might add, which I told you in the days of yore that you didn’t
have much need for until now, is to have a 2-string method, just returns a string
representation of that particular object if you ask for string representation. So it just
writes out “album name” by band name colon the number stock in stock. So it can return
to you a string that basically has all the information about the object in some nice little
display format. That’s the whole class, okay? This is just a simple class that keeps track
of information about one album because we’re gonna have a bunch of albums that we
wanna keep track of. So now that we can keep track of information about one album, it
kind of brings up a deeper question. The deeper question is we don’t wanna keep track of
just information about one album. We, in some sense, wanna keep track of a whole set of
albums, a database of albums, and what we wanna do if we think about a running
program – so I’ll go back to the running program – is we wanna allow someone, given a
particular name for an album, to be able to go look up all the information on that album.
So the way you wanna think about it is given a name, I wanna go and look up the record
for that particular thing. And this happens all the time. It happens with your student I.D.
records, except we don’t do it by name. We use student I.D. reenact records. We say
given your Stanford student I.D., let’s go grab a record of all of your information. It’s
exactly the same problem. This is just the simple version with albums. So if we wanna
think about having some mapping, where, for example, from some name, we can go get
the whole information about that record. What kind of data structure might we think
about? What kind of thing that you’ve seen before?
Ah, yeah, the whispered HashMap. Could it be the HashMap? And in fact, yes, it could
be a HashMap. And the thing you wanna think about with the HashMap, that’s very
concentrated. It’s a low variance event where it’s kind of tougher the whole time and
you’re like, ah, everyone. Yeah, it’s early. It’s before Thanksgiving. Have some sugar.
We can think about a HashMap. Now when we think about having a HashMap –
suddenly, everyone wakes up. Food? Food? Bark, bark. I know, sometimes. Anyway,
HashMap, what are we gonna map to? What are gonna be the two types that our
HashMap is parameterized by? What’s the first type? What are we gonna look things up
by? What’s the key? String, right? We’re gonna look things up by the name, which is a
string. When we look something up, what do we wanna get back? An album. So what
we’re gonna have is a HashMap that maps from strings to albums, and I think someone
said album right over here, although I think I missed you. Sorry. I missed you again. So
the basic idea is given some name, I’ll go look up the whole album and at this point, you
might say but Mehran, isn’t the name inside the album? Yeah, that’s fine. In your student
record, it also contains your student I.D. and your name. We just happen to look it up by
your student I.D. and it’s the same thing here. The user’s gonna give us the name to look
it up. When we go look it up, it’s fine if the name’s also contained in the album, but
there’s a whole bunch of other information we care about there as well. So if we have
some HashMap, we’ll call this particular HashMap “Inventory” and we might say new
HashMap that’s gonna map from strings to album, and there’s the constructor. And so
that’s how we might actually create this particular HashMap.
So once we have this HashMap, if we’re gonna have some object inventory that’s a
HashMap of all these things, we need to load it up. We need to say, hey, all my data is
actually sitting in a file somewhere. What I need to do is read the data in from the file and
as I read the file line by line, every line I’m gonna create one of these album objects
because every line is information about one album, and after I create this album object,
I’m gonna add it to my HashMap and so my inventory’s gonna be all of my albums
mapped to by their name. Any questions about that basic idea? So let me show you the
code for them. What does that actually look like? So here’s album. You saw album. What
I’m gonna have is I’m gonna have My Music Shop. What’s My Music Shop gonna do?
Before I show you everything else the Music Shop’s gonna do, it’s gonna have this
HashMap. It’s gonna have a HashMap for inventory that’s a map from strings to albums,
and it’s initialized just the same way you saw it over here, and the way I set this up is I’m
gonna have some method I’m gonna call – called Load Inventory. What’s Load Inventory
gonna do? It’s going to have a buffered reader because I need to open a file and I’m just
gonna hard code my files called musicdata.txt. I go and I read the file line by line, so I
grab a line from the reader. If it’s the last line of the file or there’s no more lines left in
the file, I’m done. Same thing you did with file crossing before. If there is a line there,
then I’m going to write some method that’s top down design called Parse Line, which
says, hey, let me give you this string that I just read in. It’s a whole line of the file. You
break up the string into all of its fields and create an album object that contains all that
information and return that to me and I will assign that to something I’ll call album,
which is a type capital A Album. And then what I’m gonna do is I need to put that in my
inventory, so in my inventory, I’m going to put it. How am I going to put it in there? I’m
gonna put it in by the albums name is the key, so I just say, hey, I have an album object
that contains all my information now, so album.getalbumname will give me the name.
That’ll be the key, and the thing that I wanna store relative to that key is the whole album
object. So this just line by line reads the line, parses it – I’ll show you how to parse it in
just a second – to create an object, and then adds that object to this HashMap I’m creating
that’s gonna store everything. Know this, live this, learn this, love this. You’ll do this for
NameSurfer. So after I do all this stuff, I close off my file and I’m done because
presumably, I should’ve read the whole file and put everything into my database and I’m
done. I do my little exceptions with file reading, just in case I had exceptions. So the only
code you haven’t seen so far is parse line. What’s parse line doing? Parse line is a string
manipulation extravaganza. So what’s parse line doing? And I’ll just go through this very
simply. It’s a lot easier than it looks. Basically, it’s just a lot of indexing for strings. What
I do is I say, hey, I got a whole string that has – oh, I erased it up here, but basically,
starts off with a bracket, has the name of the album, the name of al, has the name of the
band, and has some number that’s an integer. So how do I break this up into sub pieces
that I can actually store in my structure?
Well, the first thing I’m gonna do is I wanna pull out the name of the album. How do I
find the name of the album? The name album starts after the first opening bracket, so I
find the index of the first opening bracket and add one to it. That’s the first character of
the album name. How do I find where the end of the album is? I look for the index of the
closing bracket, and so basically, if I take a sub string from the start of the album name to
the end of the album name, I pull out that piece of text that’s just the album name and I’m
gonna store that in a string called Album Name, which is just a local variable. So now
I’ve pulled out the album name. How do I get the band name? Band name, I look for the
index of the first bracket after the album name. That’s the critical thing. If I don’t look
starting after the album name, I’m gonna read the album name again. So I look for the
first bracket after the album name, which is ed album name end plus one. That will get
me the index of the bracket where the band name starts and I add one to that, which gets
me to the first character of the band’s name.
And then I do the same thing over here. Where’s the end of the band’s name? Get the
index of the closing bracket starting at the end of the album name so I don’t get the
closing bracket for the album name. I get the closing bracket for the band name. So I start
at the album name plus one. So now I have the boundaries for the band’s name and so the
band’s name is just the substring I get in the line from the starting index for the band’s
name to the ending index for the band’s name. Now, the final thing I need to do and this
is funky thing. It’s probably the funkiest thing of this whole function, of this whole
method, and it’s pretty simple, which is say that last thing that’s on the line is actually
integer, so I don’t wanna pull it out as just a string. I need to actually convert that string
to a real integer. How do I do that? Well, let me first find out where that number actually
lives. Where do I find the number? I look for the number by finding the first space after
the end of the band name. The first space after the band name is gonna be this index right
here. The number starts on the next location, so if I take that particular location, after the
end of the band name, and add one to it, I now have an index that’s the very beginning of
the number of that numeric sequence. So what I wanna do is I wanna say pull out that
numeric sequence as a string and convert that string to an actual integer. How do I do
that?
Well, the way I pulled it out is I say take the substring of the line that starts at the starting
position of the number of the number stock. That’s where I just computed in the last line
was where that number starts. Because I don’t specify an ending index for this substring,
it goes till the end of the line, which means it takes all the characters. If there happens to
be like 100 in stock, it starts at the one and takes the 100, it takes that whole substring as
this substring right here, and what do I do to that? There’s a method that’s a static method
of our friend the integer class called parse ins, and so if you say integer.parseins, you give
it a string, it converts that string into its integer equivalent. So what it does is it says, hey,
I’m giving you the number that’s the number stock as a string. It says okay, I’m gonna
parse that and turn it into an integer and what I will give you back is something you can
store as an int. So that’s how we convert that last portion of line from a string to an
integer. We first extract it and we get the integer. And then what are we gonna return to
the person who called our function? We’re gonna return a new album object, we’re gonna
create a new album object, where we initialize the album object to have the album name,
the band name, and the number stock that we just parsed out of that line. Are there any
questions about that? Standard thing you do in files, you pull out a line as a string, you
break up that string using some string manipulation operation, however you wanna break
it up, and then you potentially create some object out of it so that you can store all of the
nice things that you extracted out of the string into nice little name fields.
So this gives you an album object. Then back up here, that album object is getting
returned by parse line. We put those album objects into our inventory HashMap indexed
by the album name. Are there any questions about that? If that’s clear, nod your head.
Good time. All right. And that’s basically the role loading of the database. Now the only
other things going on here is we need to figure out our little interactors, right? So in our
program, we have a label that asks for the album name where the user can type the album
name, so we put in a label. Then we put in a text field that has a maximum size of 20,
right? At this point, this should all be sort of old hat. We add the label to the southern
region. We add the album name, which is just a text field that’s gonna take in the album
name for the southern region so we get those two interactors. We get the label and the
text box, okay? And the things we wanna do after we set up the interactors is we say, hey,
I need to display the stuff somewhere. Mehran, I remember he told me, oh, about 20
minutes ago, that if I wanted to actually have some canvas that could resize itself
automatically when the user changed the window, what I need to do is extend the Gcanvas.
I need to create in my own version of canvas and make it a component listener.
That’s the same thing I’m gonna do here. I’m gonna create something called a Music
Shop display and Music Shop display, which I’ll show you the class for in just a second,
is something that I’m going to store as my canvas as a private variable inside my class.
And I’ll just go ahead and say, after you put your little interactors on this screen, create
your new canvas and add the canvas, just like I did before in the previous program, now
load all your inventory, so go read the file, do all that parsing, the funky stuff, set up the
inventory. Add action listeners because I wanna be able to listen for events that actually
happen on the buttons and also add the text field album name as an action listener. So it
basically wires everything up. It says put in the interactors, create the canvas that I’m
gonna draw stuff on, load the inventory into data, and get ready to listen for stuff. And
then it’s ready to go. It’s not gonna do anything until I get some events, but now it’s
ready to go. So load inventory you saw, parse line you saw. The only thing you haven’t
seen is what do I do when an action’s performed.
I don’t have some button the user compressed. All I have is the text field, so when they
hit enter, I check to see if the source is the text field album name. If it is, what I’m going
to do is ask the canvas to display the inventory of a particular album. How do I get the
particular album? What I do is I’m gonna say what I want you to display, I’m gonna give
you an album object that’s gonna contain all the information you need to display, so I’m
gonna call display inventory pass in album object. How do I get the album object? I say,
oh, text field, give me the text that’s in you. It says, oh, here you go, and here’s what
these are typed in. That should be the name of an album. I can use that name for an album
in a HashMap to look up the album object, so in my inventory HashMap, I say get on the
album name and if there is an album object in my inventory HashMap, that’s what I’ll get
back. If there isn’t, I’ll get back null and I’ll go ahead and call display inventory with
null, so it needs to know how to handle that. So all the action to do the display is gonna
happen in display inventory. So let me show you musicshop.display, which kind of pulls
this final thing together. These are shock display extends G-canvas, just like you saw in
the previous example with the little square, implements component listener, just like you
saw in the previous example, and it just has a little bit more complexity. The only
additional complexity it has is in its constructor. As before, it needs to add itself as a
component listener. That’s broiler plate. But it says, hey, you know what? I’m gonna
keep track of the last album the user actually typed in because when you resize the
window, what I need is the information about that album to redraw everything in the
window relative to that last album. So when I start off, there was no last album, so I set it
to null, but as soon as you give me a real album, that’s what I’m gonna store in last
album, is the last album from the user. I’ll show you a few things down here. So last
album is basically just album that I keep track of in album object, in last album
[inaudible]. I have a few constants that indicate for me how big things are gonna be on
my display and I can get all the methods of a component listener. Again, the only one I
care about is the resizing event. The other ones I ignore. On the resizing event, I’ll call
Update. If I call Update on the net display, display from my inventory the last album that
I displayed. So if I had something in my display and my display got resized, basically all
I wanna do is redisplay that last album in the same graphics window.
So Update calls display inventory or I can call display inventory directly from my main
program to display something. And this is way more complicated than it looks, so I’ll just
briefly tell you what it does. It clears everything that’s in the display from G-canvas
currently by calling Remove All. That is you just gave me an album to display. The last
album that I wanna keep track of, the thing that I wanna keep track of in display next
time I get resized or whatever is the album you just gave me because you just saved me a
new album to display, so that’s gonna be the album I keep track of to display on resize
events. If that album was not null – if it was null, I’d just clear the screen. I wouldn’t do
anything else. If it wasn’t null, it means that you had a real object in your inventory that
was an album, so there’s some work for me to do. What am I gonna do? I’m gonna ask
that album for the number that are in stock and I’m gonna create a label that has album
and the name of the album by and the name of the band, and I’m gonna place it on the
screen at a location that’s censored based on the height of the current display. Then I’m
gonna have a fore loop that displays squares that indicate – shouldn’t be dictated; it
should be indicated – how many are in by inventory. I won’t go through all the math
because the math is not interesting. The only thing that’s interesting about this is I have a
fore loop that goes through the number in stock and draws one filled in rectangle for
every number in stock. What’s the size of that rectangle? The length of that rectangle is
called the broad length that depends on the total size of the window. So I look at the total
size of the window and I divide by however many maximum squares I can display in the
window, which happens to be 20, to get my size. So as the window gets smaller, the
display object’s gonna get smaller and as the window gets larger, broad length will get
larger. So it depends on the size of the width of the window.
And I do this in a loop so basically, it just draws all the squares. And you can go through
the math on your own if you’re interested in it, but the basic idea is the squares just size
depending on the width of the window. Last but not least, I write out another label that
says how many are in stock and where I display this on the screen depends on the height
of the window because I’m in the center. So as the height of the window changes, this
will always recenter as well. And that’s where all the action is, so when I run this
program, it starts off not doing anything. And when I type in an album – let’s use Snakes
and Arrows because I think that’s in there – I get a bunch of squares and it’s just sitting
here. If I type in an album that doesn’t exist, like Cow, it clears the display and there’s
nothing to display. But if I happen to type in – I’m gonna do Snakes and Arrows again –
something actually does display. When I do the resize, it’s resizing based on the size of
the window because it knows what the last thing displayed was, right. It knows the last
thing displayed was the album Snakes and Arrows and it’s storing that in its own local
variable, so that when I resize, it knows what information to redisplay on the screen to
resize. Any questions about that? We’ll do exactly the same thing in NameSurfer and I’ll
give you all the code you just saw.
[End of Audio]
Duration: 50 minutes

Mehran Sahami Handout #38A CS 106A November 14, 2007

Mehran Sahami Handout #38A
CS 106A November 14, 2007
Solution to Section #7
Based on a handout by Eric Roberts
// File: BoxDiagram.java
// This program allows the user to create a set of boxes with labels
// and then drag them around in the window.
import acm.graphics.*;
import acm.program.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
public class BoxDiagram extends GraphicsProgram {
/* Initializes the program */
public void init() {
contents = new HashMap<String,GObject>();
createController();
addActionListeners();
addMouseListeners();
}
/* Creates the control strip at the bottom of the window */
private void createController() {
nameField = new JTextField(MAX_NAME);
nameField.addActionListener(this);
addButton = new JButton("Add");
removeButton = new JButton("Remove");
clearButton = new JButton("Clear");
add(new JLabel("Name"), SOUTH);
add(nameField, SOUTH);
add(addButton, SOUTH);
add(removeButton, SOUTH);
add(clearButton, SOUTH);
}
/* Adds a box with the given name at the center of the window */
private void addBox(String name) {
GCompound box = new GCompound();
GRect outline = new GRect(BOX_WIDTH, BOX_HEIGHT);
GLabel label = new GLabel(name);
box.add(outline, -BOX_WIDTH / 2, -BOX_HEIGHT / 2);
box.add(label, -label.getWidth() / 2, label.getAscent() / 2);
add(box, getWidth() / 2, getHeight() / 2);
contents.put(name, box);
}
/* Removes the box with the given name */
private void removeBox(String name) {
GObject obj = contents.get(name);
if (obj != null) {
remove(obj);
}
}
– 2 –
/* Removes all boxes in the contents table */
private void removeContents() {
Iterator<String> iterator = contents.keySet().iterator();
while (iterator.hasNext()) {
removeBox(iterator.next());
}
contents.clear(); // Clear all entries in the hashmap
}
/* Called in response to button actions */
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == addButton || source == nameField) {
addBox(nameField.getText());
} else if (source == removeButton) {
removeBox(nameField.getText());
} else if (source == clearButton) {
removeContents();
}
}
/* Called on mouse press to record the coordinates of the click */
public void mousePressed(MouseEvent e) {
last = new GPoint(e.getPoint());
currentObject = getElementAt(last);
}
/* Called on mouse drag to reposition the object */
public void mouseDragged(MouseEvent e) {
if (currentObject != null) {
currentObject.move(e.getX() - last.getX(),
e.getY() - last.getY());
last = new GPoint(e.getPoint());
}
}
/* Called on mouse click to move this object to the front */
public void mouseClicked(MouseEvent e) {
if (currentObject != null) currentObject.sendToFront();
}
/* Private constants */
private static final int MAX_NAME = 25;
private static final double BOX_WIDTH = 120;
private static final double BOX_HEIGHT = 50;
/* Private instance variables */
private HashMap<String,GObject> contents;
private JTextField nameField;
private JButton addButton;
private JButton removeButton;
private JButton clearButton;
private GObject currentObject;
private GPoint last;
}

Programming Methodology-Lecture21 Instructor (Mehran Sahami)

Programming Methodology-Lecture21
Instructor (Mehran Sahami): So welcome back to the beginning of week eight. We're
getting down to the end. Well, we've got a few more weeks to go. It feels like we're
getting down to the end, though. It's one of those inverse relation things for the amount of
work. The amount of work you do as the quarter sort of reaches the end goes up. The
amount of work I do goes down, which I shouldn't laugh about, but that's just the way it
is.
There's two handouts today. One handout's your section handout for this week. Sections
are still happening this week. The other handout is some code on interactors that you saw
last time as well as some additional code that we'll go over today on interactors. Other
announcement, computer science career panel. So just a quick show of hands, how many
people are thinking about computers science as a major?
A few folks. How many people thought about computer science as a major prior to taking
this class? And now they're not thinking about doing computer science as a major? All
right. Sorry. How many people were not thinking about computer science prior to this
class that are now potentially thinking about computer science? A few folks in there, too.
That's good to see.
So this computer science career panel, one thing that people make the mistake of doing is
to equate computer science with programming, which is not at all the case. So if you're
trying to make a decision about whether or not to major in computer science just based on
this class, if you like programming, you should do computer science. You'll be a great
computer science. No doubt.
If you don't like programming, but you were thinking, hey, computer science might be for
me, in fact, many computer science majors don't end up programming after they
graduate. But having a computer science degree opens up doors for them to go into the
industry, in roles which, otherwise, they may not have been able to go to. So if you want
to find out about careers in computer science, and so the folks on this panel include some
people who are engineers, people who are at startups, people who are big companies,
people who are doing design, people who are doing product management. There's also
someone on the panel who went into academia, so not me, but another new professor on
the department. He'll also be talking about careers in academia on this panel.
It's Wednesday, November 14, 5:30 p.m. in Packard 101. There will be food, so don't
worry about missing dinner because there will be food there. There'll folks and there'll be
fun, and there will be computer science. So you just got to make everything start with an
F, and there aren't that many C-words.
So with that said, it's time to delve into a continuation of our last great topic. So it's time
to continue a bit with our friend, the interactor. If we think about the interactor and action
listeners – so last time we talked about having buttons and buttons generated action
events. Remember that? So we're going to do a brief review of that and push it a little bit
further.
So one of the things we talked about is having your program say in your innate method,
innate, somewhere you might have public, void, innate and inside here, you would set up
the parts of your program that you want to actually do something like the various
interactors, that when someone clicks on them, something happens. Then you would say,
add action listeners. What this would do is basically say, hey, I got some buttons in my
program. I want you to be listening for buttons.
So when someone clicks on a button, I want you to call a particular method for me, called
action performed, and then based on when you call action performed, I'll figure out what
button was clicked and then actually do something. Okay? So over here, we had our
friend, public void action performed. And action performed would get, as its parameter,
something called an action event. An action event, we'll just refer to it as E, was basically
what it would check to see what action was actually taken or basically which button was
actually clicked.
So hopefully you remember that. That's just a little bit of review from last time. Now
when we've got this action event, and we said there are a couple things you could do with
it. There was actually one main thing we talked about that you could do with it, and you
could figure out which command was actually the thing that caused this action event to
be generated by saying, hey, you know what I want to do? I want to pull out, as a string,
and I'll just call it CMD for command, the command or the name of the interactor that
caused this action performed method to be called.
So here I would say E dot command equals E dot get action command. And what get
action command does, it's just a method of this action event that says, I'll return to you
the name of the interactor as a string, and button's names are basically just whatever
display's on the button.
So then I can have some ifs in here based on this command. If command dot equals – and
I can check for some name that I might want to take some action based on that button. It
turns out there's something else you can ask this action event, E, for, other than the action
command. You saw this very briefly last time, and the program that we did, and you're
going to see it a little bit more now.
So I want to spend a little bit more time on it. It's something where you can say, E, what I
want to get from you is not the action command. I want to get the source of the action.
Now, the interesting thing about what get source returns to you – actually, let me not put
the semicolon here right now – is get source actually returns to you an object.
It returns to you the object that caused this even to be generated, which means if a button
was clicked, E dot get action command will get the name of the button. E dot get source
will actually give you a reference to the button object. So what you're getting back from
this is an object. You're getting a reference to that object.
So what does that mean for you in your everyday life? What that means is over here,
when you want to set up your initialization, you could say, I want to create a button. So
I'll have some button I want to create. So I'll say new J button, and maybe that button, I
want it to say hi on it. Okay? So one thing I can do is I can say hi equals new J button. Hi,
what I'm going to do is make that an instance variable. So somewhere down here in my
program where I have my I vars, my instance variables, I would have private J button hi.
So I just do the declaration of a variable called hi, which is of type J button, and then in
my initialization method, I actually create that button with the label hi on it. Then I go
ahead and add it somewhere to one of the control bars in my program. So I would say add
hi maybe to the south control bar because we really like adding things to the south control
bar. It's just fun when buttons show up on the bottom of our screen.
So we say add it there, and then wait for something to happen. So add my action listener
in case this button gets clicked. Now when the button gets clicked over here, what I can
do – I could actually ask command to get its name. Or I could ask action event to get the
action command name, and then I could say something like if command dot equals and
the name of the particular button over there happens to be hi, then there's something I
want to do. Maybe I want to print something on the screen or whatever the case may be.
That's one way I could write this, and that's the classic way that you've seen it written
before. That's the way you saw it last time. The other way I can write it, with my friend
get source, is rather than getting the name of the command and checking to see if the
command is equal to hi, I can actually say, Maron told me about this thing called E dot
get source. As a matter of fact, I don't even need this line for command anymore. Let me
just comment it out so I don't erase him.
I can say if E dot get source – this returns an object to me. I want to check to see if that
object that it returns is my hi button. So here, I check directly, is it equal to hi, and then I
do whatever I was going to do. So this has exactly the same effect as before. It's checking
to see if I've gotten a button that is the hi button that was clicked. So the difference
between these two things, if you kind of think about them, one of them is I'm just using a
name as a string, and the other ones, I'm using the actual object.
Now, if you think about it more deeply what that means, if I think about the name over
here, if I think just in terms of the name, I never need to be able to refer to the actual
object. Which means if I don't need to refer to the actual object again over here, I don't
necessarily need it as an instance variable. I only need it as an instance variable if I'm
going to refer to it again in some place that's in a different method than some other
method I may have already used it in.
So let me show you an example of what I mean by that in code to make that more
concrete. So if we come over here to code, here's essentially the code I just wrote for
basically reacting a button. So it's just the code I wrote on the board, except I made the
font bigger. I create a button with the name hi. I put it in the southern region, and I add
my action listeners to listen for that button getting clicked.
When the button gets clicked, I say, is the thing that got clicked this button that I created?
Here I actually called it hi button instead of just hi over there. I shortened it to hi so it'd
take up less board space.
If it's actually the source of that action, is my hi button, then I will print out hello there.
So I can go ahead and run this program. If I run this program, this is – I click hi, I get the
same thing I saw before. Every time I click hi, I get hello there. Now, alternatively, I
could've written this slightly differently, which is the way you saw it last time.
What I can do here is I can say, when I'm going to do the add, just go ahead and create
that button and add it, all in one line because I don't need to have some variable that
stores the button. Down here, I don't need to check for the source of what that action
event was. I'm going to say, action event, give me your command. The command is going
to be the name of the button, so I no longer need a variable to actually store a reference to
the actual button object because this is going to give me the name whenever I need it.
So as a result, notice here I don't have an instance variable. So this is one of those things
that's a tradeoff. It should also give you a little bit more insight into when you have
instance variables versus when you don't have instance variables. You need to have the
instance variable in the case, where you need to – wrong line. I want the new one. You
want the instance variable in the case where you want to be able to refer to this variable
in some method that's different than perhaps the method, which got created.
So I created the button over here, and I stored it somewhere, but I need to be able to refer
to it in some other method, so it's got to be an instance variable. If I don't need to refer to
it in any other method, which is what I saw in the second case, I don't need to refer to it
again. As a matter of fact, there's no other place I need to refer to it after I create it. Then
I don't need to store it anywhere. Any questions about that?
Student: [Inaudible]
Instructor (Mehran Sahami): So that's a bug in your logic. The computer shouldn't try
to figure out which one because if you give it two buttons with the same name, it says, I
have no idea. It's going to cause you problems, so don’t do it. If you want to see what
happens, go ahead and try. It's a bug in logic, not a bug in what the computer's executing.
Any other questions? Uh huh?
Student: [Inaudible].
Instructor (Mehran Sahami): It's still going to get the actual button, so you're saying in
this other case over here, what is this thing going to return if I didn't create a variable
over here? This thing's still going to return some reference to your object. The only issue
for you now, though, is you have no way of checking for equality with some object. If
you don't have this as an instance variable, you can't check to see if that thing's equal to
hi button.
So if you created hi button over here and just immediately added it and never kept track
of it over here, this guy would return to you a pointer to hi button, and you'd say great, I
got a pointer to hi button. How do you know it's hi button? You don't. You have no way
of comparing it to the actual hi button you created. That's why we need to store it.
All right. So why do I show you these two different ways of doing it? The reason why I
show you these is because now you're going to actually make use of this with respect to
some other interactors that you're actually going to see where we care about viewing get
source as opposed to the action command.
So what we're going to do next is we're going to say, you know, a lot of times in
programs, what you really want to have is some way of letting the user have some way to
specify some text in a program that's running interactively that's not in the console.
They'd like to be able to type something in, so let me just show you an example of this.
So here's a little program that's go what we refer to as a text field down here, and I call
that name. So if I say, hey, my name's Maron, it says, hello, Maron. I say, no, my name is
really Sally. Most of you don't know this. It says, oh, hello, Sally. It's just some way of
being able to have some text field over here that the user fills in. This is an interactor,
right? This is just one field. It's not on the console. Then do some action, and the action
we happen to do here is just to write something to the console that makes use of the text
that the user actually typed in.
So how do we get something like that to work? So what we need to do is have an
interactor that's called the text field. Basically, text field is just that thing you saw. It's a
little place where someone can type some text as an interactor. So it shows up in one of
the control bars, and then potentially, when they hit enter, you get some action event that
tells you, you need to actually – of if you want, you can do something with this text. So
that's the basic idea.
What you really get is a box, and that's all you get with it. If want to add a label to that
box, like we added name over here, we need to specify that. I'll show you how to do that
in just a second, but what you get is the box. The user types in something and then hits
the enter key. Then potentially some event is generated for you. So how is that actually
set up?
So the thing we want to create is a J text field. It's just another one of these interactor like
you saw before with check boxes and combo boxes and all that stuff. It's just called a J
text field. I'll name this one TF to stand for text field. What you do when you create a
new one of these is you say, new J text field. What you give it as a parameter, and here's
the funky thing.
You don't give it its label. The label doesn't come with the text field. You need to create
the label separately. What you give it is the size of that text field, how big it should be in
terms of the maximum number of characters that would show up in there. So if you say
ten, for example, what you're saying is I want to have some text field that will hold, at
most, ten characters. If you use some font that's variable with it, it automatically gives
you the size of 10 Ms because M is the widest character, in case you didn't know. That's
just life in the city.
Now the funky think about this, relative to this action performed, is when the user hits
enter, if I didn't do anything else, you would not actually get this call to action performed
because action performed is only called for you for buttons. So what you need to do is
after you actually create this text field, you need to say, you know what, I need to let you
know about this text field as something that can generate actions.
So the way you'd do this, because it looks a little bit funky, but you tell the text field dot
add action listener this. Okay? You don't need to worry about all the way does that
actually mean at a very low level. All you need to know is you're telling this text field,
you're going to be able to generate actions now, and the thing that you're going to let
people know when you generate some actions is yourself, which is why we passed this.
But anytime you create a text field, and you don't just do this once for all text fields. If
you have multiple text fields, you need to send this add action listener this message to
each one independently. We only have one here, so we only need to do it once here.
But what this basically does is says, text field, you can now generate these action events
as well. So after you create it and you set up this line – and you would want to add it
somewhere into your program. So in your program, you would probably say add TF, and
we might add TF, for example, in the south because we add everything in the south.
When someone types something in to TF and hits enter, then it will generate some call to
action event for you or action performed and pass you an action event. Now once that
gets set up, how do you actually figure out what was the text field that generated this
event. You could have multiple text fields that someone could've typed into and hit the
enter key. What you're going to do is you're going to add E dot get source. So inside here,
what you're going to say is if E dot get source is equal to TF. At this point, all kinds of
warning bells should go off for you. So maybe inside here, you want to do a printlin
where you want to say hi and then add to it the text that's in that text box.
The way you do that is you just say the name of whatever the text field is and the
message you send it is get text. What it will give you back is it will just return to you this
thing by itself. It just returns a string of whatever is in that box when the user hits enter.
So this will write out hi and then whatever text you typed in, just like you saw in the
program. Except that was writing hello, and maybe that's what we want to do.
But the warning bells that should be going off now, what's the problem if I've just written
a code like this?
Student: [Inaudible]
Instructor (Mehran Sahami): It's not an instance variable, right? So I have no way, if
this is my innate method over here, of being able to refer to TF again out here. So I need
to create the instance variable, right? If this is my innate method, and I have public void
innate in front of it. What I need to do is this TF, somewhere else in my class, let's say
over here, which is where I declare my I bars. It's just lower down in the class
somewhere. I need to actually have private J text field TF.
Then over here, rather than declaring it, I just create the new TF. So I need to set it up as
an instance variable, just like you saw in the example with the buttons. The same kind of
thing's going on here, except it's a text field.
So let me show you an example of this code in action. So here's a little text field example.
What I'm going to do is I'm going to extend the console program. So I'm still going to
have a console. In my innate, I'm going to have something called name field. What's
name field? It's just a private J text field. It's an instance variable, so I can save off name
field. Name field, I initialized over here to be some new J text field of size ten. This is
exactly the code you just saw over there.
Now what I also want to do, here's the one extra funkiness in the program. I want to give
that box a label. So before I add this box to my control bar, I'm going to add a new J label
that just says name. So all J label does, it just says I'm going to create something that's
just this name or just this particular piece of text. The text happens to be name, and I'm
going to add that to my southern control bar.
So first it's just going to write name out there, and then after I write name, I'm going to
add my name field, which is going to create the box after name. Then I'm going to do
exactly what I told you where you have to tell name field, you're going to add action
listeners of yourself so that if you do anything, you're going to let someone else know
that you actually have done some action when the user types into you and hits enter. That
means action performed is going to get called for you because now you're going to be
able to generate events to an action listener.
In action performed, we check E dot get source. We can compare against name field
because we have that saved off down here as an instance variable. We'll just write out
hello and then the text associated with name field. Let me increase the text size, here, just
so it's a little bit bigger and we can see what's going on.
We'll do Courier 24. Make it bigger.
So here, once again, Maron, hello, Maron. See? It knows it's getting the event when I hit
enter. Enter, enter, enter. See, that text just stays there. It's another one of those things. It's
only so much fun. Sally, we're scrolling. Not a whole lot of excitement going on here.
This is good for about two minutes.
So we can go ahead and do it this way. Now you can get information from a text box.
Any questions about the text box? Yeah, in the back?
Student: [Inaudible]?
Instructor (Mehran Sahami): Yeah, so basically the way the layout works is every time
you add things, they just get added sequentially from left to right in whatever region
you're adding them to. In this case, the southern region, and the whole set of stuff gets
centered. So if you want to space stuff out, what you actually need to do or add, for
example, more J labels, they might just have more spaces in them. That will create more
spaces between stuff. There's no way I can hit you. I'll just leave it here, and you can pick
it up after class.
So there's one other things that we can do that's kind of funky. We can actually name the
text field. So you might say, but Maron, this whole get source thing, keeping it on the
instance variable, I'm not so keen on that. What I am kind of more keen on is giving
things names so I can just refer to them by their name. That's cool. You can have a name.
So here's that exactly same example, slightly differently. What I'm going to do is I'm
going to add just one more line here. So this is exactly the same code I had before, except
after I create the name field, I say, hey, I'm going to give you an action command, and
your action command is going to be name. So whenever you generate these events, yeah,
I can check to see if the source of that event is you.
Or, if I've given you a name, I can do the same thing I just did with buttons. Down here, I
can get action command. That gives me the string, which is the name of the object that
created this event. I can see if it's equal to name, which is the name that I gave it. So this
just shows you a little back and forth. With the buttons, I kind of show you, with buttons,
you just name them because you always name buttons and you check against names. You
could actually check against the source of the button if you wanted to.
J text fields, it's kind of backwards. J text field, you always, in some sense, have the text
field that you can get with get source, but if you want to refer to it by name, you have to
explicitly give it a name because name doesn't show up as part of it. If we want the label,
we still need to add this separate label name over here. This is just naming the particular
event that comes from that box. That's all it does. Any questions about that?
Student: [Inaudible].
Instructor (Mehran Sahami): That's the maximum amount it shows.
Student: [Inaudible].
Instructor (Mehran Sahami): Yeah, name field is still an I var here. It's really actually
no longer necessary because I don't need to refer to it over here. So I wanted to, I could
just do this. A little cut and paste. Thanks, I vars, thanks for playing. That's real nice of
you. Yeah.
Oh, no, I can't. That's why I had it in here. I still need to refer to it over here to get this
text. To be honest, actually, what I could do is I could just call E get source here and get
its source and then get its text. So I really don't need to, but it's just better stock because it
makes it cleaner that I'm getting the text here. So there is a way around it, but the cleaner
way is to actually do it this way.
Let me get rid of that. So any questions about that J text field?
Student: [Inaudible].
Instructor (Mehran Sahami): Oh, yeah. You can. I'll show you that in about 20
minutes. And three seats away. Before we get there, it's time for something completely
different is to say – it kind of gets to the question in the back of the room. These things
are all sort of showing up centered on the bottom on the screen. Could I actually have
these interactors laid out a different way than this way that they're getting laid out for me.
In fact, you can, and strangely enough, the thing you use to do that is called a layout. So a
layout controls the layout of the particular interactors. It turns out, when you used your
friend, the console program, or your friend the graphics program, what you got was a
layout that was called the border layout. As a matter of fact, you already saw the border
layout. You saw the border layout last time. It looked like this.
You had some center region. You had a north, south, east and west borders, which is why
this thing's called the border layout. What happened with this border layout is that the
center was where all the action takes place. The console program would add a console to
the center automatically. That's just what happens in a console program. And a graphics
program would add a G canvas to the center automatically, which is where you're going
to draw all your stuff.
The other regions are only visible if you add stuff do them. So in the very early days,
when you had a graphics program that was all just graphics, you would say, hey, nothing
showed up in the south region. Yeah, because we didn't put any interactors there. So
these interactor regions only show up if we actually put interactors on them.
We said these are referred to as control bars. So you saw these last time. How do I
consider different kinds of layouts? So there's a couple other layouts to also think about.
There's something called a grid layout. The way a grid layout works is you actually create
and object called the grid layout, and you specify in that grid layout how many rows and
columns are in the grid layout. So we might say two rows and three columns, which
means we're going to have a layout that looks something like this.
It's just a grid with two rows and three columns. I'll show you the code for this in just a
second so we can get into the nitty gritty details. Conceptually, here's what it is. Now,
when I add items, what I do is I say, you know what, I want to set my layout to be this
grid layout. What now happens when I add items is it will add items, the items being the
interactors, one by one, starting at the topmost row and the leftmost square.
Every time I add a new element, it moves over by one until I get to the end of the row,
and then it automatically comes down. It goes sequentially across, row by row. It allows
me to sort of lay things out in a grid if I want to actually be able to do things in a grid. So
let me show you an example of what a grid layout might look like.
So grid layout, here's a simple program that does it. What we do is we start off in our
innate method by saying I want to create a layout. So I want to set the existing layout that
the program is going to use to be a new grid layout that's two, three. Two rows by three
columns.
Now one thing that's interesting about this program, if you look at grid layout example, it
does not extend console program. It does not extend graphics program. These are not its
beautiful house and its beautiful wife and children. What have I done? What I've done is
said I'm just going to extend the program. I don't want you to create a console for me, and
I don't want you to create a G canvas for me.
I want to take up the whole screen with my buttons, baby, so that's what I'm going to do.
I'm going to add six new buttons, and these buttons are just going to get sequentially
added in the order that you saw. Then I'm going to say add my action listeners. I'm not
going to do anything. I'm just going to ignore the buttons.
The reason why I'm doing this is I just want to see some big, fat buttons. Yeah. Look at
that. Six buttons that take up the whole screen. It's a grid. My interactors fill up the grid.
The layout takes up as much space as possible in the screen. More importantly, each of
the interactors that I put into a grid cell takes up as much cells, as much space as possible.
So this button comes along.
Oh, yeah, I got so much space. You're like, why does it do this? This is the most braindamaged
thing ever. I don't need a two inch by three-inch button. The reason why is –
how did you find that so quickly. We won't talk about it right now. Maybe afterwards. It's
like having a sound effects guy.
Check this out as I resize the window. All buttons small and cute, big buttons. That's why
we have layout managers because the layout managers just give conceptual – it says, this
is how your layout's going to be. It says, I'm going to handle all the dynamics of resizing
and all that stuff for you because people resize the window. But I need to know how
things are laid out. If you give me more space than I need, I'm just going to take it up.
Grid layout, not so useful, just something to see. If you see it in the book, you know what
it's talking about. There's another kind of layout which is called a table layout. There's
actually another kind of layout called the flow layout. We're not going to talk about it, but
there's something called a table layout.
A table layout is basically just like a grid layout except for the niceties. So you also give
it a number of rows and columns, except what it says is rather than having each one of
the interactors fill up itself, the maximum possible size, I'm just going to give that
interactor as much space as it needs in that cell and no more.
So what does that mean? That means if I come in here, rather than a grid layout, I say I
want to create a new table layout, and I run this – I need to add more imports. Let me just
grab imports from over here. Come on table layout. Let me just show you the nicer
example of table layout.
Sometimes in life, you just got to get ugly with it. We got ugly with it. Oh, table layout?
There's table layout. Six buttons still. We can still resize the window, but the buttons are
just given as much size as they would actually need. They don't fill up the whole region
that they actually want. So table layout's actually something slightly more useful for us
than grid layout.
This question came up before which was, can I actually link buttons and text fields
together to create something a little bit more funky? In fact, I can do that, and I'm going
to show you that in a context of something a little bit more interesting. It's a program that
allows for conversion in temperature. So this one's actually in the book. I didn't give you
the code because the code is all in the book. So I didn't give it to you on a separate
handout.
Basically, the idea is we write out a label called degrees Fahrenheit, a label called degrees
Celsius, and inside here, we can type in some value. If we click Fahrenheit to Celsius, it
will automatically fill in the Celsius field with the corresponding value. So 32 is zero
Celsius.
The other thing that's kind of funky is I don't necessarily have to click the button. I can
type in, say, some value and hit enter, and that's just like clicking the button. Interesting.
So how do I create this program? Well, if you think about this program, first thing I'm
going to need is these things are not supersized, but they're all laid out in a grid. So I'm
going to need a table layout that has two rows and three columns.
The first element that I have here is just a label. Then I'm going to have a field that's a
text field. As a matter of fact, I'm going to have a specialized kind of text field. There's
two specialized kinds of text fields. Something called an intfield and a double field. They
work just like text fields except you're guaranteed to get an integer value or a double
value from them.
You might ask what happens if someone types in A and wants to convert A to a
temperature? Oh, I clicked the wrong button. I want to convert A to a temperature. It says
enter an integer, and it brings up this pop-up box and gets in their face. Then you say,
sorry, my bad. So it guarantees you get an integer.
Then I'm going to have a button, and somehow, I want to link the button and the text
fields to do the same action. So let me show you the code for that. It's actually a lot
shorter than it looks.
First thing I'm going to do is set the layout to be a table layout. Notice once again here,
I'm extending a program because I don’t want a console or a canvas created for me. I
want to be able to specify the whole layout, so I'm just extending a program. I set the
layout to be a table layout, 2, 3. Again, we're going to go sequentially through all the
elements. So what I want to have in the first element, the first thing I'm going to add to
my layout, I don't specify until I'm down here.
The first thing I'm going to add to my layout is degrees Fahrenheit as a label. Then I'm
going to add some Fahrenheit field. How did I create that Fahrenheit field? I actually
created it up here. What I did, first, was declaring it as an instance variable. So Fahrenheit
field is an intfield, not a J text field, but an intfield, which is just a specialization of a J
text field to just give you that integer.
Other than that, it works just like a text field except here, I just wanted to show you
intfield, so it's an intfield. So I create a new intfield. I specify its initial value, not its
initial size. Its initial value is 32. Then what I say is Fahrenheit field, I'm going to set
your action command so that when you generate actions, the name associated with the
actions that you generate is going to be F dash greater than, which you can just think of
arrow, C.
That's going to be your name. So I set its name, and then I say you're going to generate
action events, so I'm going to add an action listener to you of yourself. Just like you saw
before with the text [inaudible], except now we're dealing with an intfield. We do exactly
that same thing with something called the Celsius field. Celsius field is also declared to
be an intfield.
It starts off with an initial value of zero. We set its action command to be C goes to F as
opposed to F goes to C. So we give it a slightly different name, and we also set it to listen
to action events or to generate action events.
Then we're going to lay out our grid. So first element to the grid is the label, as we talked
about before. Next element to our grid is our little text box that's going to actually have
the numeric value in it. Last element of our grid on the first row of the grid is a button
that’s name is F goes to C. And you look at this, and you say, hey, if I have a button that's
name is F goes to C, and I named this guy F goes to C, aren't I getting back to the
previous point over here of – wasn't this the logical problem where I actually have two
elements that have the same name?
Yeah, I have two elements that have the same name, but I want to do exactly the same
thing in both cases, so it doesn't make a difference. So what I want to do is say if
someone clicks the button, I'm going to do the conversion. So I'm going to have some
code that's going to do the conversion. If someone types something into the text field and
hits enter, I'm going to do the same thing.
So this is something you'd see a lot of times on the web where, for example, if there's a
search engine you use, you can type in the search engine and click search, or you can just
hit enter. How many people actually click the search button? One. How many just hit
enter. Yeah. Isn't it nice that you can just hit enter? Yeah.
That's the same thing we're doing in this program. That's why we went through this extra
rigamarole of setting this action command here because sometimes it's just nice to hit
enter. We do exactly the same thing for degrees Celsius. So we add the label, degrees
Celsius, we add the Celsius field, and then we create a new button whose name is the
same as the action command for the Celsius field. Then we add action listeners.
So that sets up our entire user interface or our entire graphical user interface, or the GUI.
Then when the user clicks on a button, we say, let me get the action command. If the
action command is F goes to C, which means either they typed something into the
Fahrenheit field and hit enter or they clicked the button, then I'll get the value in the
Fahrenheit field because Fahrenheit field is an integer field. It just always gives me back
an integer. And I do a little bit of math. If you don't know the math conversion from
Fahrenheit to Celsius, don’t worry about it. This is just how you convert from Fahrenheit
to Celsius.
You take nine fifths times the Fahrenheit value minus 32, and that gives you the Celsius
value. Now you know. And what I do, more interestingly, is I set the value in the Celsius
field to be whatever value I computed. So someone just typed something into the
Fahrenheit field and hit enter or clicked the F to C button, but what I do to update the
screen is I change whatever value is in the Celsius field.
I do the compliment of that – the mirror image. How many words can you come up with
for the same thing? If someone does C to F, which is I get the value that's in the Celsius
field. I do the math that's necessary to convert from Celsius to Fahrenheit, and I set the
Fahrenheit field. And that's the whole program. Here's my instance variables.
So if I run my little temperature program, I have my label. I have my initial value, and I
have my Fahrenheit to Celsius. If I put in some value here like 100 degrees Fahrenheit is
38 degrees Celsius. 212 degrees Fahrenheit, we'll not touch the mouse, just hit the enter
key. Enter does the same thing as if I click the mouse.
Same thing on this side. I can say 0 Celsius. Yeah, 32. Good times. Now I've created a
whole program with the graphical user interface, and I can resize. It just does – oh, it
always centers for me. Isn't that nice. If I make it too small, well, these things don't get to
small. I can't see the screen.
Any questions about that?
Student: [Inaudible].
Instructor (Mehran Sahami): Oh, can you use the mics, please? I got to keep reminding
everyone to use the microphones.
Student: Can you adjust the width of the grid, each cell within the grid?
Instructor (Mehran Sahami): There are ways with table layout, you can actually give it
what are referred to as hints to actually specify different sizes for things. I just didn't do
that here. It's in the book, if you want to do it, but we're not going to push it that far in
this class. But there are ways that you can.
So one final thing that we want to do, you might say, this is kind of fun, but what I like is
some text and some graphics together, and I want some interactors. So I kind of want it
all. I want text, I want graphics, I want interactors. You think back to the days, you think
Hangman.
Hangman, you had text and you had graphics, but you didn't have interactors. Here you
have interactors, and I showed you and example with interactors and text where you click
the button, and it said Hi and gave your name or whatever.
Now it's time to roll the enchilada and put them all together in our friend, text and
graphics. So what text and graphics is going to do, is we want to think about having some
console in the program and the graphics canvas in the program and interactors in the
program so we can just go to town and do whatever we want to do. How do we make this
happen?
First thing we're going to do, let me write a little bit of text on the board. So text and
graphics. Two great tastes that taste great together. You can decide which one's chocolate
and which one's peanut butter, but it's text and graphics. So it's like Hangman, but with
interactors.
So what we're going to do, is we're going to extend a console program. The reason why
we're going to extend the console program is we still need our friend, the console. That's
where we're going to get the text portion of doing this interaction is from having a
console program. So when we have a console program, what this gives us is the borders
that we've come to know and love.
It gives us the north, south, east and west borders. These are places where we can still
place our interactors. The interesting thing is what's going on in the center region. What I
told you before, the console program fills up the center region with a place where you can
put text, and that's all you can do with it. So what we're going to do is say, console
program, what I want to do is in the center region, I want to give you a different layout
and put stuff in that layout so I can potentially have some text and some graphics.
So what am I going to do? The first thing I'm going to do is I'm going to think about
having some layout. My layout's going to apply to this middle region. The important
thing to keep in mind is the console program, what it used to do, was create a console that
filled up the entire region. Now what I'm going to get is a console as my first element.
This means however I do the layout and whatever I do in it, the very first thing – let's say
I have a grid that has three elements to it in one row. The first element of that will be my
console. That you don't have any control over just because of the way the console
program works.
The first elements of whatever layout you use when you extend the console program and
create a layout for it will always be whatever your text is. You said, you were also going
to tell me about graphics, but if I'm doing this in a console program, how do I get
graphics?
We do the little trick we did in hangman. There was this thing called the G canvas. What
we're going to do is create a G canvas. It importantly, is actually something that we can
add to a layout. So what I can do is say, create my console program. I'm going to create
some layout. Let's say I'm going to have a grid that's – I'm going to create some sort of
layout.
Maybe I'll have a grid layout that's one, three, which would give me this. My first thing is
already taken up by my console. What I'm going to do is create a G canvas and add that
G canvas as my second element. Just to be super cool, to give you something that
normally, you'd have to pay $12.95 for, but I'm going to give it to you for free, we're
going to create another G canvas and add it over here.
So that's G canvas dos. So what we get is console and two different G canvases. Plus, we
can still add interactors all around our screen. At this point, you should be looking at this
in shock, horror and delight and going, okay. Let's all put it together in five minutes
because it's just that easy. So here's how it looks.
Text and graphics. I extend console program. That's where I'm going to get my console.
In my innate, I say set the layout. I want a new grid layout. Remember, grid layout, the
elements expand to take however much space you give them. That's what I want in this
case because what I want to say is I want to have a grid. I want to give the console one
third of the whole grid, and two canvases another third of those grids and grow them to as
large as they can be.
Then what I'm going to do is I'm going to create two canvases. So I need to have some
instance variables to refer to these canvases. I'm going to have two canvases, which are
just – type is G canvas. They're private variables. I will call them the right canvas and the
left canvas. I'm also going to have a text field in this program just for laughs, just because
I can. That's going to be one of my interactors. I want to have interactors, text and
graphics.
What am I going to do? First thing I'm going to do is I'm going say, left canvas, create a
new canvas. Add that canvas, and when I do this add, it's adding it to my layout. I'm
adding a whole canvas. So what does that do? It says, you told me you got a grid layout
here. I've already filled in the first thing with the console because that's what I do. I'm a
console program.
You just told me to add a canvas. Element No. 2 will be the canvas. I do the same thing
again for right canvas. Element No. 3 is now the right canvas. So I have two big canvases
on there as the second and third elements of my grid.
Now I got a console, canvas, canvas. Now I'm going to add some interactors because it's
just that cool. I'm going to create a text field. We'll say new J text field. Text field, I
declare it as a private instance variable. I just showed you that. Maximum size is ten. I
will add a label to it, and the label's just going to be called some text. So the right some
text in the southern region. Then I will add my text field in the southern region.
As of this point, you should come to know and love, you always got to remember to add
your action listener. Very common thing that happens, people create a text field, and
they're typing it and stuff in their program, and nothing's happening. They're tearing their
hair out, and they're wondering why. They just forgot to add the action listener. Know it,
learn it, live it, love it. It's a good time.
Then I'm going to add two buttons, just for good times. So I have my text field. I'm going
to add two more buttons. A button that says draw on the left and a button that says draw
on the right. So let me show you what all these things are going to do before I show you
the rest of the program. So I want to show you text and graphics.
I have my console over here. I have two – you can't see them, but they're side by side.
Two different canvas windows over here. Here's some text. I can type in hi. You typed hi.
Wow. It's that exciting. Draw left, in my left canvas. I'm just drawing rectangles. I'll show
you how I do that in just a second. Draw right. Drawing in my right canvas.
How did I make that happen? Let me show you the rest of the program. I've set
everything up. Console, two canvases, text field and two buttons at the bottom. Here's
where all the action's going on. When action performed is called, that means someone's
interacting with one of the interactors.
There's nothing else I can do in the program except interacting with one of the
interactors. First I check for the text field. If the interaction with the text field – so if the
source of the interaction was the text field, I write out, you type in the text field. This will
go into the console because anytime you do a printlin, the text always goes into the
console. So it just shows up in the console. Not a whole lot of excitement going on there.
Alternatively, if the thing they did was not to type into the text field, they clicked one of
the buttons. I could've either done all with get source or all with get action command. I'm
using both just to show you that you can mix and match if you want. So I say, what was
the command? Get action command. If it was draw left, then what I'm going to do is I'm
going to create a new filled rectangle. Let me show you.
Create new filled rectangle. It's very simple. It just creates a rectangle that's 50 by 20, and
yes, they should've been constants, but I didn't make them constant so I wouldn't have to
scroll down and show you the constants. I set it to be filled, and I return the rectangles.
All it does is create a filled rectangle and say, here you go.
All I do is I take that filled rectangle, and I add it to my left canvas. So because it's not a
graphics program, I can't just say add with the rectangle and add it. If I want to add the
rectangle somewhere, I need to specify which canvas I'm adding it to. I'm adding it to the
left canvas. So I say, left canvas, add to yourself this rectangle. Where are you going to
add it? At X location 20 and at Y location left Y.
Left Y starts out with the value ten, and every time I add something, I space down my Y.
So I'm just making Y go down by some spacer amount, which is 30. So all it's doing is
drawing a rectangle and essentially moving down. So I'll draw my next rectangle below
it, moving down to draw the next rectangle below it.
I do exactly the same thing for the right hand side, except after I create the filled
rectangle, I have a separate right Y, which keeps track of how low I've gotten on that
side, in terms of the Y coordinate. I add to the right canvas. That's the only difference.
So when I run this program, some text. Again, if I type in great, great. If I typed in great
and hit enter, it generates the event, which does this printlin on the screen. It generates
this event over here, this action performed. The source was text field, and I write out the
text on the screen.
If I click on one of the buttons, draw left, it draws the filled rectangle, and it's
incremented the Y on the left hand side. So the next time I click draw left, it draws it
lower and lower and lower. Draw right does the same thing.
Notice that the X location for both this canvas and this canvas, when I add the rectangles,
are both at 20. The reason why it shows up two different places in the screen is because
there are two different canvases, and there's kind of an invisible border here. So you can
create text, graphics and interactors all together and just go to town.
Any questions? All right. I will see you on Wednesday.
[End of Audio]
Duration: 50 minutes

Search This Blog