This week we explain how and why we wrote an applet that we introduced two weeks ago. If you've just found us, you should check out last week's article to get a handle on what we've been talking about. An In-Depth Look at the Workings of an Applet
We've talked about how we organize our applet into three classes; this time we're going to talk about the specific details of how it works--so sit back, relax, and prepare to take in some technical jargon.
First let's pick apart the applet class. There are three principal parts to it, all of which are based in the
init()method, which runs as soon as the applet loads with your Web page. The first consists of things we've spent a lot of time talking about, such as instructions for creating the (simple) interface. However, before we start talking about that, we'd like to call your attention to the very first two lines:
String ourhost = getDocumentBase().getHost(); String ourfile = getDocumentBase().getFile();If you recall when we started talking about networking, these two commands store the host and filename that identify the Web page it loaded from into two strings:
ourhostandourfile. Notice how we do it: It looks like we're calling methods on a method, namely,getDocumentBase(). Strictly speaking, that's not quite true;getDocumentBase()returns aURLobject, andgetHost()andgetFile()are two methods that we're invoking on that URL object. (Yes, we can do that.)This is beneficial because we've decided that we don't want a URL--we just want to know the name of the computer and the file. We could just use the URL, but that's getting ahead of ourselves.
With that detail out of the way, and the information safely tucked into our strings, we assemble our interface, or at least the top half--the static half.
// Then we set up the layout for our interface objects: GridBagLayout layout = new GridBagLayout(); GridBagConstraints constraints = new GridBagConstraints(); setLayout(layout);Just as we discussed a few months ago when we were detailing how one develops an interface layout in Java, we create our layout manager and "activate" it. Because it's a
GridBagLayout, we also set up its constraints--telling it how we want our layout to behave:
// Objects should fill the space available: constraints.fill = GridBagConstraints.BOTH; constraints.weightx = .5; constraints.weighty = .5; // But leave a little room between each other: constraints.insets = new Insets(3,3,3,3); // And in the first row, there will only be one thing: constraints.gridwidth = GridBagConstraints.REMAINDER;We now add our components, of which there are three parts. The first isn't really necessary, but hopefully it makes the whole project a little less ugly and confusing: It's the title that you see across the top of the applet.
// ...a title, in the form of a label: Label title = new Label("HTML Tag Information:",Label.LEFT); title.setFont(new Font("Courier New",Font.ITALIC,14)); layout.setConstraints(title,constraints); add(title);Notice that we can control the size and font of the label by creating a "
new Font" and calling the label'ssetFontmethod with it.To top it off, we add the two text boxes that we'll be using later.
// ...a single text field to display highlighted information. highlightbox = new TextField(40); highlightbox.setEditable(false); layout.setConstraints(highlightbox,constraints); add(highlightbox); // Then we create the text box to display the page itself: displaybox = new TextArea(6,40); displaybox.setEditable(false); layout.setConstraints(displaybox,constraints); add(displaybox); // Now prepare for the rows of things that're going to come next: constraints.gridwidth = 1;We've left our constraints set a certain way, which is important when we add the buttons, but we'll get to that in a minute.
A very few issues ago we talked about the various ways a Java applet could access the network. We picked a method rather arbitrarily. This time we elected to take some code from an example we gave earlier, which uses a
socketto connect the iWORLD Web server and to download an HTML document. In this case, as then, the document we load is the one that carries the applet. We could have used a simplerURLConnectionto do this transfer, but we chose not to. Feel free to skip back to check out the code and see exactly how this is done.The last distinct part of the init() process is the key to what (little) this applet does, and (technically) it consists of just a few lines.
// Now, we process what we've read into HTML tags: // We copy the contents of our display into a string: String webpage = displaybox.getText(); // And we make a Vector: // (A vector is like an array that grows automatically if we need // more space. Very handy...) Vector tags = new Vector(50); // We have a method that makes entries in the vector based on HTML // tags in a string: readtags(webpage,tags); // And we have another method that makes a special kind of button // for each tag in our vector of tag information. addbuttons(tags,layout,constraints);
Vectorsare handy, and you should remember them. In case not enough people have been getting the word out, the days when programmers are forced to grab all the memory space they think they might need in advance are over. TheVectorclass, and the other tools that are available like it, take care of the mundane aspects of allocating more memory as you need it, and usually quite adequately as well. Those of you who are regular programmers (whose intelligence we haven't insulted yet) are probably familiar with having to guess in advance how much space will be needed for something (e.g., "How many elements should this array hold?"). In this case, we've just told our Vector to start out with space for 50 objects.Now the catch:
readtagsandaddbuttonsare definitely not built-in methods. (In case you hadn't guessed.)
private void readtags(String input,Vector output) { // We created a simple Tag object to keep all the relevent information // about a tag. Tag current; int counter = 0;We'll get to the Tag class we created in a minute. First, our method's about to loop through the string we stored the Web page in, looking for HTML tags.
// We look through the entire string doing this: while (counter >= 0) { // First we find the beginning of a tag. if ((counter = input.indexOf('<',counter)) >= 0) { // Then we Record where it begins. current = new Tag(); current.startindex = counter; // Then we find the ending of the FIRST WORD in the tag. while ((input.charAt(counter) != ' ') && // It's either a space or a '>' (input.charAt(counter) != '>')) counter++; // Now we know where the first word ends... we use that information // to copy out the tag's "name"... the first word in the <>. current.tagname = input.substring(current.startindex + 1,counter); // Then we look for the end of the tag: if (input.charAt(counter) == '>') // (if we haven't already found it) current.endindex = counter; else counter = current.endindex = input.indexOf('>',counter); // And now that we know where the tag starts, ends, and what it's // name is, and all of those things have been placed in a Tag object, // we add that to the vector. output.addElement(current); } } }Hopefully the comments have made it at least somewhat understandable--we're trying to find every HTML tag in the string we're given. Remember three things about it: namely, where the tag starts, where it ends, and what its "name" is. We've decided to name tags by whatever the first word in the tag happens to be. For each tag, we create a Tag object, stored temporarily in
current, and add it to the Vector when we're done.Our methods are nothing new but may look a little confusing. Our advice is to first take a look at the
Stringclass. We use some tricks and tools that the Java designers threw in. You can see that we used a loop--one that runs as long ascounteris zero or greater. Thecountervariable just keeps track of where we are in the string, so you may be wondering: Why would the loop ever stop? The answer lies in one of the String shortcuts we use:indexOf().
indexOf()actually returns the numbered position in the string of the next occurrence of the character (or characters) you specify. In the event that it can't find what you're looking for, it returns a negative number (-1, to be exact), and that's the event, coincidentally, in which we want to stop the loop. Although it may not be the easiest thing to read and understand, it's there to make a point: It's by noticing and writing with these coincidences that programs are made to be efficient.Once the routine in the loop finds the beginning of a tag, it finds the end of its name and the end of the whole thing. Then it copies the name (using the
substringmethod of the string) and the indexes into the current Tag object--and so on, until we're done.The latter method is the easier to understand, for the most part:
private void addbuttons(Vector tags,GridBagLayout layout,GridBagConstraints constraints) { // This is the special kind of button we created... TagButton current; int i;Of course, this method gets the
Vectorcontaining our Tags. We also have to pass off our layout and its constraints to this method because it uses them to add things to the applet. Not to lead you astray, it actually shouldn't be done this way, but we've done it so we can make a show of correcting it later. Notice that our loop here is designed to stop not only when we run out of tags, but also if we exceed a certain amount of them (MAX_BUTTONS). That's set near the top of the applet class.
// We know we have a finite amount of space on the screen, so we're only // interested in a certain fixed number of buttons - MAX_BUTTONS. for (i = 0;(i < MAX_BUTTONS) && (i < tags.size());i++) { // We create a new button: current = new TagButton((Tag) tags.elementAt(i),displaybox,highlightbox); // Every 8 buttons or so, we want to add an extra line, so we do this // fancy math (checking the remainder of a division) to see if we want to // end the current "row" in the layout. if ((i != 0) && (i % 8) == 0) // If we do, we set this in the layout constraints. constraints.gridwidth = GridBagConstraints.REMAINDER; else // If not, we set this: constraints.gridwidth = 1; // Then we add the new button: layout.setConstraints(current,constraints); add(current); } } }This should be fairly self-explanatory. If you've been waiting for some more of that jargon we promised you, the "%" sign we use in that if statement is (in Java as well as in a few other popular programming languages) used to invoke modulo division--the division that leaves the remainder that we're interested in. This is the trick we use to fit (usually) eight buttons in a row. If we divide the number of buttons we've actually laid out by eight, and the remainder is zero, then we know we've filled up a row. In other words, we've laid out 8, or 16, or 24 buttons. This sort of thing may actually qualify as an official "Old programmer's trick."® It's not done perfectly here, but we'll get to that shortly.
Our parting shot in this applet is to leave an instructional message in the top text box as follows:
// And then we put something instructive in the top box: highlightbox.setText("Press one of the buttons.");The applet class itself is finished. It's collected some information and spooled out some other objects--they happen to be buttons--and now the user can interact with them.
This may be a lot to take in if you're still a novice programmer; as always, questions are welcome. Next week, we're going to look in detail at our ever-mysterious second class, and start thinking about how we can actually improve this applet. See you then.