Here I sit, once again, in front of the computer. I spoke with my father today about computers, and why he does not understand them: no breadth of experience. Without applying the computer to many different problems, one cannot abstract between them and get a feel for what is the same (the computer) and what is different (the application). It is expecting too much from a user to abstract so much from so little.

This is a deep insight with wide application. "Repetition makes for recognition" has been misused. Repetition after changing certain parameters can help you understand a system.

This can be applied to understanding any system, such as a physical or a game system. Set up a process, and run through the process with different initial conditions to get a feel for what is the same between invocations.

Consider the creation of a computer program. I submit that the understanding of computer programming is proportional to the number of programs you write.

But what kinds of programs? What should they do? What interface should they use? These decisions can best be made by a programming teacher, who understands which goals are approachable for a student at a given level. However, with some extra discipline, a student can tackle any small application (in other words, an office suite or autocad might be too much). The method she uses is a combination of divide and conquer, comparison, and finally recombination.

Dividing an application is perhaps the hardest thing for the beginner, simply because it isn't clear what the best spots are. Picking the wrong delineations can be disastrous. A teacher is helpful to stop a path before too much time is wasted. There is a good argument that the student learns a lot from waste, initially, and gets a feel for which are dead-ends.

Comparison is the critical act of comparing what you want with what you've got. This is where you start off with something simple, and cyclically modify it until it is what you want.

Finally, each simple part is placed into a whole and the system can be tested. This process is perhaps the most important of all in terms of learning the software process.

Application programming with Java Swing

The first thing is to gather up some simple applications that you want to emulate, and then do them in order. The Windows Accessories offers a good starting point.

Notepad
Wordpad
Calculator
Paint
Hyperterminal
(Media)
CD Player
Sound Recorder
System volume control
Windows Media Player
(Games)
Minesweeper
Solitaire
Freecell
Pinball
(utils)
Char map
system information
file explorer
(net)
ftp
telnet
ping
web client
...

Some of these programs are much more complex than others. Some have interaction with hardware (Hyperterminal, system info) that is tough to do with Java. Some hide complex algorithms that might be hard to guess (minesweeper mine layout). In these cases we can use our imaginations to get a comparable utility, such as reporting on Java information with System info.

As you begin, the first thing that you will notice is that Swing doesn't look like windows. It sort-of behaves the same way (supports the same UI idioms, such as menus and buttons) but there is something eerie and a little disconcerting about it if you are a Windows person. (Those of us with cross-platform experience may be slightly less affected.)

Luckily, this aspect of the program is stored in a single place, and referred to as the "look and feel" of Java Swing, and it can be changed. It is a Java platform setting that can be set at runtime or at invocation time. It is perhaps simpler to set it at invocation time.

Let's start with Notepad. The first thing to do is to really take a look at it, and define it. We can look at its appearance first, and then the behavior. It has an icon in the title bar and a title text that has the file name (untitled if the file is unsaved) a dash and then a program identifier. Next is the menu bar, and then the remainder of the window is a text editing region with an (optional) scroll bar along the right. You can note colors and even pixel widths.

For behavior, you can start with program invocation. Notepad is started in Windows 2000 with Start|Programs|Accessories|Notepad which is a link to %SystemRoot%\system32\notepad.exe. Also note that this file has an icon associated with it, which is the same as the one in the title bar. There may even be some behavior to note, such as start-up time (hint: the Java version will be slower).

Another logical place to start is with program installation. All of the programs above are installed with Windows. Essentially the user needs a setup.exe. Note that Java's requirements are more stringent than notepad's. In particular the user needs a JRE. This implies that a full-featured installer would not require a JRE, which means that it cannot be written in Java itself. There are several non-Java installer options: scripting (shell, Javascript, WSH, Ruby, Tk/TCL, etc), another (platform specific) compilable language (C++, VB, etc).

At this point you might be wondering how Sun can call Java "write once run anywhere". Personally, I think its a good question! Installation and invocation are two extremely important parts of an applications life, and yet in both cases we need platform (Windows) specific code. Webstart doesn't really address this problem fully, to my knowledge. Install Anywhere might; I haven't tried it. I think Sun would do well to distribute a simple Installer app with the JDK!

We will ignore the installation issue, for now. If you really want, you can use a script, possibly even Ant if you are willing to assume a JRE is present.

We will not ignore invocation. We will handle only the Windows case, however. You will note that Java programs can be started in two ways:
1)java -jar <jarfilename> <appargs>
2)java -cp <jarfilename> <mainclassname> <appargs>
(assumes java on the path)
The only added burden with #2 is having to know the main class name. In both cases, the absolute filename of the jar file must be known. In other words, from our perspective the invocation method is unimportant.

Without writing a trivial native Windows executable (as JEdit does) we have 2 options:
1) create a shortcut direct to the jar file
2) create a shortcut to a script

While #1 avoids the script file, #2 allows for invocation from the command line (and #1 doesn't) and also allows file associations. Note that one should not rely on #2 to pass initial args to the app, as a savvy user could execute the jar separately. there are some relatively subtle ui issues with the script approach WRT file associations (icons).

Needless to say, there is only one drop in replacement method: a small executable. The next best is the script with shortcut, and the final, simplest is a direct shortcut. (From what I've seen most people just provide a script, without even a shortcut.) (If we didn't have the icon requirement we could get away with just the executable jar).

We will choose the script, shortcut, and non-executable jar invocation. We will also look into installation and invocation tools for Java that can give us a windows executable.

What will this project look like? I anticipate about 1 hour at a time, writing source code, testing, and modifying. There will also be reading the javadocs, other sources for ideas and information (finding the hidden gems in Swing). Automated testing will be difficult, although we will keep our eyes out for uses of the AWT.Robot. It is assumed to be a lone wolf project, so CVS is unnecessary. I am not sure how valuable tracking progress will be, so RCS or other source tracking may or may not be valuable to you.

The mechanics of the process. I will use Netbeans as my editor and debugger. I will use jikes for the compiler. For this simple project, the source and class files can reside in the same directory. Invocation during development can be handled by NB. Deployment will happen last with either command line jar or NB jar. Testing will be done largely manually. Ant would be overkill here. Testing of platform specific invocation can go last. I may use a the jEdit beautifier.

Be wary of complication/optimization/elegance. This is not an elegance project. This is an attempt to duplicate another program. Elegance can come later. Go with your first instinct! This does NOT mean that you should ignore standard idioms and conventions!

========
JNotepad

First things first. Get a JFrame and show it. What is the behavior? What is the behavior compared to Notepad? Does notepad remember its size and position between invocations (yes)? Where does a JFrame popup by default and how big is it? How do you control this, and the icon, the title? How does its appearance differ from Notepad? Fonts, colors, geometry..

JFrame is a complex object. It is 5 layers deep in the inheritance hierarchy. It has about 25 methods and 100 more from parent classes. It is an overwhelming object to start with. But get used to it. Swing is like this.

How can we deal with being overwhelmed? We could diligently read through all of the Javadocs, even all of the source for JFrame and its ancestors. But that is like trying to learn French by reading a French dictionary! Maybe there are a few geniuses that could manage, but I couldn't and I would wager that you can't either.

We could try the long view approach, and take a gander at the javax.swing package as a whole. There are 20 some interfaces and about 40 classes. Still quite a lot! (We note that there are 14 sub packages of javax.swing and try not to despair.)

We can look at the classes and see if we can tell what they do by their names: action button constants editor model map factory layout group pane renderer manager filter icon verifier keystroke lookandfeel

The J stuff: applet button checkbox component dialog chooser label list menu pane field table toggle tree view port window

At first glance, the J stuff looks more friendly - pretty concrete, except for maybe view port. Most of the other stuff is really weird and abstract sounding. constants, icon, keystroke, and look-and-feel seem ok (editor might *sound* friendly, but trust me, it isn't what you think!).

A quick look at the other J stuff (of which JFrame is one) shows that all of them are about 3 or 4 levels deep in the hierarchy, sub classing at least java.awt.Component, and java.awt.Container. (JFrame is the deepest, sub classing Window and Frame too). Interestingly, the freaky weird stuff is generally much shallower, and so simpler. What irony!

Ack! We don't want to learn AWT (which is a collection of another 12 packages), we want to learn Swing, what is this all about? Do we have to learn AWT to learn Swing?

It really isn't possible for a newbie to answer that question, so I'll give you the answer: you do have to learn some of it. In particular, the event model is used in Swing, which is why you will see "import java.awt.event.*" a lot in Swing apps. AWT layouts are also commonly used, so you will see import java.awt.*. Fundamentally this has to do with Swing maintaining compatibility with AWT and using its event scheduler. Swing also leverages a lot of AWT.

Another heartening tip I can give you is that most methods you use will be on the Swing class itself, not an AWT super class. There are exceptions unfortunately. This is hard to verify with Javadoc, as it doesn't show which methods have been overridden. JFC in a Nutshell by Flanagan, O'Reilly, does a good job here. (It is also ironic that our first class, JFrame, breaks this rule the most, using lots of stuff from its awt.Frame parent).

A note on using Javadoc: it is weak compared to Flanagan's JFC in a nutshell, at least in terms of skimming a package or class. He collects the information in a more compact way and groups methods in a better way, as well as correlating the BeanInfo Further, he lists not only the hierarchy, but what interfaces each class implements. This allows you to determine the complete list of implemented interfaces for a single class without a lot of searching. JFrame implements 3 interfaces directly, and 7 from its ancestors!! Javadoc is better for understanding the semantics of the method, Nutshell better for overall code structure.

Have I made the point that Swing is complex? Basically, it is impossible to learn Swing without more resources than Sun gives you out of the box. So what resources do you need? Examples are good because you can get a feel for what is used where and usage frequency. A high level overview of the architecture is good, as a tool to deal with high complexity.

http://java.sun.com/products/jfc/tsc/articles/index.html

There are some books, too:
Core JAVA 2 VII-Advanced Features from Sun Microsystems Press. ISBN is 0-13-081934-4
"Definitive Guide to Swing for Java 2" from John Zukowski
Java Swing from O'Reilly
Geary's book, Graphic Java 2 : Mastering the JFC Volume 2 - Swing
http://www.javaranch.com/bunkhouse/bunkhouseSwing.jsp (reviews)

Some of this info might be gleaned from the tutorial at Sun's site.
http://java.sun.com/docs/books/tutorial/
http://java.sun.com/docs/books/tutorial/uiswing/index.html

Lastly, there is always the community!
javaranch, usenet, jug

OK, so it turned out that this wasn't the best way to learn Swing. Or rather, there is some more work to do before we can continue.

There are 2 paths to go down with these resources: emulate some examples and modify them, or understand Swing and start from scratch. I am of the opinion that one should emulate examples first. Then understand the architecture. I think many people agree with me.

The JRE comes with some demos, one of which is an attempt at a Notepad clone. It functions something like Notepad, but looks nothing like it. The icon is different, the menu is thicker and uses a different font. There is a border around the whole thing. The text font is different. There is a toolbar. The sliders look different (bumps). The menus have icons. Many menu commands are different and/or missing.

Functionally there are lots of differences. JNotepad has a debug menu, but Notepad has a format and help menu, and the edit menu provides for search and replace. JNotepad has no word-wrap feature. Its size and shape do not persist between invocations, nor does it remember the last directory. THe program does not ask you if you want to save changes.

This certainly seems within our grasp. The demo is a single source file (not including a debuging support class) about 600 lines long. It uses some interesting idioms and features of Swing, some of which we will rip out. Some we may keep, such as the use of Actions.

We can start our examination with invocation. interestingly, the notepad class is not public, yet defines a static main. Is this a feature of executable jars? Anyway, here is a good example of some useful JFrame methods. setTitle, setBackground, getContentPane, addWindowListener, pack, setSize, show. Of these, getContentPane and pack seem to be the least understandable. Not too bad.

Nestled in there, almost unnoticed, is frame.getContentPane().add("Center", new Notepad());. This is where things happen. This is one of those common invocation idioms that would be good to learn: script a JFrame in a main method, adding the parent class as a component. It is simple and avoids the pitfalls of some other "tricky" idioms, like the ones that subclass JFrame.

Lets browse through the Notepad class. What do we look for? Imports are good to know. Lots of them! Data members, how many methods and their names. Later, their signatures. Then thread the needle, starting with invocation. (look before you leap!)

Notepad extends JPanel, so it would be good to know that class well. Something that programmers in general seem to ignore is that subclassing is a big responsibility! In many ways it can break encapsulation, and so requires a more complete understanding of the ancestor classes and their implementation compared to just writing client code.

Next, we see some resource bundle code. Interesting. We'll look at that later. Seems like a good place to add our persistence.

Next, we come to the constructor. The original author Timothy Prizing was nice enough to provide us with some clues as to how to change the L&F. Something to do with "UI Manager". Interesting class, maybe we'll look at it later. It is certainly one of those "abstract sounding ones, though!

(A small aside about reading someone else's code. It fundamentally requires a very strong knowledge of Java to read code. The reason is that you must be able to understand someone else's intentions through their idioms. There are tools to help with mechanical problems relating to code conventions (Jedit beautifier comes to mind). However there are no tools that can help with bad names. Regardless, there is sometimes important information in the formatting of the source, so it behooves you to at least skim it before reformatting. You may be able to change names, but this is invasive and risky. A refactoring tool like IDEA may come in handy here. Syntax highlighting is a must for making the process faster and more bearable. While you read, you may want to keep some notes, and somehow associate these notes with the source, either in a project specific folder with a standard naming convention, or with the source file.)

We skim the rest of the class. Much of it is concerned with creating actions and menu items. There is also a bunch of stuff concerned with toolbars, the undo function, a file loader and the status bar. Unfortunately, the data members are spread around in a weird way (they seem to follow the code block that uses them.) The editor itself appears to be a JTextArea.

So perhaps this source file is not as simple as we thought. It has several nested classes. It has a ton of imports. But still, it IS only 600 lines long, including comments, so we should be able to handle it! Besides, we will actually be removing the toolbar code to get it even slimmer. We may also be able to remove the parameterized menu building. This depends.

Anyway, moving back to the constructor, we find the editor being instanced and adjusted, including adding an undo listener to the underlying document. We see a command hash map created, mapping a string name to an Action object. We see some scroll-support code. We see menu creation. We see the high level layout code.

The interesting methods are createEditor, getActions, createToolbar, createStatusBar. The interesting fields are undoHandler, commands, editor, menuitems, menubar. After examining these fields and methods, you can determine that the interesting classes are hashtable, jpanel, borderlayout, action, jmenubar, jmenuitem. There are other classes, and some are more interesting than others, I think. For example, Action is the most interesting to me. Also the interaction between the undohandler and the editor via getDocument is interesting.

(How do I decide what is interesting? That's a good question. What interests you will change in time. Often I find I can ignore most statements as being glue or data conversion, or loop details. Unusual method calls are always interesting: but this requires you know the usual ones! Assignments to fields are important.

We could stop here and skim the javadocs for the classes. Not a bad thing to do, really. We could also continue to trace the interesting methods.

Another thing to notice is what we aren't seeing. Except for the status bar, I don't see any low-level painting code. I don't see anything that looks like keystroke handling code. But we KNOW its there, so that means its being hidden from us, abstracted away. This can be a good thing - luckily the only requirement that might need low level manipulation would be word wrapping. Most of the editor's low level behavior seems fine: it provides a blinking caret, black on white text, etc. It responds to arrow keys and even cut and copy keystrokes as you would expect.

Lets do that overview again with Netbeans help. There are 11 nested classes (6 of them actions). There are 22 methods, mostly protected. There are 24 fields.

Most of the methods are used to partition the construction of the GUI in pieces, and are called only once in the program's lifetime. There is one helper method "tokenize" and another "resetUndoManager".

There are 6 action classes, 2 undo related classes, one custom component class (status bar), one helper class (file loader), and 2 other classes (appcloser, action changed listener).

Much of the method code consists of constructing UI elements from a resource file, and connecting these resources to an action class. Many of the fields are involved in this process, as well. The action classes are very simple, essentially wrapping a no-arg method. The methods themselves contain a large amount of application code (as might be expected).

we are not really refactoring this code, but we have to wonder how to make it simpler. All of the menu construction is pretty bad. Also, later changes to Swing have made a lot of this code redundant, as menus and toolbars have been altered to do many of these things automatically when an Action is added to them. A GUI builder might have stuck all of the setup code into a single method, relying on design time UI to make it manageable.