Home Accessibility Courses Diary The Mouth Forum Resources Site Map About Us Contact
 
Python and Tcl - public course schedule [here]
Private courses on your site - see [here]
Please ask about maintenance training for Perl, PHP, Lua, etc
 
Extending Graphics in Java part 2

SIMPLE SWING

Here's the simplest stand-alone Swing application:

import javax.swing.*;

public class Swtiny extends JPanel {

// Swing main program

public static void main (String [] args) {

    JFrame frame = new JFrame ("Tiny, Stand alone");
    JLabel jl = new JLabel("A Tiny Example");

    frame.getContentPane().add(jl);
    frame.setSize(180,80);
    frame.setVisible(true);

}
}

When run, you see


Our application creates a top level Frame (a window) into which we're going to place our component - the Frame is labelled with the text "Tiny, Stand alone".

The frame is set to a size of 180 x 80 pixels, and to be visible - without settings like these, you won't see it, or it will be 0 x 0 which looks like this:


(We show you in case it happens to you and you wonder where your window's gone ;-) )

JFrames have many properties ... and one of those is their content pane. Do you see how much this is modelled on a real window? Rather than being filled with transparent glass, we fill our window pane with components - in this case a Swing Label (or JLabel), with the text "A Tiny Example" on it.

Components are created through constructors (just as you would expect - after all, that's the whole OO paradigm of Java), but they aren't placed in any position in any pane until instructed to do so by the program. This is rather like creating a piece for a board game, but not actually placing it onto the board until the time comes (and until you know where you want to place it). Think of it being like a house or hotel in Monopoly.

USING MULTIPLE COMPONENTS

You'll want to have more than one component on a Pane - just look at any typical GUI window and there's a whole lot of components there.

The layout managers from the AWT provide the ability to lay out components in many ways, and you can even write your own custom layout manager. We'll use the most basic - a flow layout - for our first example:

import java.awt.*;
import javax.swing.*;

public class S1 extends JFrame {

public static void main (String [] args) {
 new S1().setVisible(true);
 }

public S1 () {

 Container cp = getContentPane();
 cp.setLayout(new FlowLayout());

 cp.add(new JLabel("This is a test"));
 cp.add(new JButton("OK!"));
 pack();

 }
}

And the results:


With a flow layout, the components are placed one after another along the top of the pane ... when the right hand side is reached (which hasn't happened in this case), a second row is started, and so on.

Rather than specify a window size as we did in the earlier example that wasn't using a layout manager, we've now left the pack method to arrange the components, which in turn allows the size of the window to be calculated. Advantage - the window isn't going to be to small, nor have spurious white space. Disadvantage - run the same application GUI twice with different data, and it will come up looking different / different sizes.

Following on from our Monopoly hotels, we now create the components off the board using their constructors. The banker hands them to the player who's purchased them through the add method, and he chooses which properties to place them on using pack.

You'll note that getContentPane returns a Container object. This is an underlying AWT object; the "rule" is that if an object starts with a capital J, then it's a Swing object, and if it starts with any other letter it's in the awt. Why do you even need to know which are which:
 - to know where to look in the reference material
 - to know what you need to import
 - to know whether your class is usable in old browsers
   without the Java plugin.

Let's use another layout manager (a grid layout) in order to set up a series of buttons like a telephone keypad:


Here's the code:

import java.awt.*;
import javax.swing.*;

public class S2 extends JFrame {

public static void main (String [] args) {
 new S2().setVisible(true);
 }

public S2 () {

 Container cp = getContentPane();
 cp.setLayout(new GridLayout(4,3));

 String [] Phone = {"7","8","9","4","5","6",
   "1","2","3","*","0","#"};
 
 for (int i=0;i<Phone.length;i++) {
  cp.add(new JButton(Phone));
 }
 pack();

 }
}

Our GridLayout is set to 4 rows by 3 columns, and as we add components in they fill up the rows one by one.

There's a huge number of properties you can change and additional methods available on layout managers and on individual components, but we're going to move on now to look at events.

EVENT HANDLING

Our Tiny "Hello Swing World" applications were really just too small. Although they provide a frame and adds graphics to the frame, they're just for display ... you can't actually DO anything with them. There's not even any way of getting rid of the window and closing the application properly.

Let's add event handling to our tiniest program:

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

public class Swsmall extends JPanel {

// Swing main program

public static void main (String [] args) {

    JFrame frame = new JFrame ("Stand alone");
    JLabel jl = new JLabel("Exits properly");

    frame.getContentPane().add(jl);
    frame.setSize(180,80);
    frame.setVisible(true);

    frame.addWindowListener(new winEvent());
    }
}

Which also involves us in adding an event handler class as well:

import java.awt.event.*;
class winEvent extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
    System.exit(0);
    }
}


Notice here that our main program defines our GUI, then defines a number (one!) of things to be done when an event happens, then appears to "fade out".

Because we've extended a Swing class, the application is left in a listener loop. It's waiting for an event to happen, and acting on that event when it gets it.

As well as windowClosing, we can provide methods such as windowActivated and windowDeactivated if we want to track when focus comes in and out of our window, and several others. The WindowAdapter class is a trivial implementation of the WindowListener interface; if you provide all 7 methods defined by that interface, you can switch to an "implements" and save your inheritance!

FEEDBACK FROM EVENTS ON INDIVIDUAL COMPONENTS

As well as handling events on our window, we can (and usually will) handle them on individual components. Let's use the ActionListener interface to note which buttons are pressed on our telephone pad; in this example, we'll echo the key strokes to System.out, but then we'll move on to providing the feedback within the GUI.

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

public class Dial extends JFrame {

public static void main (String [] args) {
 new Dial().setVisible(true);
 }

public Dial () {

 Container cp = getContentPane();
 cp.setLayout(new GridLayout(4,3));

 String [] Phone = {"7","8","9","4","5","6",
   "1","2","3","*","0","#"};
 
 for (int i=0;i<Phone.length;i++) {
  JButton current;
  cp.add(current = new JButton(Phone));
  current.addActionListener(
   new ActionListener()

// Definition through an inner class =============================
 {
 public void actionPerformed(ActionEvent e) {
  System.out.print(e.getActionCommand());
  }
 }
// End of inner class definition =================================
 );
 }
 pack();

 }
}

We've chosen to use an inner class here to define the action to be performed ... saves us getting too many separate source files all over the place! You will find that a file called Dial$1.class has turned up so it does NOT save you a class file .... but then you'll be using a jar for distribution, won't you?

The keypad just looks the same as the earlier one did, but when you run it and select buttons, you'll get ...

$
01225708225
$

PROVIDING FEEDBACK IN THE GUI

We'll now complete our telephone dialling GUI, by providing feedback of the number being dialled within the panel, and also providing controls such as a "done" button. Here's what it will look like in use:


and here's the source code:

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

public class Dialer extends JFrame {

static String PhoneNumber = "";
JLabel Result;

public static void main (String [] args) {
 new Dialer().setVisible(true);
 }

public Dialer () {

 Container cp = getContentPane();
 cp.setLayout(new GridLayout(2,1));

// Upper panel - responses

 JPanel upper = new JPanel();
 upper.setLayout(new GridLayout(3,1));

 upper.add(new JLabel("Dialer Example"));
 upper.add(Result = new JLabel(""));
 JButton OK;
 upper.add(OK = new JButton("OK"));
  OK.addActionListener(
   new ActionListener()
// Definition through an inner class =============================
 {
 public void actionPerformed(ActionEvent e) {
  System.out.println("Called "+PhoneNumber);
  System.out.println("Dialling Completed");
  System.exit(0);
  }
 }
// End of inner class definition =================================
 );

// Lower panel - keypad

 JPanel lower = new JPanel();
 lower.setLayout(new GridLayout(4,3));

 String [] Phone = {"7","8","9","4","5","6",
   "1","2","3","*","0","#"};
 
 for (int i=0;i<Phone.length;i++) {
  JButton current;
  lower.add(current = new JButton(Phone));
  current.addActionListener(
   new ActionListener()

// Definition through an inner class =============================
 {
 public void actionPerformed(ActionEvent e) {
  PhoneNumber = PhoneNumber + e.getActionCommand();
  Result.setText(PhoneNumber);
  }
 }
// End of inner class definition =================================
 );
 }
 cp.add(upper);
 cp.add(lower);
 this.pack();

 }
}

Things to notice here:

 static String PhoneNumber = "";
 JLabel Result;

are both declared as class rather than local variables, so that they can be used within the inner class; local variables can only be used in the inner class if they're declared as final (i.e. unchanging), which is not appropriate in this case.

We've now got not one but three grid layouts, as we've provided a more complex composite layout. We could have used any of the other layout managers (Border, Grid, GridBag, Flow, Box) or our own for any of the layouts had we wished - Indeed, a Border might have been more appropriate for the outer layout as it would allow the upper and lower areas to differ in size.

The inner panels had to be added to the outer panel - this does not happen automatically (and failure to do so means that the inner panels are not displayed). The whole still had to be packed.

The main action listener (the one that we've used for all the buttons on the telephone pad) actually goes back and modifies the text in the feedback box:

 public void actionPerformed(ActionEvent e) {
  PhoneNumber = PhoneNumber + e.getActionCommand();
  Result.setText(PhoneNumber);
  }

which is really at the heart of the changes in this example.

HELLO SWING WORLD AS AN APPLET

The minimal Swing applet doesn't need to allow for window closing (after all, it's the browser that provides such management) so a "Hello Swing World" applet is much simpler:

import javax.swing.*;

public class Swapp extends JApplet {

// Swing applet

public void init() {

    JLabel jl = new JLabel("Swing based Applet");
    this.getContentPane().add(jl);
}
}

In order to run this, though, you do need a web page in HTML which includes an object tag (or an applet tag, although that's now deprecated):

<html>
<head>
<title>Swing Applet - Hello World</title>
</head>
<body bgcolor=white>
Test applet:<P>
<object code=Swapp.class width=220 height=110>
</object><P>
Uses Java Swing
</body>
</html>


A COMPLETE GUI ON AN APPLET

Here's our Dialer application as an Applet:


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

public class DialApplet extends JApplet {

static String PhoneNumber = "";
JLabel Result;

public void init () {
 new DialApplet();
 }

public DialApplet () {

 Container cp = getContentPane();
 cp.setLayout(new BorderLayout());

// Upper panel - responses

 JPanel upper = new JPanel();
 upper.setLayout(new GridLayout(3,1));

 upper.add(new JLabel("Dialer Example"));
 upper.add(Result = new JLabel(""));
 JButton OK;
 upper.add(OK = new JButton("OK"));
  OK.addActionListener(
   new ActionListener()
// Definition through an inner class =============================
 {
 public void actionPerformed(ActionEvent e) {
  // Following inappropriate for an Applet!
  // System.out.println("Called "+PhoneNumber);
  // System.out.println("Dialling Completed");
  // System.exit(0);
  }
 }
// End of inner class definition =================================
 );

// Lower panel - keypad

 JPanel lower = new JPanel();
 lower.setLayout(new GridLayout(4,3));

 String [] Phone = {"7","8","9","4","5","6",
   "1","2","3","*","0","#"};
 
 for (int i=0;i<Phone.length;i++) {
  JButton current;
  lower.add(current = new JButton(Phone));
  current.addActionListener(
   new ActionListener()

// Definition through an inner class =============================
 {
 public void actionPerformed(ActionEvent e) {
  PhoneNumber = PhoneNumber + e.getActionCommand();
  Result.setText(PhoneNumber);
  }
 }
// End of inner class definition =================================
 );
 }
 cp.add(upper,BorderLayout.NORTH);
 cp.add(lower,BorderLayout.SOUTH);
 // cp.pack();

 }
}

You might like to note that we had to make the following changes to our stand alone GUI application to change it into an Applet:

1. main was removed, and init added

2. It now extends JApplet rather than JFrame

3. pack was removed

4. sizing The size of the window is now taken from the HTML rather than from the size that's needed to hold the components; beware, you may find unwanted white space, or compressed or overlapping parts of your GUI if you don't think this one through properly.

5. System.out.println and System.exit removed; you can't print to the user's display, nor can you exit from a browser. Chances are that results would be passed back via your network to the host from which the applet was loaded - a topic that's beyond the scope of this module.

What if you want to use the same class as both a stand alone application and within a browser? That's quite feasible; you provide both main and init methods, you note whether you're running an applet or not (a good use for a boolean) and you can then put in small adjustments as necessary to cover the points that we listed as changes above.

Note - we have modified this Dialer example to use a BorderLayout for the outer frame; this was not a necessary change as we moved across to an applet - it's done to provide you with an example of a different layout to the GridLayout


See also

Please note that articles in this section of our web site were current and correct to the best of our ability when published, but by the nature of our business may go out of date quite quickly. The quoting of a price, contract term or any other information in this area of our website is NOT an offer to supply now on those terms - please check back via our main web site

Related Material

Extending Graphics in Java
  [1326] GUI design - Sketch it out first! (Java / Swing example) - (2007-08-30)
  [1325] Java - Client side applet applications as well as server side - (2007-08-29)

resource index - Java
Solutions centre home page

You'll find shorter technical items at The Horse's Mouth and delegate's questions answered at the Opentalk forum.

At Well House Consultants, we provide training courses on subjects such as Ruby, Lua, Perl, Python, Linux, C, C++, Tcl/Tk, Tomcat, PHP and MySQL. We're asked (and answer) many questions, and answers to those which are of general interest are published in this area of our site.

You can Add a comment or ranking to this page

© WELL HOUSE CONSULTANTS LTD., 2019: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01225 708225 • FAX: 01225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho

PAGE: http://www.wellho.net/solutions/java-ext ... art-2.html • PAGE BUILT: Wed Mar 28 07:47:11 2012 • BUILD SYSTEM: wizard