CS2 Advanced Programming in Java note 8

29 downloads 182 Views 94KB Size Report
CS2 Advanced Programming in Java note 8. Swing. GUI building in Java. This note gives a short presentation of Java support for graphical user interfaces,.
CS2 Advanced Programming in Java note 8

CS2Bh 24.4.2002

CS2 Advanced Programming in Java note 8 Swing GUI building in Java This note gives a short presentation of Java support for graphical user interfaces, in particular the Swing libraries. Once you have followed it, you will be able to name some typical interface components, give an outline of the Swing event model, and build a very small graphical application. To supplement this note, you need to read your course textbook: TIJ §13; UJ §13; or work through Sun’s online quick-start guide. http://java.sun.com/docs/ books/tutorial/uiswing/mini/index.html Two Books Walrath and Campione, The JFC Swing Tutorial: A Guide to Constructing GUIs. Addison Wesley, 1999. Detailed and readable. Available online from Sun as a trail on the Java Tutorial. http://java.sun.com/docs/books/tutorial/uiswing/ Niemeyer and Knudsen, Learning Java. O’Reilly, 2000. A decent teach-yourself Java text, with particular emphasis on the standard libraries. Swing fills Chapters 13–16. 8.1

Something old, something new

Since its inception, Java has provided facilities for writing programs with a graphical user interface (GUI). This is good. What it hasn’t provided is stability: in a fairly short time the relevant libraries have already undergone considerable transformation. The original scheme was known as the Abstract Windowing Toolkit, or AWT, in java.awt and its subpackages. The current favoured approach uses the Java Foundation Classes1 , whose user interface part is known as Swing, in javax.swing and subpackages. These do different things, and the new libraries depend on the old ones; so you will need some idea of how they fit together. Both AWT and Swing give a standard set of graphical components like windows, buttons, text fields and so on: AWT has Button and TextField, Swing has JButton and JTextField. AWT components are implemented using the local windowing tools — a Java application running under Windows will use buttons that 1

or JFC, naturally

1

CS2 Advanced Programming in Java note 8

CS2Bh 24.4.2002

look familiar to Windows users, and on a Macintosh it will use Mac buttons. This is done with peers: every Java Button is associated with some button object (its peer) from the host window system. The advantages of this are that AWT components only contain wrapper code, the local operating system does all the drawing, and applications naturally adopt the visual style of their hosts. Unfortunately, the wrapper code turns out to be rather substantial, and this approach also means that the AWT can only be a lowest common denominator: to include a feature, it must have native support on every platform. Swing instead uses a peerless model, also termed “lightweight”, where components are implemented wholly in Java. This is faster to execute, and means that Java applications look the same on every platform. There are also lots of handy things rolled in with Swing to make it slick. Features like tooltips and tree viewers; accessibility (how do you use a GUI if you are blind?); and “pluggable look-and-feel”, so that Java programs can still look like Windows ones, if that’s what you want. Underneath all this, the AWT still provides basic drawing commands, with management of fonts, colour and rendering (the "2D API").

8.2

Components and containers

Under Swing, a GUI typically takes the form of a window containing several components, some nested within others: say, a list inside a scrolling box beside some buttons within a panel. The base class for all of these is JComponent, with general methods like getSize() and setToolTipText(String). Subclassing this are around forty different kinds of component, from radio buttons to toolbars: the Swing tutorial provides an online “visual index”. There is a demonstration program, distributed with the Java libraries, that shows off most of these. On the local Linux machines it is available as follows: try it out yourself. $ cd /usr/share/jdk1.3/demo/jfc/SwingSet2/ $ java −jar SwingSet2.jar & The old AWT distinguished between a Component and Container. However, the natural nesting of components means that under Swing almost all of them can act as containers for further components, and indeed JComponent is actually subclass of Container. Even so, some things are specifically designated as top-level containers: in particular JFrame for standard application windows and JApplet for applets in web pages. Most applications construct their GUI by stitching together components within some top-level container. Figure 8.1 shows this in a tiny Java application: two buttons and a text field, all sitting in a panel within a main window (the JFrame). Once these are all assembled a call to pack() works out the right size for everything, and show() puts it on the screen. This can get quite lengthy, and for some common situations Swing provides ready-made solutions: thus JOptionPane will put up basic dialog boxes for error 2

CS2 Advanced Programming in Java note 8

CS2Bh 24.4.2002

messages and yes/no questions; while JFileChooser and JColorChooser present standard interfaces for selecting files and colours respectively. 8.3

Events and listeners

The counter in Figure 8.1 looks pretty, but clicking on the buttons doesn’t do anything. The event model of a GUI library describes how components communicate with each other. Again, there is a messy history: the original AWT event model has been overlaid by the new AWT event model, later adopted by Swing. What there is now is a notion of event sources (buttons, menus, text fields) and event listeners (pieces of code that do things). Once an application has put together its visible components, it registers some listeners with them. As the user points and clicks, sources fire off events to all interested listeners, which then do things. This is a multicast system, where a source can have any number of listeners. Although this sounds very concurrent, in fact everything happens in a single event-dispatching thread. “Firing” an event just means calling a method on a listener; and while that method is running, the whole interface freezes up. If clicking a button should start some long-running activity, then the listener must spin off a separate worker thread so that the event-dispatching thread can get back to its job. There are events for every possible activity in a GUI. Low level things like when the mouse moves, a key is pressed, or released. Higher level things like a (graphical) button pressed, or text entered into a field. More abstract things, like a change in the status of some component, or the disposal of some resource. Any component may generate one of a range of events, and for each kind of event there is a corresponding kind of listener. Figures 8.2 and 8.3 demonstrate this for our tiny application, with listeners registered on the two buttons. Now when the user clicks on down it generates an action event, calling method actionPerformed on any registered ActionEventListeners and passing an actionEvent value with further details. In this case there is a DownButtonListener registered, whose actionPerformed method reads the value presently in the text field and reduces it by one. Interaction between components shows up as a data dependency in the code: whereas Figure 8.1 uses anonymous objects as components, now we give them names, so that listeners can refer to the value text field, and themselves be attached to the buttons up and down. 8.4

Building a GUI

The counter example takes a fairly standard route to assembling a GUI: create some components, register listeners, fit components together, display and wait for the events to roll in. Nothing at all happens in the program main method after show(): like most graphical applications this is wholly event driven. 3

CS2 Advanced Programming in Java note 8

CS2Bh 24.4.2002

Unfortunately this can lead to an explosion of classes. In Java we cannot simply register a piece of code as a listener; we have to write a whole new class with a method containing the code, and then create a single object of that class. What is worse, all these one-off classes need to share common data, which breaks encapsulation. There are various solutions, with varying merits. Java 2 extends the programming language itself with inner or nested classes, including anonymous classes, to help — we shall look at those in the next note. Often one listener will masquerade as several, using information about where an event came from to decide what to do. Another trick is to arrange that objects already in the program do double duty by implementing extra interfaces. Sometimes that can be reasonably natural: for example, making a component its own listener. At other times it is just a pun to save coding. The program in Figure 8.4 uses these to fit our whole application into a single class Counter, which is simultaneously all of the following. • A program, with a static main method. • A JFrame, the top-level application window. • An ActionListener for both buttons, using getSource() to discriminate. An all-in-one class like this can seem rather confusing. However, Java applications use the technique widely to contain class blowup; so be aware that a single class may in its time play many parts. 8.5

Further study

This note gives only the briefest of introductions to Swing. Learning how to use the library for real requires a lot more: reading tutorials, browsing manuals, and most of all finding out by doing. 1. Run the SwingSet2 demo. 2. Download the code for the Counter demo. Compile and run it. Find out what happens when you resize its window to be larger and smaller. 3. Add two buttons: “Random” to set the counter to a random integer 0–99, and “Quit” to exit the application. 4. Follow the Swing trail on the Java tutorial. 5. Write a text editor in Java. [Not in fact very hard.] Here are some sample features of Swing that you should find out about: layout managers that dynamically arrange components; factories for creating borders to decorate things; and the model-view-controller pattern that separates content from appearance. Ian Stark 4

CS2 Advanced Programming in Java note 8

import javax.swing.∗;

CS2Bh 24.4.2002

// GUI libraries

class Counter { public static void main (String[] args) { JFrame frame = new JFrame("Counter"); // Main window JPanel contents = new JPanel(); // What goes in it: contents.add(new JButton("Down")); contents.add(new JTextField("42")); contents.add(new JButton("Up"));

// − button // − field // − button

frame.setContentPane(contents); frame.pack(); frame.show();

// Put frame in window // Sort out size // Make it appear

} } Figure 8.1: A minimal graphical application. Complete, but does nothing.

5

CS2 Advanced Programming in Java note 8

import javax.swing.∗;

CS2Bh 24.4.2002

// GUI libraries

class Counter { public static void main (String[] args) { JButton down = new JButton("Down"); // First create JTextField value = new JTextField("42"); // the various JButton up = new JButton("Up"); // components // Register interested listeners down.addActionListener(new DownButtonListener(value)); up.addActionListener(new UpButtonListener(value)); JPanel contents = new JPanel(); contents.add(down); contents.add(value); contents.add(up);

// Fit all the // components // together

JFrame frame = new JFrame("Counter"); // Window to hold them frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setContentPane(contents); frame.pack(); frame.show();

// Sort out size // Make it appear

} } Figure 8.2: A livelier graphical application — now it does things. See next page for some supporting classes.

6

CS2 Advanced Programming in Java note 8

import javax.swing.∗; import java.awt.event.∗;

CS2Bh 24.4.2002

// GUI libraries // Events too

class DownButtonListener implements ActionListener { // This holds a reference to the text field we want to modify private JTextField value; DownButtonListener(JTextField v) { value = v; } // Constructor public void actionPerformed(ActionEvent e) { int i = Integer.parseInt(value.getText()); // Decipher the current value value.setText(Integer.toString(i−1)); // Set it to be one less } } class UpButtonListener implements ActionListener { // This holds a reference to the text field we want to modify private JTextField value; UpButtonListener(JTextField v) { value = v; } // Constructor public void actionPerformed(ActionEvent e) { int i = Integer.parseInt(value.getText()); // Decipher the current value value.setText(Integer.toString(i+1)); // Set it to be one more } } Figure 8.3: Supporting listener classes for counter on the previous page.

7

CS2 Advanced Programming in Java note 8

import javax.swing.∗; import java.awt.event.∗;

CS2Bh 24.4.2002

// GUI libraries // Events too

class Counter extends JFrame implements ActionListener { JButton down = new JButton("Down"); JTextField value = new JTextField("42"); JButton up = new JButton("Up"); JPanel contents = new JPanel(); // Main program code public static void main (String[] args) { JFrame counter = new Counter(); counter.show(); }

// // // //

Instance variables hold references to all the different components

// Create GUI // Set it going

// Constructor for this class builds the GUI Counter() { super("Counter"); // Create JFrame down.addActionListener(this); // Register self up.addActionListener(this); // as listener contents.add(down); contents.add(value); contents.add(up); setContentPane(contents);

// Put the pieces // in place

setDefaultCloseOperation(EXIT_ON_CLOSE); pack();

// Sort out sizes

} // As well as a frame, this object is also an event listener public void actionPerformed(ActionEvent e) { int i = Integer.parseInt(value.getText()); // Decipher the current value if (e.getSource()==up) { i++; } else { i−−; } // Move up or down as appropriate value.setText(Integer.toString(i)); // Set the new value } } Figure 8.4: How to do it all in one class.

8