Programming user interfaces with the JFC

Jan Newmarch

Last modified: 25 January, 1999.
These slides are Copyright Jan Newmarch, 1998.

Abstract

This tutorial looks at GUI programming using the new JFC/Swing classes. It assumes a background of the AWT, and concentrates on additional features and changes from the AWT.


OVERVIEW


Evolution of Java GUI programming


Greater set of objects

The Swing set includes

Capability


JFrame


Hello World using Swing

import javax.swing.*;

public class JHello extends JFrame {

  public static void main(String argv[])
  {
    new JHello();
  }

  JHello() {
    JLabel hello = new JLabel("Hello World");
    getContentPane().add(hello, "Center");
    setSize(200, 200);
    setVisible(true);
  }
}

JBUTTON


JButton



JButton with Image

A button may be made with an icon image
 
import javax.swing.*;
import java.awt.*;

public class JButtonImage extends JFrame {

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

 
  public JButtonImage() {
    ImageIcon image1 =
              new ImageIcon("bart.gif");
    ImageIcon image2 =
              new ImageIcon("swing.small.gif");
    JButton btn1 = new JButton(image1);
    JButton btn2 = new JButton(image2);

    Container pane = getContentPane();
    pane.setLayout(new GridLayout(1, 2));
    pane.add(btn1);
    pane.add(btn2);
    pack();
  }
}
If the image has a transparent background (the second one), it looks better on pressing the button


JButton with more icons and text

Pressed, rollover and disabled icons can also be set

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

public class TestRollover extends JFrame {

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

 
  public TestRollover() {
    ImageIcon left =
              new ImageIcon("left.gif");
    ImageIcon leftRollover =
              new ImageIcon("leftRollover.gif");
    ImageIcon leftDown =
              new ImageIcon("leftDown.gif");

    JButton button = new JButton("Left",
                                 left);
    button.setPressedIcon(leftDown);
    button.setRolloverIcon(leftRollover);
    button.setRolloverEnabled(true);
    button.setToolTipText(
       "This is a Button with a RolloverIcon");

    getContentPane().add(button, "Center");
    pack();
  }
}

JButton with animated icon


Property change listeners


EVENTS


AWT events


AWT Event classes

The class AWTEvent has subclasses:


AWT Event ids

Some of these classes have an id value to distinguish between them

Triggering events

Events are posted by user actions (or may be done programmatically)

Listeners

Listeners are objects that handle events

Listeners as interfaces

Listeners are defined as interfaces and must be implemented by the application
 
public interface ActionListener
       extends EventListener {
  public void actionPerformed(ActionEvent e);
}

public interface MouseListener
       extends EventListener {
  public void mouseClicked(MouseEvent e);
  public void mousePressed(MouseEvent e);
  public void mouseReleased(MouseEvent e);
  public void mouseEntered(MouseEvent e);
  public void mouseExited(MouseEvent e);
}

Registering listeners


Simple Delegation program (1)

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

public class JDelegateDemo
             extends JFrame {
  public static void main(String argv[]) {
    new JDelegateDemo().setVisible(true);
  }

  public JDelegateDemo() {
    // create the GUI objects
    JButton left = new JButton("Left");
    JButton right = new JButton("Right");
    JLabel label = new JLabel("       ",
                   SwingConstants.CENTER);

 
    // set their geometry
    Container pane = getContentPane();
    pane.add(left, "West");
    pane.add(right, "East");
    pane.add(label, "Center");
    pack();

    // continue constructor
    // create a listener and add it to each Button
    SimpleListener simple = 
        new SimpleListener(label);
    left.addActionListener(simple);
    right.addActionListener(simple);    
  }
}

 

/**
 * A listener object that is invoked
 * when a Button is activated it finds
 * the Button's label and sets it in a Label
 */
class SimpleListener implements ActionListener {

  private JLabel label;

  public SimpleListener(JLabel l) {
    // the listener needs to know the Label
    // it will act on 
    label = l;
  }

 

  public void actionPerformed(ActionEvent e) {
    // get the label showing in whichever
    // Button was pressed
    String name = e.getActionCommand();

    // set this in the Label object
    label.setText(name);
  }
}    

Event Delivery Model


Event Model (2)

For a mouse press and mouse release on a Button inside a Frame, the following sequences for Java using X Windows occur


The Motif Pushbutton recognises that it has been clicked and sends an ActionEvent

Event Model (3)

For a mouse press and mouse release on a JButton inside a JFrame, the following sequences for Java using X Windows occur


The JButton now recognises it has been clicked

Changing key values (1)

import java.awt.*;
import java.awt.event.*;

public class MapKey extends Frame {
  public static void main(String argv[]) {
    new MapKey().setVisible(true);
  }
  public MapKey() {
    TextField text = new TextField(20);
    add(text);	
    pack();
    text.addKeyListener(new ToUpper());
  }
}

Changing key values (2)


class ToUpper implements KeyListener {
    
  public void keyTyped(KeyEvent e) {
    // empty
  }

  public void keyPressed(KeyEvent e) {
    e.setModifiers(Event.SHIFT_MASK);
  }

  public void keyReleased(KeyEvent e) {
    // empty
  }
}

Consuming events


Consuming events

This key listener discards non-alphabetic events:
public class Alpha implements KeyListener {
  public void keyPressed(KeyEvent e) {
    if (! Character.isLetter(e.getKeyChar())) {
      Toolkit.getDefaultToolkit().beep();
      e.consume();
     }
  }
  public void keyReleased(KeyEvent e) {
    // empty
  }
  public void keyTyped(KeyEvent e) {
    // empty
  }
}

Generating Events


GEOMETRY


Insets


Borders

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

public class TestBorder extends JFrame {

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

 
  public TestBorder() {

    Border border = BorderFactory.
                       createBevelBorder(
                           BevelBorder.RAISED);
    JLabel label = new JLabel("Hello");
    label.setBorder(border);
    getContentPane().add(label, "Center");
    pack();
  }
}

Layout Objects


BorderLayout


BorderLayout (2)

 
import java.awt.*;

class TestBorderLayout extends JFrame {
  public TestBorderLayout() {
    Container pane = getContentPane();
    pane.add(new JButton("Push Me W"), "West");
    pane.add(new JButton("Push Me E"), "East");
    pane.add(new JButton("Push Me S"), "South");
    pane.add(new JButton("Push Me N"), "North");
    setSize(400, 200);
    setVisible(true);
  }
}

Building your own manager


Building your own manager

The following manager sets the size of its (single) child (ignoring insets):
 
class SizeLayout implements LayoutManager {
  Dimension size;

  public SizeLayout() {
    size = new Dimension(0, 0);
  }

  public SizeLayout(Dimension s) {
    size = new Dimension(s);
  }

 
  public void setSize(Dimension s) {
    size = new Dimension(s);
  }

  public Dimension getSize() {
    return new Dimension(size);
  }

  public void
  addLayoutComponent(String n, Component c) {
  }

  public void
  removeLayoutComponent(Component c) {
  }

 
  public Dimension
  preferredLayoutSize(Container parent) {
    if (parent.countComponents() == 0)
      return new Dimension(width, height);

    // use the first component added
    Component c = parent.getComponent(0);
    return c.preferredSize();
  }

 
  public Dimension
  minimumLayoutSize(Container parent) {
    if (parent.countComponents() == 0)
      return new Dimension(width, height);

    // use the first component added
    Component c = parent.getComponent(0);
    return c.minimumSize();
  }

 
  public void
  layoutContainer(Container parent) {
    if (parent.countComponents() == 0)
      return;

    // use the first component added
    Component c = parent.getComponent(0);
    c.setBounds(0, 0, size.width, size.height);
    c.validate();
  }
}

Building constraint managers


Reusing GridBagLayout

Layout managers can also be built by restricting the use of a complex manager such as GridBagLayout. This manager gives a ``box of buttons'' layout
 
public class ButtonBoxLayout
       implements LayoutManager {

  GridBagLayout gridbag = new GridBagLayout();
  GridBagConstraints constraints =
             new GridBagConstraints();

  public void
  addLayoutComponent(String name, Component comp) {
    // empty -this should never be called
  }

 
  public void
  removeLayoutComponent(Component comp) {
    // empty - no state maintained here
  }

  // the next three methods restore state
  // if the parent has had changes done to
  // its children, before calling gridbag
  public Dimension
  preferredLayoutSize(Container parent) {
    if ( ! parent.isValid()) {
      layoutButtons(parent);
    }
    return gridbag.preferredLayoutSize(parent);
  }

 
  public Dimension
  minimumLayoutSize(Container parent) {
    if ( ! parent.isValid()) {
      layoutButtons(parent);
    }
    return gridbag.minimumLayoutSize(parent);
  }

  public void
  layoutContainer(Container parent) {
    if ( ! parent.isValid()) {
      layoutButtons(parent);
    }
    gridbag.layoutContainer(parent);
  }

 
  /**
   * Find the height of the first component,
   * and add half of it
   * above and below using ipady.
   * Find the largest width, and set ipadx
   * for all components to give it that width
   */
  protected void layoutButtons(Container parent) {

    int width = parent.getSize().width;
    int nbuttons = parent.getComponentCount();

    if (nbuttons == 0)
      return;

 
    constraints.weightx = 1.0;
    // stretch each component vertically
    constraints.ipady =
         parent.getComponent(0).
            getPreferredSize().height/2;

    // find the largest width
    Dimension compSize;
    int maxWidth = 0;
    for (int n = 0; n < nbuttons; n++) {
      compSize = parent.getComponent(n).
                getPreferredSize();
      maxWidth = Math.max(compSize.width, maxWidth);
    }

 
    // use the largest width or increase
    // using available space
    maxWidth = Math.max(width/(nbuttons*2), maxWidth);

    // set the ipadx to make each button the same size
    for (int n = 0; n < nbuttons; n++) {
      Component component = parent.getComponent(n);

      compSize = component.getPreferredSize();
      constraints.ipadx = maxWidth - compSize.width;
      gridbag.setConstraints(component, constraints);
    }
  }
 }

Composite Objects

Rather than doing geometry afresh each time, one can create new composite objects which are just reused in toto
 
public class LabelledTextField extends JPanel {
  protected JLabel label;
  protected JTextField text;

  public LabelledTextField(String lab, int cols) {
    setLayout(new BorderLayout());
    label = new JLabel(lab);
    text = new JTextField(cols);
    add(label, BorderLayout.WEST);
    add(text, BorderLayout.CENTER);
  }

 
  public String getText() {
    return text.getText();
  }

  public void addActionListener(ActionListener al) {
    text.addActionListener(al);
  }
}

ARCHITECTURE


Swing component architecture



JButton structure


ButtonModel


ButtonUI


Button UI elements


Button listeners

There is a set of listeners to decouple model and view from state change listeners

Looking for state changes by listeners simplifies the model and view a little.

Button instance



Changing the model


CountButtonModel

 
public class CountButtonModel
         extends DefaultButtonModel {

  protected int count = 0;

  public int getCount() {
    return count;
  }

  public void setPressed(boolean b) {
    // b is true if pressed,
    // false if released
    super.setPressed(b);
    if (b) {
      count++;
    }
  }
}

CountButton

 
public class CountButton extends JButton {

  public CountButton() {
    this(null, null);
  }

  public CountButton(Icon icon) {
    this(null, icon);
  }
  
  public CountButton(String text) {
    this(text, null);
  }
    

 
  public CountButton(String text, Icon icon) {
    super(text, icon);
    // Create the model
    setModel(new CountButtonModel());
  }

  public int getCount() {
    return ((CountButtonModel) model).getCount();
  }
}


Using the CountButton is done by e.g.
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import CountButton;

public class TestCountButton extends JFrame
               implements ActionListener{

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

 
  public TestCountButton() {
    CountButton btn = new CountButton("Press me");
    getContentPane().add(btn, BorderLayout.CENTER);
    pack();
    btn.addActionListener(this);
  }

  public void actionPerformed(ActionEvent evt) {
    CountButton btn = (CountButton) evt.getSource();
    System.out.println("Count: " + btn.getCount());
  }             
}


Changing the UI


JLIST


JList


JList with Strings


Simple JList example

This uses a list of Strings, like List
 
import javax.swing.event.*;
import javax.swing.*;

public class TestList extends JFrame 
       implements ListSelectionListener {

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

  public TestList() {
    String [] elmts = {"one", "two", "three"};
    JList list = new JList(elmts);
    getContentPane().add(list, "Center");
    pack();
    list.addListSelectionListener(this);
  }

 

  public void valueChanged(ListSelectionEvent evt) {
    JList list = (JList)
                 evt.getSource();
    String value = (String)
                 list.getSelectedValue();
    if (value != null &&
        ! evt.getValueIsAdjusting()) {
      System.out.println("Selected: " +
                          value);
    }
  }
}

JList using Icons

This shows a list of icons
 
import javax.swing.event.*;
import javax.swing.*;

public class TestIconList extends JFrame 
     implements ListSelectionListener {
  static public void main(String argv[]) {
    new TestIconList().setVisible(true);
  }

 
  public TestIconList() {
    ImageIcon images[] = new ImageIcon[2];
    images[0] = new ImageIcon("bart.gif");
    images[1] = new ImageIcon("swing.small.gif");

    JList list = new JList(images);
    getContentPane().add(list, "Center");
    pack();
    list.addListSelectionListener(this);
  }

 
  public void valueChanged(ListSelectionEvent evt) {
    JList list = (JList) evt.getSource();
    int value = list.getSelectedIndex();
    if (value != -1 && ! evt.getValueIsAdjusting()) {
      System.out.println("Selected: " + value);
    }
  }
}

Rendering JList with a Component

This shows a list of image+text, where rendering is done by calling paint() on a JLabel:
 
import java.awt.*;
import javax.swing.event.*;
import javax.swing.*;

public class TestLabelList extends JFrame {

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

  public TestLabelList() {

    JList list = new JList(new String [] {"Bart", "Swing"});
    getContentPane().add(list, "Center");
    list.setCellRenderer(new LabelCellRenderer());
    pack();
  }
}

 
class LabelCellRenderer extends JLabel 
            implements ListCellRenderer {

  static protected ImageIcon images[] = {
    new ImageIcon("bart.gif"),
    new ImageIcon("swing.small.gif")
  };

  public LabelCellRenderer() {
    setOpaque(true);
  }

 
  public Component
  getListCellRendererComponent(
               JList list, 
               Object value, 
               int index, 
               boolean isSelected, 
               boolean cellHasFocus) {
    setText(value.toString());
    setIcon(images[index]);
    setBackground(isSelected ?
            Color.red : Color.white);
    setForeground(isSelected ?
            Color.white : Color.black);
    return this;
  }
}

Rendering JList yourself

Draw your own shapes in a JList
 
import java.awt.*;
import javax.swing.event.*;
import javax.swing.*;

public class TestDrawList extends JFrame 
     implements ListSelectionListener {
  static public void main(String argv[]) {
    new TestDrawList().setVisible(true);
  }

 
  public TestDrawList() {

    JList list = new JList(new String []
                 {"Circle", "Square"});
    getContentPane().add(list, "Center");
    list.setCellRenderer(new DrawCellRenderer());

    // fix cell sizes since list doesn't know them
    list.setFixedCellWidth(30);
    list.setFixedCellHeight(30);
    pack();
  }
}

 
class DrawCellRenderer extends JComponent 
     implements ListCellRenderer {

  protected int index;
  boolean selected;

  public boolean isOpaque() {
    return true;
  }

 
  public Component
  getListCellRendererComponent(
            JList list, 
            Object value, 
            int index, 
            boolean selected, 
            boolean cellHasFocus) {
    this.index = index;
    this.selected = selected;
    return this;
  }

 
  public void paint(Graphics g) {
    Color fg, bg;

    if (selected) {
      fg = Color.green;
      bg = Color.black;
    } else {
      fg = Color.red;
      bg = Color.white;
    }

 
    // fill background
    g.setColor(bg);
    g.fillRect(0, 0, getWidth(), getHeight());

    // draw shape
    g.setColor(fg);
    if (index == 0) {
      g.fillOval(5, 5, 25, 25);
    } else {
      g.fillRect(5, 5, 25, 25);
    }
  }
}

Scrolling list


TEXT


Text replacements


Model

The model is known as a Document, and can be shared between Text objects.

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

public class Text2 extends JFrame {

  public static void main(String argv[]) {
    new Text2().setVisible(true);
  }
  
  public Text2() {
    JTextArea text1 = new JTextArea("starting text", 5, 30);
    JTextArea text2 = new JTextArea(5, 30);
    text2.setDocument(text1.getDocument());

    Border border = BorderFactory.
                       createLineBorder(Color.black);
    text1.setBorder(border);
    text2.setBorder(border);

    Container pane = getContentPane();
    pane.setLayout(new GridLayout(2, 1));
    pane.add(text1);
    pane.add(text2);
    pack();
  }
  
}

Styles


Changing document colours

This program allows you to select a colour from a menu. Any text entered after that will be in that colour
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;

public class TestStyle extends JFrame
         implements ActionListener {

  private Style redStyle, blueStyle, greenStyle;
  private JTextPane text;

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

 
  public TestStyle() {
    JTextPane text = createEditor();
    getContentPane().add(text, "Center");
    setJMenuBar(createMenu());
    setSize(200, 200);
  }

 
  private JMenuBar createMenu() {
    JMenuBar mbar = new JMenuBar();
    JMenu color = new JMenu("Color");
    mbar.add(color);

    JMenuItem mi = new JMenuItem("Red");
    color.add(mi);
    mi.addActionListener(this);

    mi = new JMenuItem("Blue");
    color.add(mi);
    mi.addActionListener(this);

    mi = new JMenuItem("Green");
    color.add(mi);
    mi.addActionListener(this);

    return mbar;
  }

 
  public void actionPerformed(ActionEvent evt) {
    Style style = null;
    String color = (String) evt.getActionCommand();
    if (color.equals("Red")) {
      style = redStyle;
    } else if (color.equals("Blue")) {
      style = blueStyle;
    } else if (color.equals("Green")) {
      style = greenStyle;
    }
    text.setCharacterAttributes(style, false);
  }

 
  private JTextPane createEditor() {
    StyleContext sc = createStyles();
    DefaultStyledDocument doc = new DefaultStyledDocument(sc);

    return (text = new JTextPane(doc));
  }

 
  private StyleContext createStyles() {
    StyleContext sc = new StyleContext();

    redStyle = sc.addStyle(null, null);
    StyleConstants.setForeground(redStyle,
                   Color.red);

    blueStyle = sc.addStyle(null, null);
    StyleConstants.setForeground(blueStyle,
                   Color.blue);

    greenStyle = sc.addStyle(null, null);
    StyleConstants.setForeground(greenStyle,
                   Color.green);
    StyleConstants.setFontSize(greenStyle, 24);

    return sc;
  }
}

Convenience Action Listeners


FileChooser


 
// using an embedded JFileChooser

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

public class BasicChooser extends JFrame 
                implements ActionListener {
  JFileChooser chooser;

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

 
  public BasicChooser() {
    getContentPane().add(chooser = new JFileChooser(), 
               BorderLayout.CENTER);
    chooser.addActionListener(this);
    pack();
  }

  public void actionPerformed(ActionEvent e) {
    System.out.println(chooser.getSelectedFile().
                   getName());
  }
}

 
// using a JFileChooser in a dialog

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

public class BasicChooser extends JFrame {
  JFileChooser chooser;

  static public void main(String argv[]) {
    BasicChoser bc = new BasicChooser();
    bc.setVisible(true);
    chooser.showOpenDialog(bc);
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      System.out.println("You selected file: " +
      chooser.getSelectedFile().getName());
    }
  }

 
  public BasicChooser() {
    setSize(100, 100);
  }
}

Menus


JMenuBar


JMenu


JMenuItem and JCheckboxMenuItem


Menus, toolbars and abstract actions

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

public class TestAction extends JFrame {
  OpenAction openAction = new OpenAction();
  SaveAction saveAction = new SaveAction();
  
  public static void main(String argv[]) {
    new TestAction().show();
  }

 
  TestAction()
  {
    createMenu();
    createToolBar();
    setSize(300, 300);
  }
  

 
  private void createMenu()
  {
    JMenuBar mb = new JMenuBar();
    JMenu fileB = new JMenu("File");
    mb.add(fileB);
    
    fileB.add(openAction);
    fileB.add(saveAction);
    
    setJMenuBar(mb);
  }
  

 
  private void createToolBar() {
    JToolBar bar = new JToolBar();
    bar.add(openAction);
    bar.add(saveAction);
    getContentPane().add(bar, BorderLayout.NORTH);
  }
}
  

 
class OpenAction extends AbstractAction {
  
  public OpenAction() {
    super("Open", new ImageIcon("open.gif"));
  }
  
  public void actionPerformed(ActionEvent e) {
    System.out.println("Open action");
  }
}

 
class SaveAction extends AbstractAction {
  
  public SaveAction() {
    super("Save", new ImageIcon("save.gif"));
  }
  
  public void actionPerformed(ActionEvent e) {
    System.out.println("Save action");
  }
}

DIALOGS


Dialogs


Dialog types

The dialog types can be This controls the default icon used

Dialog buttons

The dialog buttons can be You can choose your own buttons (labels or images)

Default warning dialog

Use JOptionPane.showMessageDialog():
 
import javax.swing.*;
import java.awt.event.*;

public class TestWarning extends JFrame 
             implements ActionListener {

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

  public TestWarning() {
    JButton btn = new JButton("Show dialog");
    getContentPane().add(btn, "Center");
    pack();
    btn.addActionListener(this);
  }

 
  public void actionPerformed(ActionEvent evt) {
    JOptionPane.showMessageDialog(this,
              "Warning", 
              "Warning Dialog", 
               JOptionPane.WARNING_MESSAGE);
  }
}

Confirmation dialog

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

public class TestConfirmation extends JFrame 
             implements ActionListener {

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

 
  public TestConfirmation() {
    JButton btn = new JButton("Show dialog");
    getContentPane().add(btn, "Center");
    pack();
    btn.addActionListener(this);
  }

 
  public void actionPerformed(ActionEvent evt) {
    int response = JOptionPane.showConfirmDialog(this,
              "Answer Yes or No", 
              "Confirmation Dialog", 
               JOptionPane.YES_NO_OPTION);
    String responseStr = null;
    if (response == JOptionPane.YES_OPTION) {
      responseStr = "Yes";
    } else {
      responseStr = "No";
    }
    System.out.println("Response: " + responseStr);
  }
}

Input dialog

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

public class TestInput extends JFrame 
             implements ActionListener {

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

 
  public TestInput() {
    JButton btn = new JButton("Show dialog");
    getContentPane().add(btn, "Center");
    pack();
    btn.addActionListener(this);
  }

 
  public void actionPerformed(ActionEvent evt) {
    String response = JOptionPane.showInputDialog(this,
              "Enter name", 
              "Input Dialog", 
               JOptionPane.DEFAULT_OPTION);
    System.out.println("Response: " + response);
  }
}

Other dialogs


Keyboard traversal

The following program moves an X around a 3x3 set of buttons by use of the arrow keys
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class TestKeyboardAction extends JFrame
                  implements ActionListener {

  protected JButton [] buttons = new JButton[9];

  static public void main(String argv[]) {
    new TestKeyboardAction().show();
  }

 
  public TestKeyboardAction() {
    Container pane = getContentPane();
    pane.setLayout(new GridLayout(3, 3));

    Border border = BorderFactory.
               createLineBorder(
                 Color.black);
    KeyStroke up = KeyStroke.getKeyStroke(
                 KeyEvent.VK_UP, 0);
    KeyStroke down = KeyStroke.getKeyStroke(
                 KeyEvent.VK_DOWN, 0);
    KeyStroke left = KeyStroke.getKeyStroke(
                 KeyEvent.VK_LEFT, 0);
    KeyStroke right = KeyStroke.getKeyStroke(
                 KeyEvent.VK_RIGHT, 0);

 
    JRootPane rootPane = getRootPane();
    rootPane.registerKeyboardAction(this,
            "up", up,
            JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    rootPane.registerKeyboardAction(this,
            "down", down,
            JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    rootPane.registerKeyboardAction(this,
            "right", right,
            JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    rootPane.registerKeyboardAction(this,
            "left", left,
            JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

 
    for (int n = 0; n < 9; n++) {
      JButton button = new JButton();
      button.setBorder(border);
      button.setName(new Integer(n).toString());
      pane.add(button);

      buttons[n] = button;
    }
    setSize(200, 200);
  }

   
  public void actionPerformed(ActionEvent e) {

    Component focusOwner = getFocusOwner(); // Window method
    String name = focusOwner.getName(); // get btn's name
    int index = Integer.parseInt(name); // as an int
    buttons[index].setText(""); // clear text
    String action = e.getActionCommand();

 
    // find next index for this action
    if (action.equals("up")) {
      index = (index < 3) ? index + 6 : index - 3;
    } else if (action.equals("down")) {
      index = (index > 5) ? index - 6 : index + 3;
    } else if (action.equals("left")) {
      index = (index == 0) ? index = 8 : index - 1;
    } else { // assume right
      index = (index == 8) ? index = 0 : index + 1;
    }

 
    buttons[index].setText("X"); // set text in next btn
    buttons[index].requestFocus(); // and focus to it
  }
}


Further Information




Jan Newmarch (http://jan.newmarch.name)
jan@newmarch.name
Last modified: Thu Jan 28 10:23:50 EST 1999
Copyright ©Jan Newmarch
All material on this site is under the copyright restriction and permissions of the Open Content license, http://www.opencontent.org/opl.shtml