As you learn Swing, you might start with spike solutionsbits of code that demonstrate how Swing should work. Once you get these spikes working, you will go back and figure out how to test the Swing code. This chapter sometimes presents its material in this fashion: I will demonstrate how to code something in Swing, then supply code that shows how to test it. Most applications, whether they use Swing or not, initiate with a frame. A frame is a top-level window with a title bar and border by default. The frame is largely drawn by and under the control of your operating system. Within Java, the Swing frame class is javax.swing.JFrame. Building an initial application in Java is as simple as constructing a JFrame, setting its size, and making it visible. Create the class Sis (short for Student Information System). package sis.ui; import javax.swing.*; public class Sis { static final int WIDTH = 350; static final int HEIGHT = 500; public static void main(String[] args) { new Sis().show(); } public void show() { JFrame frame = new JFrame(); frame.setSize(WIDTH, HEIGHT); frame.setVisible(true); } } The definition for Sis includes a main method to allow you to execute the application from the command line. About the only things you ever want to do in a main method are to construct a new instance and call a single method on it. You may first need to call a method to parse the command-line arguments. If your main method is more involved, you need to refactor. Resist adding any real logic to mainmain is usually not comprehensively tested. Compile and execute Sis. You should see a simple frame window (see Figure 1). Experiment with this window and note that you can do things such as size it, minimize it, or close it like any other windowed application. You may also want to experiment with the setSize and setVisible messages to see how they impact the frame. Try omitting either or both message sends. Figure 1. A Frame WindowThe only problem is that when you close this window, the Java process does not terminate. Behind the scenes, Swing creates user threads. Exiting the main method does not result in the termination of these user threads. See the section Shutting Down in Lesson 13 for a discussion of user threads and daemon threads. You can tell the JFrame to terminate the Java process by telling it to exit on close: package sis.ui; import javax.swing.*; public class Sis { static final int WIDTH = 300; static final int HEIGHT = 200; public static void main(String[] args) { new Sis().show(); } void show() { JFrame frame = new JFrame(); frame.setSize(WIDTH, HEIGHT); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } Now that you understand what it takes to build a frame, you can toss this code away and write a couple of tests. You will want to refer to the Java API documentation to see what kinds of queries you can send to a JFrame object. The tests show that you can inspect each piece of information you use to initialize the frame. You can also query whether or not the frame is visible. package sis.ui; import junit.framework.*; import javax.swing.*; public class SisTest extends TestCase { private Sis sis; private JFrame frame; protected void setUp() { sis = new Sis(); frame = sis.getFrame(); } public void testCreate() { final double tolerance = 0.05; assertEquals(Sis.HEIGHT, frame.getSize().getHeight(), tolerance); assertEquals(Sis.WIDTH, frame.getSize().getWidth(), tolerance); assertEquals(JFrame.EXIT_ON_CLOSE, frame.getDefaultCloseOperation()); } public void testShow() { sis.show(); assertTrue(frame.isVisible()); } } The code that meets this test ends up slightly different than the spike code: package sis.ui; import javax.swing.*; public class Sis { static final int WIDTH = 300; static final int HEIGHT = 200; private JFrame frame = new JFrame(); public static void main(String[] args) { new Sis().show(); } Sis() { frame.setSize(WIDTH, HEIGHT); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } void show() { frame.setVisible(true); } JFrame getFrame() { return frame; } } When you run the test, you will see the frame window display on screen, because the test instantiates Sis. Resist embedding such tests that pop up windows. It is very distracting and will slow down your tests considerably. You will learn techniques later that eliminate the need to render the user interface while running tests. For now, a test or two that pops up windows might be considered acceptable. The frame window does not disappear even after the test completes. This is a bigger distraction that you can fix. In your test's tearDown method, tell the application to close: public class SisTest extends TestCase { ... protected void tearDown() { sis.close(); } ... } Close the application by having it dispose of the frame window: package sis.ui; import javax.swing.*; public class Sis { ... private JFrame frame = new JFrame(); ... void close() { frame.dispose(); } }
|