Java Window Focus and State in Java, Part 2

Window Focus and State in Java, Part 2

Java Programming, Notes # 1858


Preface

The focus subsystem

This lesson is part of a series designed to
teach you how to use features of the focus subsystem.  This is also the second part of a two-part lesson designed to teach you how to
write code to use Window focus and state features.

The first lesson in the series was entitled
Focus
Traversal Policies in Java Version 1.4
.  The previous lesson was
entitled Window Focus and State in Java, Part 1 of 2.

Previous topics

Previous lessons in this series have taught you how to use several features of the new focus subsystem,
including the following:

  • Defining new focus traversal keys.
  • How to control focusability at runtime.
  • The ability to query for the currently focused Component.
  • The default Focus Traversal Policy.
  • How to establish a focus traversal policy and modify it at runtime.
  • How to control the focus programmatically.
  • Opposite components.
  • The KeyEventDispatcher.
  • The KeyEventPostProcessor.

Topics covered in this lesson

Part 1 of this two-part lesson explained Window
focus and extended Window state.

This lesson will present and explain a program that
demonstrates various aspects of Window focus and extended Window
state.

What do we mean by focus?

Among all of the applications showing on the desktop at any point in time,
only one will respond to the keyboard.

If that application is a Java application, only one component
within that application’s graphical user interface (GUI) will respond to
the keyboard.  That is the component that has the focus at that
point in time.

It is also possible for a Java Window, (and its
subclasses Frame, JFrame, Dialog, and JDialog)

to gain the focus and to respond to the
keyboard even if the Window contains no focusable components.

A Java component or Window that has the focus also has the ability to fire KeyEvents when it responds to the keyboard. 
The fact that a component or Window can fire KeyEvents confirms that it has the
focus.

Viewing tip

You may find it useful to open another copy of this lesson in a separate
browser window.  That will make it easier for you to scroll back and
forth among the different figures and listings while you are reading about
them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection
of online Java tutorials.  You will find those lessons published at
Gamelan.com.  However,
as of the date of this writing, Gamelan doesn’t maintain a consolidated index
of my Java tutorial lessons, and sometimes they are difficult to locate there. 
You will find a consolidated index at www.DickBaldwin.com.

Background Information

I provided a great deal of background information in zzPart 1 of this
two-part lesson.  I strongly recommend that you study that lesson before
embarking on this lesson.

I will recap some of that information very briefly in this lesson.

Window focus

Objects of the class Window and its subclasses
Frame, JFrame, Dialog, and JDialog have the ability
to gain the focus and to respond to the
keyboard even if the object doesn’t contain any focusable
components.

(Throughout this lesson, I will often refer to a Frame, a JFrame, a
Dialog, or a JDialog as a Window, because
Window is the superclass of these other classes.)

Extended Window state

Prior to V1.4, the state information maintained by a Window was limited
to:

  • NORMAL
  • ICONIFIED

V1.4 added the ability of a Window to maintain state information
that includes:

  • MAXIMIZED_HORIZ
  • MAXIMIZED_VERT
  • MAXIMIZED_BOTH

Window focus events

A Window can fire events when its state changes.

A program can respond to those events and determine both the old state and the
new state of the Window.

The program can also determine the current state at any point
in time by invoking the getExtendedState method on the Window.

Uses of Window focus

One might like to display an animated creature in a Window and to control its
movement and behavior using the keyboard. 

A Window that has the focus can respond to the
keyboard and fire KeyEvents.  Code can be written into the KeyEvent handlers to control the behavior of the animated creature.

(Although it doesn’t use an animated creature, the program that I will
explain in this lesson is similar to this example.)

Uses of Window state

Prior to the release of the extended state feature in V1.4, I was not aware of any mechanism that made it possible for
a program to determine that the user had maximized a Frame or a JFrame.

Subsequent to the release of V1.4, a program can register to be notified each time the state of a Window
changes, and can easily determine both the old state and the new state when the
change occurs.  Among other things, the program can determine that the user
has maximized the Window.

In addition, the extended current state is available at any time simply by
invoking the getExtendedState method on the Window.

Required modifications to the API

Several modifications were required to add these two
features to the API.  I provided a partial list of those changes in Part1.

Order of event delivery

When the focus moves from a component in one Window to another
Window
, or to a component in another Window, the transition requires a
well-defined series of steps in a specific order.  I explained those steps
in Part 1.

Preview

In Part 1 of this lesson, I explained how a Window
can gain the focus, and can respond to the keyboard while it has the focus, even
if that Window contains no focusable components.

I described both low-level and high-level event handlers to
respond to Window focus events.

I explained how to make use of the extended Window state and explained how a program can respond to Window state events to
learn that the user has maximized a Window.

I provided a program that illustrates the above concepts.  However, I did not explain that program in Part 1.

I will break that program down into fragments and explain it
in detail in this lesson.

Discussion and Sample
Code

The two parts of this lesson present and explain a sample program named FocusWindow02
that illustrates the ability of a Window:

  • To gain and lose the focus
  • To fire events when the focus is gained or lost

The program also illustrates the capability of a Window object to fire
events when the state of the Window changes among five different possible
states. Significant among these possible states are three states having to with
maximization of the Window.

I provided a detailed description of the operation of the program in Part
1, and will not repeat that description here.  I will provide just enough
of a description of the operation to be able to explain the code in detail.

The program GUI

The program causes two JFrame objects to appear on the screen as
shown in Figures 1 and 2.



Figure 1 Half of program GUI.

Only one can be active

Both JFrame objects appear on the screen at the same time, but only
one can be active at any given
time.



Figure 2 Other half of program GUI.

The JFrame object shown in Figure 1 contains two JButton objects, both of which are focusable.

The JFrame object shown in Figure 2 contains a
single Canvas object, which is not focusable. Therefore, the JFrame
object in Figure 2 contains no focusable components.

Coordinates of an invisible point

The JFrame object in Figure 2 displays the coordinates of an
invisible point on the Canvas near the location of the
invisible point.

(The location of the invisible point is immediately to the left of and
slightly below the left-most character in the coordinates.)

Behavior of the object in Figure 2

When this JFrame object has the focus, pressing an
arrow key causes an increase or a decrease in a coordinate value for the invisible point.  Thus, pressing the arrow keys modifies and moves the displayed coordinate values.

(Thus, the behavior is similar to, but simpler than using the keys to
control the movement and behavior of an animated creature.)

Behavior of the object in Figure 1

The JFrame object in Figure 1 contains two JButton objects labeled
respectively:

  • Regain focus
  • Send focus to B

Very briefly, clicking the button labeled Regain focus causes the JFrame object in Figure 1
and the JButton object labeled Regain focus to gain
the focus.

(I described the series of steps involved in this process in detail in Part 1.)

Clicking the button labeled Send focus to B in Figure 1 causes the
JFrame object in Figure 2 to gain the focus.

(I also described the series of steps involved in this process in
detail in Part 1.)

Gaining focus in Figure 2

The JFrame object in Figure 2 will also gain the focus if it is
clicked with the mouse, and it can gain the focus in a few other ways as well
(such as restoring it to the screen from the iconified state).

Screen output

As each JFrame object gains and loses focus, and becomes iconified or
maximized, information about the
gain and loss of focus and the status of the Window is displayed on the screen.

This is accomplished using both high-level event handling and low-level event
handling.

High-level and low-level event handling

I explained the difference between high-level and low-level event handling in
Part 1.

Sample screen output

The screen output at startup is shown in Figure 3.

Low:processWindowEvent B
205 WINDOW_ACTIVATED

Low:processWindowFocusEvent B
207 WINDOW_GAINED_FOCUS
High:windowGainedFocus B

Low:processWindowEvent B
200 WINDOW_OPENED

Low:processWindowFocusEvent B
208 WINDOW_LOST_FOCUS
High:windowLostFocus B

Low:processWindowEvent B
206 WINDOW_DEACTIVATED

Low:processWindowEvent A
205 WINDOW_ACTIVATED

Low:processWindowFocusEvent A
207 WINDOW_GAINED_FOCUS
High:windowGainedFocus A
High:focusGained on Regain focus button

Low:processWindowEvent A
200 WINDOW_OPENED

Figure 3

Low-level event handling output

The lines of text that begin with the word Low, and the lines that
begin with a number such as 205 were produced by low-level event handlers.

High-level event handling output

The lines that begin with the word High were produced by high-level
event handlers.

Will discuss the program in fragments

The program was tested using J2SE 5.0 under WinXP

I will discuss this program in fragments.  A complete listing of the
program is provided in Listing 25 near the end of the lesson.

The class named FocusWindow02

The beginning of the program and the main method are shown in Listing
1.

public class FocusWindow02 extends JFrame{

  public static void main(String[] args){
    FocusWindow02 winA = new FocusWindow02();
  }//end main

Listing 1

The main method instantiates a new object of this class, which is the
object shown in Figure 1.  This object is identified as A in the screen
output.

Code in the constructor for this class instantiates an object of the class
named GraphicsGUI, which is the object shown in Figure 2.  This
object is identified as B in the screen output.

The constructor for FocusWindow02

The constructor for the class named FocusWindow02 begins in Listing 2.

  public FocusWindow02(){//constructor

    final GraphicsGUI winB = new GraphicsGUI();

Listing 2

A new object of the GraphicsGUI class

The code in Listing 2 instantiates a new object of the class named GraphicsGUI, and saves the object’s reference in a reference variable named
winB.  As mentioned above, this is the object shown in Figure 2.

I will explain the code in the GraphicsGUI class shortly. 

The screen output

The first seven lines of output in
Figure 3 were produced when this object was constructed and became visible. 
As you can see,

  • It became the active window.
  • It gained the focus
  • Then it opened

Giving up the focus

The next five lines in Figure 3 were produced as the object of the GraphicsGUI class gave up its
active status and gave up the
focus to the object of the FocusWindow02 class, which was constructed
immediately after the construction of the GraphicsGUI object.

As you can see from Figure 3, the object of the GraphicsGUI class first lost the
focus and then became deactivated.  This happened when the object of the FocusWindow02 class became visible on the screen.

Construction of the FocusWindow02 object

The bottom eight lines of output in Figure 3 were produced as the object of
the FocusWindow02 class became active and gained the focus.  As you
can see, the object first became active and then gained the focus.  Then
the button on the left in Figure 1 gained the focus.  Finally, the window
opened.

Set property values

Continuing with the constructor for the FocusWindow02 class the code
in Listing 3 sets some typical property values.

    setTitle("A Copyright 2004, R.G.Baldwin");
    getContentPane().setLayout(new FlowLayout());
    setSize(400,100);
    setDefaultCloseOperation(
                           JFrame.EXIT_ON_CLOSE);

Listing 3

There is nothing new in the code in Listing 3, so I won’t
discuss it further.

Create and condition the buttons

The code in Listing 4:

  • Instantiates the two JButton objects
  • Registers a high-level FocusListener object on each button
  • Places the two buttons in the JFrame object shown in Figure 1
    JButton regainButton = new JButton(
                                 "Regain focus");
    regainButton.addFocusListener(
                               new FocusLstnr());
    getContentPane().add(regainButton);

    JButton sendButton = new JButton(
                              "Send focus to B");
    sendButton.addFocusListener(
                               new FocusLstnr());
    getContentPane().add(sendButton);

Listing 4

This code is straightforward, so I will leave it at that.

Register an ActionListener on one of the buttons

The code in Listing 5 uses an anonymous inner
class to register a high-level ActionListener object on the rightmost
button shown in Figure 1.

    sendButton.addActionListener(
      new ActionListener(){
        public void actionPerformed(
                                  ActionEvent e){
          winB.requestFocus();
        }//end actionPerformed
      }//end new ActionListener
    );//end addActionListener

Listing 5

The interesting part

The interesting part of this code is the statement near the center where
the requestFocus method is invoked on the reference to the JFrame
object shown in Figure 2. 

The sequence of events

Assuming that the object shown in Figure 1 is
the active object and the button labeled Regain focus has the focus when
the button labeled Send focus to B is clicked, the screen output produced
as a result of this action is shown in Figure 4.

High:focusLost on Regain focus button
High:focusGained on Send focus to B button
High:focusLost on Send focus to B button

Low:processWindowFocusEvent A
208 WINDOW_LOST_FOCUS
High:windowLostFocus A

Low:processWindowEvent A
206 WINDOW_DEACTIVATED

Low:processWindowEvent B
205 WINDOW_ACTIVATED

Low:processWindowFocusEvent B
207 WINDOW_GAINED_FOCUS
High:windowGainedFocus B

Figure 4

The steps in the sequence are:

  • Focus is transferred from the Regain focus button to the Send
    focus to B
    button on the Window in Figure 1
  • The Send focus to B button loses focus on the Window in
    Figure 1
  • The Window shown in Figure 1 loses focus
  • The Window shown in Figure 1 is deactivated
  • The Window shown in Figure 2 is activated
  • The Window shown in Figure 2 gains the focus

Pressing the arrow keys

Because there are no focusable components in the Window in Figure 2,
the focus comes to rest on the Window.

At this point, the Window in Figure 2 will respond to keystrokes from the keyboard.  As
we will see later, if the user presses any of the arrow keys on the keyboard,
the values of the coordinates shown in Figure 2 will be modified, and the
location at which those coordinates are drawn will change to reflect the new
values.

Enable WindowEvents

Continuing once more with the constructor, the statement in Listing 6
prepares the Window in Figure 1 to respond to WindowEvents on a
low-level basis.

    enableEvents(AWTEvent.WINDOW_EVENT_MASK);

Listing 6

The low-level
event methods

Following the execution of this statement, all Window events fired by
the JFrame object will be delivered to one of the following three
methods, which are defined in the Window class and inherited into the JFrame class. 

  • processWindowEvent(WindowEvent e)
  • processWindowFocusEvent(WindowEvent e)
  • processWindowStateEvent(WindowEvent e)

(The Sun documentation indicates that these methods will be invoked if
any WindowListener objects are registered on the JFrame even if
the enableEvents method in Listing 6 has not been explicitly invoked.)

The dispatcher for WindowEvents

Further, the Sun documentation indicates that these three methods actually dispatch
all WindowEvents to all registered WindowListener objects.

(Event handling provided by registered WindowListener objects is what I have been
referring to as high-level event handling.)

Methods can be overridden

You can override these methods to provide WindowEvent handling in addition to the handling provided by registered
WindowListener objects.

(This is what I have been referring to as
low-level event handling.)

Caution

If you do override these methods, you must be sure to include statements similar to
the following in your overridden versions of the methods.

 super.processWindowEvent(e);
 super.processWindowFocusEvent(e);
 super.processWindowStateEvent(e);

If you fail to do so, the events will be stopped short in your overridden
version of the method and won’t be dispatched to registered WindowListener
objects.

The placement of the statement

You can place this statement anywhere in your overridden method as long as you
make certain that it will be executed.

By adjusting the location of the
statement, you can control the order in which low-level and high-level event
handling occurs.

If you put the statement at the end of the method, low-level event handling will
take place before high-level event handling. 

If you put it at the beginning of the method,
high-level event handling will take place before low-level event handling. 

If
you place it somewhere in the middle, some low-level event handling will take
place
before high-level event handling, and some low-level event handling will take
place
after high-level event handling.

Register high-level WindowListener objects

Still in the constructor, the code in Listing 7 registers WindowListener objects on the
JFrame in Figure 1 to perform high-level handling of WindowEvents.

    addWindowFocusListener(new WindowLstnr());
    addWindowStateListener(new WindowLstnr());

Listing 7

I will discuss the code in the WindowListener class named WindowLstnr later.

Make the JFrame visible

Finally, the code in Listing 8 causes the JFrame shown in Figure 1 to become
visible for the first time.

    setVisible(true);

  }//end constructor

Listing 8

By the time control reaches this point, the JFrame object in Figure 2
is already visible, is the active Window, and has the focus.

When this JFrame becomes visible, it will become the active Window
and will steal the focus from the JFrame in Figure 2.

(This is illustrated by the screen output shown in Figure 3.)

End the constructor

The code in Listing 8 also signals the end of the constructor for the class
named FocusWindow02.

A low-level event handler method

Listing 9 shows the overridden version of the method named processWindowEvent

  //Sample screen output for this method:
  // Low:processWindowEvent A
  // 205 WINDOW_ACTIVATED
  protected void processWindowEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                     "Low:processWindowEvent A");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowEvent(e);
  }//end processWindowEvent

Listing 9

Listing 9 also shows a sample of the screen output produced by this method in
the comments at the beginning of Listing 9.

Call the superclass version

Note the inclusion of the last statement in Listing 9, which invokes the
superclass version of the method, passing the WindowEvent object’s
reference as a parameter.  The superclass version in turn
dispatches the event to all registered WindowListener objects.

No listeners registered …

I didn’t register any WindowListener objects to handle WindowEvents
that would be dispatched by this method.  I only registered WindowListener objects to handle
Window
focus events and Window state events.

(These event types would be dispatched by the
other two low-level event handler
methods.)

However, this statement is still required for proper operation of the program.  Without it, the special
built-in event handler associated with the close button in the
upper-right corner of the JFrame doesn’t get executed.

(The built-in event handler probably operates on a hidden form of an event of type
WINDOW_CLOSING.)

Order of event handling

Because I invoked the superclass version at the end of the method, the
low-level event handling code executes before the high-level event handling
code.  This is illustrated in Figure 3.

The type of the event

The code in Listing 9 invokes the getEventType method to get a String that represents each numeric event type.  Otherwise, the code is
completely straightforward and shouldn’t require any further discussion.

(The getEventType method is also straightforward.  I will
show it to you shortly.)

The overridden processWindowFocusEvent method

Listing 10 shows the overridden version of the low-level event handling
method for Window focus events.  Listing 10 also shows sample screen
output for this method.

  //Sample screen output for this method:
  // Low:processWindowFocusEvent A
  // 207 WINDOW_GAINED_FOCUS
  protected void processWindowFocusEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                "Low:processWindowFocusEvent A");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowFocusEvent(e);
  }//end processWindowFocusEvent

Listing 10

The method in Listing 10 is invoked whenever the Window gains or
loses the focus.

Except for the name of the method, Listing 10 is almost identical to Listing
9.

The overridden processWindowStateEvent method

Listing 11 shows the overridden version of the low-level event handling
method for Window state events.

  //Sample screen output for this method:
  // Low:processWindowStateEvent A
  // 209 WINDOW_STATE_CHANGED
  protected void processWindowStateEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                "Low:processWindowStateEvent A");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowStateEvent(e);
  }//end processWindowStateEvent

Listing 11

Once again, the code in Listing 11 is almost identical to the code in Listings
9 and 10.  Therefore, I won’t discuss it further.

The getEventType method

Listing 12 shows the method that is called in Listings 9, 10, and
11 to convert numeric event type identifications to Strings that
describe the event type.

  String getEventType(int ID){
    if(ID == WindowEvent.WINDOW_ACTIVATED){
      return "WINDOW_ACTIVATED";
    }else if(ID == WindowEvent.WINDOW_CLOSED){
      return "WINDOW_CLOSED";
    }else if(ID == WindowEvent.WINDOW_CLOSING){
      return "WINDOW_CLOSING";
    }else if(ID ==
                 WindowEvent.WINDOW_DEACTIVATED){
      return "WINDOW_DEACTIVATED";
    }else if(ID ==
                 WindowEvent.WINDOW_DEICONIFIED){
      return "WINDOW_DEICONIFIED";
    }else if(ID == WindowEvent.WINDOW_ICONIFIED){
      return "WINDOW_ICONIFIED";
    }else if(ID == WindowEvent.WINDOW_OPENED){
      return "WINDOW_OPENED";
    }else if(ID ==
               WindowEvent.WINDOW_STATE_CHANGED){
      return "WINDOW_STATE_CHANGED";
    }else if(ID ==
                WindowEvent.WINDOW_GAINED_FOCUS){
      return "WINDOW_GAINED_FOCUS";
    }else if(ID ==
                  WindowEvent.WINDOW_LOST_FOCUS){
      return "WINDOW_LOST_FOCUS";
    }else{
      return "Unknown event type";
    }//end else
  }//end getEventType

}//end class FocusWindow02

Listing 12

The getEventType method is straightforward and shouldn’t require further
discussion.

End of FocusWindow02 class

Listing 12 also signals the end of the class definition for the class named
FocusWindow02.

The FocusLstnr class

Listing 13 defines a class that implements the FocusListener
interface.  Objects of this class are registered on the two JButton
objects in Figure 1 to report high-level focusGained and focusLost
events.

Listing 13 also provides some sample screen output produced by the
event-handler methods defined in the class.

//Sample outputs from these methods:
// High:focusGained on Regain focus button
// High:focusLost on Regain focus button
// High:focusGained on Send focus to B button
// High:focusLost on Send focus to B button
class FocusLstnr implements FocusListener{

  public void focusGained(FocusEvent e){
    System.out.println("High:focusGained on "
             + ((JButton)e.getSource()).getText()
             + " button");
  }//wns focusGained
  //-------------------------------------------//

  public void focusLost(FocusEvent e){
    System.out.println("High:focusLost on "
             + ((JButton)e.getSource()).getText()
             + " button");
  }//end focusLost
}//end class FocusLstnr

Listing 13

The code in Listing 13 represents plain old-fashioned event handling using
registered FocusListener objects, so I won’t discuss it further.

The WindowLstnr class

Listing 14 shows the beginning of a class that implements both the WindowFocusListener interface and the
WindowStateListener interface.

Objects of this class are registered on the two JFrame objects in
Figures 1 and 2 to handle high-level Window focus and Window state events.

Listing 14 also shows some sample screen output produced by the methods
defined in this class.

//Sample outputs from the methods are:
// High:windowGainedFocus A
// High:windowLostFocus A
// High:windowGainedFocus B
// High:windowLostFocus B
// High:windowStateChanged NORMAL to ICONIFIED B
// High:windowStateChanged NORMAL to ICONIFIED A
// High:windowStateChanged ICONIFIED to NORMAL A
// High:windowStateChanged ICONIFIED to NORMAL B

class WindowLstnr implements
         WindowFocusListener,WindowStateListener{

Listing 14

The interface methods

By implementing the two interfaces shown in Listing 14, the WindowLstnr
class must define the following interface methods:

  • windowGainedFocus(WindowEvent e)
  • windowLostFocus(WindowEvent e)
  • windowStateChanged(WindowEvent e)

The first two of these methods are shown in Listing 15 and shouldn’t require
any discussion.

  public void windowGainedFocus(WindowEvent e){
    System.out.print("High:windowGainedFocus ");
    System.out.println(((JFrame)e.getSource()).
                      getTitle().substring(0,1));
  }//end windowGainedFocus

  public void windowLostFocus(WindowEvent e){
    System.out.print("High:windowLostFocus ");
    System.out.println(((JFrame)e.getSource()).
                      getTitle().substring(0,1));
  }//windowLostFocus

Listing 15

The windowStateChanged method

The windowStateChanged method is shown in Listing 16.  Although it isn’t
complicated, it does contain some new material.

  public void windowStateChanged(WindowEvent e){
    System.out.println("High:windowStateChanged "
             + getState(e.getOldState())
             + " to " + getState(e.getNewState())
             + " "
             + ((JFrame)e.getSource()).
                      getTitle().substring(0,1));
  }//windowStateChanged

Listing 16

This method is invoked whenever the Window on which the listener
object is registered changes state.  The possible states are:

  • NORMAL
  • ICONIFIED
  • MAXIMIZED_HORIZ
  • MAXIMIZED_VERT
  • MAXIMIZED_BOTH

Get and display the old and new states

Whenever the method is invoked, the getOldState and getNewState
methods are invoked on the reference to the KeyEvent object to get the numeric
values representing the old and new states respectively.

The documentation describes those numeric values as bit masks, so I
expected them to have values of 0, 1, 2, 4, and 8.  To my surprise, after
much searching through the Sun documentation, I learned that the numeric values
are 0, 1, 2, 4, and 6 instead.

The method named getState

In any event, I really didn’t need to know the actual numeric values for the
five states (I was just curious).

Having access to the corresponding constants in the Frame class, it was
a simple matter to write the method named getState, shown in Listing 17. 
This method converts from numeric state values to Strings more suitable for screen
display.

  String getState(int state){
    if(state == Frame.NORMAL){
      return "NORMAL";
    }else if(state == Frame.ICONIFIED){
      return "ICONIFIED";
    }else if(state == Frame.MAXIMIZED_HORIZ){
      return "MAXIMIZED_HORIZ";
    }else if(state == Frame.MAXIMIZED_VERT){
      return "MAXIMIZED_VERT";
    }else if(state == Frame.MAXIMIZED_BOTH){
      return "MAXIMIZED_BOTH";
    }else{
      return "Unknown state";
    }//end else
  }//end getState
}//end class WindowLstnr

Listing 17

End of the WindowLstnr class

Listing 17 also signals the end of the code for the class named WindowLstnr.

The GraphicsGUI class

That brings us to the class from which the JFrame object shown in
Figure 2 is instantiated.

An object of this class is instantiated to illustrate the use of focus on a
Window that contains no focusable components. 

Responding to the keyboard

The coordinates of an invisible point are displayed on a Canvas in the
JFrame near the location of the invisible point.  When this object has the focus, pressing the arrow keys
changes the coordinates of the invisible point, thus modifying and moving the displayed coordinate values.

The coordinate values are modified in a high-level KeyEvent handler
registered on the JFrame object.  The fact that the JFrame
object responds to the arrow keys and fires key events confirms that the JFrame does, in fact, have the focus.

The coordinate variables

The class definition for the GraphicsGUI class begins in Listing 18.

class GraphicsGUI extends JFrame{

  int xCoor = 200;
  int yCoor = 40;

Listing 18

The code in Listing 18 declares and initializes two instance variables that
hold the coordinates of the invisible point in pixels. 

We will see later
that pressing one of the horizontal arrow keys either adds five pixels to or subtracts five pixels
from the variable named xCoor.  Similarly, pressing one of the
vertical arrow keys either adds five pixels to or subtracts five pixels from the
variable named yCoor.

The constructor for the GraphicsGUI class

The constructor begins in Listing 19. 

  public GraphicsGUI(){//constructor
    setBounds(0,100,400,100);
    setTitle("B Copyright 2004 R.G.Baldwin");
    Display display = new Display();
    getContentPane().add(display);

    setDefaultCloseOperation(
                           JFrame.EXIT_ON_CLOSE);

Listing 19

The most interesting thing about the code in Listing 19 is the instantiation
of the new object of the class named Display.  As we will see, this
is a Canvas object.  We will draw coordinate values on it later
in a KeyListener object.

Prepare to handle various types of events

The remaining constructor code is shown in Listing 20.

    enableEvents(AWTEvent.WINDOW_EVENT_MASK);

    this.addKeyListener(new KeyListnr(display));

    addWindowFocusListener(new WindowLstnr());
    addWindowStateListener(new WindowLstnr());

    setVisible(true);
  }//end constructor

Listing 20

The code in Listing 20 prepares for the handling of:

  • Low-level WindowEvents, by invoking the enableEvents
    methods and passing WINDOW_EVENT_MASK as a parameter.
  • High-level KeyEvents, by registering a listener object of type KeyListnr.  This is the listener object that will draw coordinate
    values on the Canvas.
  • High-level Window focus events, by registering a WindowListener object of type
    WindowLstnr(A listener
    object of this same type was also registered on the other JFrame object shown in Figure
    1.)
  • High-level Window state events, by registering a WindowListener object of the same
    WindowLstnr type as above.

Make the object visible on the screen

Listing 20 also causes the object in Figure 2 to become visible on the
screen.  This causes it to momentarily become the active Window and
to gain the focus.

(Recall that it loses that status as the active window with the focus
shortly thereafter when the object in Figure 1 becomes visible.)

Listing 20 also signals the end of the constructor.

Low-level event handlers

The first three methods shown in Listing 21 are low-level event handlers
designed to process ordinary WindowEvents, WindowFocusEvents,
and WindowStatusEvents.  The fourth method in Listing 21 is used
by the other three to convert numeric event type values to strings for display.

  //Sample screen output for this method:
  // Low:processWindowEvent B
  // 205 WINDOW_ACTIVATED
  protected void processWindowEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                     "Low:processWindowEvent B");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowEvent(e);
  }//end processWindowEvent
  //-------------------------------------------//

  //Sample screen output for this method:
  // Low:processWindowFocusEvent B
  // 207 WINDOW_GAINED_FOCUS
  protected void processWindowFocusEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                "Low:processWindowFocusEvent B");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowFocusEvent(e);
  }//end processWindowFocusEvent
  //-------------------------------------------//

  //Sample screen output for this method:
  // Low:processWindowStateEvent B
  // 209 WINDOW_STATE_CHANGED
  protected void processWindowStateEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                "Low:processWindowStateEvent B");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowStateEvent(e);
  }//end processWindowStateEvent
  //-------------------------------------------//

  String getEventType(int ID){
    if(ID == WindowEvent.WINDOW_ACTIVATED){
      return "WINDOW_ACTIVATED";
    }else if(ID == WindowEvent.WINDOW_CLOSED){
      return "WINDOW_CLOSED";
    }else if(ID == WindowEvent.WINDOW_CLOSING){
      return "WINDOW_CLOSING";
    }else if(ID ==
                 WindowEvent.WINDOW_DEACTIVATED){
      return "WINDOW_DEACTIVATED";
    }else if(ID ==
                 WindowEvent.WINDOW_DEICONIFIED){
      return "WINDOW_DEICONIFIED";
    }else if(ID == WindowEvent.WINDOW_ICONIFIED){
      return "WINDOW_ICONIFIED";
    }else if(ID == WindowEvent.WINDOW_OPENED){
      return "WINDOW_OPENED";
    }else if(ID ==
               WindowEvent.WINDOW_STATE_CHANGED){
      return "WINDOW_STATE_CHANGED";
    }else if(ID ==
                WindowEvent.WINDOW_GAINED_FOCUS){
      return "WINDOW_GAINED_FOCUS";
    }else if(ID ==
                  WindowEvent.WINDOW_LOST_FOCUS){
      return "WINDOW_LOST_FOCUS";
    }else{
      return "Unknown event type";
    }//end else
  }//end getEventType

Listing 21

The methods in Listing 21 are identical to methods having the same names defined
and discussed earlier for the class named FocusWindow02, except that the screen output identifies the object as B rather than A.

The Display class

Listing 22 defines an inner class.  An object of this class is the Canvas upon which the
coordinate values are drawn.  (Note that the class extends Canvas.)

class Display extends Canvas{

  Display(){//constructor
    setFocusable(false);
  }//end constructor

  public void paint(Graphics g){
    super.paint(g);
    g.drawString(
        "" + xCoor + ", " + yCoor, xCoor, yCoor);
  }//end paint()
}//end class Display

Listing 22

Set focusable property to false

The constructor sets the focusable property of the object
to false.  This was done to guarantee that the Window to which it
belongs (see Figure 2) contains no focusable components.

(The central premise of this lesson is that a Window
can gain the focus, and can respond to the keyboard while it has the focus,
even if that Window contains no focusable components.)

The overridden paint method

Then Listing 22 overrides the inherited paint method. 
The behavior of the overridden paint method is to draw the values stored
in xCoor and yCoor on the Canvas whenever the operating system
causes the method to be invoked.

This code causes the coordinate values to be drawn at the
location specified by the coordinate values.  Thus, as the values change,
the location at which they are drawn changes accordingly.

(The coordinates are drawn to the right of and slightly
above the point described by the coordinates.)

Repainting the screen

The operating system will cause the paint method to be
invoked whenever there is a requirement to repaint that portion of the screen
occupied by the object in Figure 2. 

There are many circumstances that make it necessary for the
operating system to repaint that portion of the screen.  For example, if
the user iconifies and then restores the JFrame in Figure 2, it must be
repainted.

Another such requirement will occur when
the high-level KeyEvent handler invokes the repaint method later.

The KeyListnr class

Now we finally come to the class that supports the central
premise of this lesson.  Recall that the central premise is that a Window can gain the focus, and can respond to the keyboard while it has the
focus, even if that Window contains no focusable components.

The best way to prove that a Window is responding to the
keyboard is to show that it fires KeyEvents when keys are pressed on the
keyboard.

The class definition

Listing 23 shows the beginning of the high-level listener class
named KeyListnr.  An object of this class is registered on the Window in Listing 20,
(which is the object shown in Figure 2).

class KeyListnr extends KeyAdapter{
  Display display;

  KeyListnr(Display display){//constructor
    this.display = display;//save ref to display
  }//end constructor

Listing 23

This class extends the KeyAdapter interface and overrides
the method named keyPressed.

Three KeyEvent types

When the user presses and then releases a key on the keyboard while
the object in Figure 2 has the focus, that object will fire the following three
KeyEvents:

  • keyPressed
  • keyReleased
  • keyTyped

The second and third methods in the above list will return
immediately doing nothing.  I will discuss the behavior of the overridden
keyPressed method shortly.

The constructor

The constructor shown in Listing 23 will
receive and save a reference to the Display object discussed in Listing
22.  This reference will be needed so that the keyPressed method can
invoke the repaint method on the Display object later when the
user presses a key.

The overridden keyPressed method

Now we have reached the very heart of the program.  The
overridden keyPressed method is shown in Listing 24.

  public void keyPressed(KeyEvent e){
    int code = e.getKeyCode();

    if(code == e.VK_UP){
      yCoor -= 5;
    }else if(code == e.VK_LEFT){
      xCoor -= 5;
    }else if(code == e.VK_RIGHT){
      xCoor += 5;
    }else if(code == e.VK_DOWN){
      yCoor += 5;
    }//end else if

    display.repaint();//Display coordinates
  }//end keyPressed()
}//end class KeyListnr

}//end GraphicsGUI class

Listing 24

The overridden keyPressed method will be invoked whenever
the user presses a key on the keyboard while the object in Figure 2 has the
focus.

Identify the key that was pressed

Listing 24 invokes the getKeyCode method on the incoming
reference of type KeyEvent to get the unique value that represents the
specific key that was pressed.

Then the overridden method uses four of the constants defined in
the KeyEvent class to determine if the user pressed one of the four arrow
keys.  If not, no changes are made to the stored coordinate values.

If an arrow key was pressed …

If one of the arrow keys was pressed, the code in Listing 24
either adds five pixels or subtracts five pixels from one of the two variables
defined in Listing 18.  The decision as to which variable to modify, and the
decision as to whether to add or subtract depends on which arrow key was
pressed.

If the right arrow key was pressed, the value of xCoor is
increased by five pixels.  If the left arrow key was pressed, the value of
xCoor is decreased by five pixels.

Vertical axis is upside down

Recall that when drawing on the screen using Java, the positive
vertical axis points down the screen, which is upside down relative to what we
are normally accustomed to seeing.  The code in Listing 24 compensates for
this.

If the key that was pressed was the up arrow key, the value of
yCoor is decreased by five pixels.  If the down arrow key was
pressed, the value of xCoor is increased by five pixels.

Repaint the screen

Then the code in Listing 24 invokes the repaint method on
the Canvas object that occupies the client area of the JFrame
shown in Figure 2.

The result of pressing an arrow key is to cause one of the
coordinate values shown in Figure 2 to increase or decrease by a value of five. 
The location at which the new coordinate values are drawn in Figure
2 will move by five pixels to the right, the left, up, or down.

The premise is demonstrated

The fact that this happens when the user presses an arrow key
demonstrates that a Window containing no focusable components can gain
the focus and will respond to the keyboard while it has the focus.

End of class and end of program

Listing 24 also signals the end of the inner class named KeyListnr and the end of the outer class named
GraphicsGUI.

Listing 24 also signals the end of the program.

The Window state

One aspect of the program that I haven’t discussed in detail has
to do with the change in state of the Window objects shown in
Figures 1 and 2.

The class named WindowLstnr, the definition of which began in
Listing 14, implements the WindowStateListener interface.  As a
result, it defines the WindowStateChanged method as shown in Listing 16.

Register the WindowStateListener
object

An object of the WindowLstnr class is registered on both
of the JFrame objects shown in Figures 1 and 2.  Whenever the
user iconifies or maximizes either JFrame object, the listener object
will be notified and the method in Listing 16 will be invoked to handle the WindowEvent received as a parameter.

Consider some typical scenarios

Assume that the user presses the button in Figure 1 labeled
Send focus to B.  This will cause the object in Figure 2 to become the
active window and to gain the focus.

Assume then that the user presses the iconify button on the
object in figure 2.

(That is the small button in the upper right corner with
the underscore character on its face.)

The state of the Window changes

That will cause the state of that Window to change from
NORMAL to ICONIFIED.  The method in Listing 16 will be invoked as a result
of the event, and will produce the third, fourth, and fifth lines of output text
highlighted in boldface in Figure 5.

Low:processWindowEvent B
203 WINDOW_ICONIFIED

Low:processWindowStateEvent B
209 WINDOW_STATE_CHANGED
High:windowStateChanged NORMAL to ICONIFIED B

Low:processWindowFocusEvent B
208 WINDOW_LOST_FOCUS
High:windowLostFocus B

Low:processWindowEvent B
206 WINDOW_DEACTIVATED

Low:processWindowEvent A
205 WINDOW_ACTIVATED

Low:processWindowFocusEvent A
207 WINDOW_GAINED_FOCUS
High:windowGainedFocus A
High:focusGained on Send focus to B button

Figure 5

What about the other lines of
output text?

The first two lines of output in Figure 5 will be produced by
the low-level processWindowEvent method shown in Listing 21.

The five lines of output text following the boldface text
in Figure 5 are produced by various event handler methods as a result of the Window in Figure 2 losing focus and becoming deactivated.

(An iconified Window cannot be the active window
and cannot hold the focus.)

The final six lines of text in Figure 5 are produced by various
event handlers as a result of:

  • The Window in Figure 1 regaining the status of being
    the active Window

  • The Window in Figure 1 regaining the focus

  • The button in Figure 1 labeled Send focus to b
    regaining the focus (focus is restored to the component that had the
    focus when the Window in Figure 1 lost the focus).

Now restore the Window

If the user then restores the Window in Figure 1 to the
screen, the windowStateChanged method in Listing 16 will be invoked to
produce the screen output shown in Figure 6.

Low:processWindowStateEvent B
209 WINDOW_STATE_CHANGED
High:windowStateChanged ICONIFIED to NORMAL B

Figure 6

(Note that the screen output text shown in Figures 6, 7,
and 8 will be surrounded by other text on the screen produced by various
other event handlers as these events occur.)

Maximize the Window

If the user clicks the maximize button on the Window in
Figure 2, the windowStateChanged method in Listing 16 will be invoked to
produce the screen output shown in Figure 7.

Low:processWindowStateEvent B
209 WINDOW_STATE_CHANGED
High:windowStateChanged NORMAL to MAXIMIZED_BOTH B

Figure 7

The program can respond to this event to become aware of the
fact that the user has maximized the Window.  Although I’m not
absolutely certain, I don’t believe that this information was available to the
program prior to the release of V1.4.

Restore the Window

While the Window is maximized, the center button in the
group of three buttons in the upper right corner of Figure 2 will have a
different appearance.  In the maximized state, that button becomes a restore button.  If the user clicks the
restore button, the windowStateChanged method in Listing 16 will be invoked to produce the
screen output shown in Figure 8.

Low:processWindowStateEvent B
209 WINDOW_STATE_CHANGED
High:windowStateChanged MAXIMIZED_BOTH to NORMAL B

Figure 8

The program can respond to this event to become aware that the
Window has been restored to its NORMAL state.

Run the Program

I encourage you to copy, compile, and run the program provided in this lesson. 
Experiment with it, making changes and observing the results of your changes.

One very useful modification to the program for experimental purposes is to
add the following statement in the various event-handler methods:

System.out.println(new Date());

This statement causes the time to be displayed along with the other
information related to an event.  This makes it easier to interpret the
various lines of output on the screen by making it possible to determine which
groups of lines were produced in rapid succession.

Also consider modifying the program to use Frame, Dialog, and
JDialog objects instead of JFrame objects.  Consider
eliminating the requirement for a Canvas object, causing your Window
to contain no components at all, focusable or otherwise.

Summary

I explained and demonstrated that a Window can gain the
focus and respond to the keyboard while it has the focus, even if that Window contains no focusable components. 

I illustrated both low-level and high-level event handlers to
respond to Window focus events.

I showed how to make use of the extended Window state and
showed how the program can respond to Window state events to learn
that the user has maximized a Window.

What’s Next?

Future lessons will discuss additional focus features including the
following:

  • Temporary focus events
  • Focus and PropertyChangeListener
  • Focus and VetoableChangeListener

Complete Program Listing

A complete listing of the program discussed in this lesson is provided below.

/*File FocusWindow02.java
Copyright 2004 R.G.Baldwin
Rev 07/30/04
This program illustrates the ability of a Window
to gain and lose the focus, and to fire events
when the focus is gained or lost.  This
capability is new to SDK V1.4.

The program also illustrates the ability of a
JFrame to fire events when the state of the
JFrame changes.  This capability is also new to
SDK V1.4.  A list of the possible states is
provided later in this discussion.

The program places two JFrame objects on the
screen, one above the other.  The JFrame object
on the top contains two JButton objects, both
of which are focusable.

The JFrame object on the bottom contains a single
Canvas object, which is not focusable.  Therefore
the JFrame object on the bottom contains no
focusable components.

The JFrame object on the bottom illustrates the
use of focus on a Window that contains no
focusable components.  The coordinates of an
invisible point are displayed on the Canvas near
the location of the invisible point.  When this
object has the focus, pressing the arrow keys
will change the coordinates of the invisible
point, thus modifying and moving the displayed
coordinate values.  This is accomplished by
servicing KeyEvents on the object, thus
demonstrating that the JFrame object actually
has the focus.

The JFrame object on the top contains two
JButton objects labeled respectively:

Regain focus
Send focus to B

Clicking the first of these two buttons will
cause the JFrame object on the top to gain the
focus, will cause the JFrame object on the bottom
to lose the focus, and will also cause the
JButton object to gain the focus.

Clicking the button labeled "Send focus to B"
will momentarily cause the JFrame object and the
button to gain the focus, but will immediately
transfer the focus to the JFrame object on the
bottom.

The JFrame objet on the bottom will also gain the
focus if it is clicked with the mouse.

As each JFrame object gains and loses focus,
information about the gain and loss of focus is
displayed on the screen, using both high-level
event handling and low-level event handling.

The high-level approach makes use of an object
of type FocusListener.

The low-level approach makes use of the following
methods:

enableEvents(AWTEvent.WINDOW_EVENT_MASK)
processWindowEvent(WindowEvent e)
processWindowFocusEvent(WindowEvent e)
processWindowStateEvent(WindowEvent e)

The program also uses low-level event handling to
display information about other WindowEvent types
such as the following.  Note that this list
includes focus and state events, which are new
to SDK V1.4.

WINDOW_ACTIVATED
WINDOW_CLOSED
WINDOW_CLOSING
WINDOW_DEACTIVATED
WINDOW_DEICONIFIED
WINDOW_ICONIFIED
WINDOW_OPENED
WINDOW_STATE_CHANGED
WINDOW_GAINED_FOCUS
WINDOW_LOST_FOCUS

Note that there is no WindowEvent type that is
fired when a JFrame is maximized.  However, a
windowStateChanged event is fired when a JFrame
is maximized.  Information about the state of
the window is encapsulated in the WindowEvent
object and can be extracted using the following
methods:

getOldState
getNewState

The fact that the JFrame has been maximized can
be extracted from the state of the window.  The
following states are defined:

NORMAL
ICONIFIED
MAXIMIZED_HORIZ
MAXIMIZED_VERT
MAXIMIZED_BOTH

This state information is defined as values of
type int, corresponding to the descriptive
constants in the above list.  These constants are
defined in the Frame class.

The actual value associated with each constant in
the above list (and many other constants as well)
can be determined by looking the constant up in
the API documentation and selecting the hyperlink
named Constant Field Values.

Although this program uses Swing components and
draws the coordinate values on a Canvas object,
it is a trivial matter to modify the program
to use only AWT components, and to eliminate the
Canvas object.  In that case, the coordinate
values are drawn directly on the Frame.  Since
the Frame doesn't contain any components at all,
it is absolutely guaranteed that it doesn't
contain any focusable components.

It is also easy to convert the program to one
that uses JDialog objects in place of JFrame
objects.  Of course, JDialog objects can't be
minimized or maximized, so that portion of the
program having to do with the Window State has
no meaning with respect to JDialog objects.

Tested using JDK J2SE 5.0 under WinXP
************************************************/

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

public class FocusWindow02 extends JFrame{

  public static void main(String[] args){
    //Instantiate an object of this class, which
    // will, in turn, instantiate an object of
    // the class named GraphicsGUI.
    FocusWindow02 winA = new FocusWindow02();
  }//end main
//---------------------------------------------//
  public FocusWindow02(){//constructor

    //Instantiate a GraphicsGUI object, The
    // GraphicsGUI object will be identified as B
    // in the screen display.
    final GraphicsGUI winB = new GraphicsGUI();

    //Now construct the object of this class,
    // prepare it to handle events, and make it
    // visible.  This object will be identified
    // as A in the screen display.
    // Begin by setting some properties.
    setTitle("A Copyright 2004, R.G.Baldwin");
    getContentPane().setLayout(new FlowLayout());
    setSize(400,100);
    setDefaultCloseOperation(
                           JFrame.EXIT_ON_CLOSE);

    //Instantiate two buttons, prepare them to
    // handle FocusEvents, and add them to the
    // JFrame.
    JButton regainButton = new JButton(
                                 "Regain focus");
    regainButton.addFocusListener(
                               new FocusLstnr());
    getContentPane().add(regainButton);

    JButton sendButton = new JButton(
                              "Send focus to B");
    sendButton.addFocusListener(
                               new FocusLstnr());
    getContentPane().add(sendButton);

    //Prepare one of the buttons to handle
    // ActionEvents using an anonymous inner
    // class.
    sendButton.addActionListener(
      new ActionListener(){
        public void actionPerformed(
                                  ActionEvent e){
          winB.requestFocus();
        }//end actionPerformed
      }//end new ActionListener
    );//end addActionListener

    //Prepare the JFrame to handle events using
    // the low-level process methods.
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);

    //Prepare the JFrame to handle events using
    // the high-level listener methods.
    addWindowFocusListener(new WindowLstnr());
    addWindowStateListener(new WindowLstnr());

    //Make this JFrame visible.  This will steal
    // the focus from the other JFrame.
    setVisible(true);

  }//end constructor
  //-------------------------------------------//

  //The next three methods are low-level event
  // handler methods that are new to V1.4.  These
  // methods are identical to methods having the
  // same names defined for the class named
  // GraphicsGUI, except that the screen output
  // identifies the object as A rather than B.

  //Sample screen output for this method:
  // Low:processWindowEvent A
  // 205 WINDOW_ACTIVATED
  protected void processWindowEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                     "Low:processWindowEvent A");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowEvent(e);
  }//end processWindowEvent
  //-------------------------------------------//

  //Sample screen output for this method:
  // Low:processWindowFocusEvent A
  // 207 WINDOW_GAINED_FOCUS
  protected void processWindowFocusEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                "Low:processWindowFocusEvent A");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowFocusEvent(e);
  }//end processWindowFocusEvent
  //-------------------------------------------//

  //Sample screen output for this method:
  // Low:processWindowStateEvent A
  // 209 WINDOW_STATE_CHANGED
  protected void processWindowStateEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                "Low:processWindowStateEvent A");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowStateEvent(e);
  }//end processWindowStateEvent
  //-------------------------------------------//

  //Method to convert event ID values to text
  // descriptions.
  String getEventType(int ID){
    if(ID == WindowEvent.WINDOW_ACTIVATED){
      return "WINDOW_ACTIVATED";
    }else if(ID == WindowEvent.WINDOW_CLOSED){
      return "WINDOW_CLOSED";
    }else if(ID == WindowEvent.WINDOW_CLOSING){
      return "WINDOW_CLOSING";
    }else if(ID ==
                 WindowEvent.WINDOW_DEACTIVATED){
      return "WINDOW_DEACTIVATED";
    }else if(ID ==
                 WindowEvent.WINDOW_DEICONIFIED){
      return "WINDOW_DEICONIFIED";
    }else if(ID == WindowEvent.WINDOW_ICONIFIED){
      return "WINDOW_ICONIFIED";
    }else if(ID == WindowEvent.WINDOW_OPENED){
      return "WINDOW_OPENED";
    }else if(ID ==
               WindowEvent.WINDOW_STATE_CHANGED){
      return "WINDOW_STATE_CHANGED";
    }else if(ID ==
                WindowEvent.WINDOW_GAINED_FOCUS){
      return "WINDOW_GAINED_FOCUS";
    }else if(ID ==
                  WindowEvent.WINDOW_LOST_FOCUS){
      return "WINDOW_LOST_FOCUS";
    }else{
      return "Unknown event type";
    }//end else
  }//end getEventType

}//end class FocusWindow02
//=============================================//

//Objects of this class are registered on the two
// JButton objects to report high-level
// focusGained and focusLost events.
//Sample outputs from these methods:
// High:focusGained on Regain focus button
// High:focusLost on Regain focus button
// High:focusGained on Send focus to B button
// High:focusLost on Send focus to B button
class FocusLstnr implements FocusListener{

  public void focusGained(FocusEvent e){
    System.out.println("High:focusGained on "
             + ((JButton)e.getSource()).getText()
             + " button");
  }//wns focusGained
  //-------------------------------------------//

  public void focusLost(FocusEvent e){
    System.out.println("High:focusLost on "
             + ((JButton)e.getSource()).getText()
             + " button");
  }//end focusLost
}//end class FocusLstnr

//=============================================//

//Objects of this class are registered on the two
// JFrame objects to report high-level focus and
// state events on the objects.

//Sample outputs from the methods are:
// High:windowGainedFocus A
// High:windowLostFocus A
// High:windowGainedFocus B
// High:windowLostFocus B
// High:windowStateChanged NORMAL to ICONIFIED B
// High:windowStateChanged NORMAL to ICONIFIED A
// High:windowStateChanged ICONIFIED to NORMAL A
// High:windowStateChanged ICONIFIED to NORMAL B

class WindowLstnr implements
         WindowFocusListener,WindowStateListener{
  public void windowGainedFocus(WindowEvent e){
    System.out.print("High:windowGainedFocus ");
    System.out.println(((JFrame)e.getSource()).
                      getTitle().substring(0,1));
  }//end windowGainedFocus

  public void windowLostFocus(WindowEvent e){
    System.out.print("High:windowLostFocus ");
    System.out.println(((JFrame)e.getSource()).
                      getTitle().substring(0,1));
  }//windowLostFocus

  public void windowStateChanged(WindowEvent e){
    System.out.println("High:windowStateChanged "
             + getState(e.getOldState())
             + " to " + getState(e.getNewState())
             + " "
             + ((JFrame)e.getSource()).
                      getTitle().substring(0,1));
  }//windowStateChanged

  //This method converts state values to text
  // descriptions.  See constant values in Frame
  // class for the correlations between state
  // values and descriptive constants.
  String getState(int state){
    if(state == Frame.NORMAL){
      return "NORMAL";
    }else if(state == Frame.ICONIFIED){
      return "ICONIFIED";
    }else if(state == Frame.MAXIMIZED_HORIZ){
      return "MAXIMIZED_HORIZ";
    }else if(state == Frame.MAXIMIZED_VERT){
      return "MAXIMIZED_VERT";
    }else if(state == Frame.MAXIMIZED_BOTH){
      return "MAXIMIZED_BOTH";
    }else{
      return "Unknown state";
    }//end else
  }//end getState
}//end class WindowLstnr
//=============================================//

//An object of this class is instantiated to
// illustrate the use of focus on a Window that
// contains no focusable components.  The
// coordinates of an invisible point are
// displayed on a Canvas in the JFrame near the
// location of the invisible point.  When this
// object has the focus, pressing the arrow keys
// will change the coordinates of the invisible
// point, thus modifying and moving the displayed
// coordinate values.

class GraphicsGUI extends JFrame{

  //These are the coordinates of the invisible
  // point.
  int xCoor = 200;
  int yCoor = 40;

  public GraphicsGUI(){//constructor
    setBounds(0,100,400,100);
    setTitle("B Copyright 2004 R.G.Baldwin");
    Display display = new Display();
    getContentPane().add(display);

    setDefaultCloseOperation(
                           JFrame.EXIT_ON_CLOSE);

    //Prepare this object to handle low-level
    // WindowEvents using the process methods.
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);

    //Prepare this object to handle high-level
    // KeyEvents using a listener.
    this.addKeyListener(new KeyListnr(display));

    //Prepare this object to handle high-level
    // focus and state events using a listener.
    addWindowFocusListener(new WindowLstnr());
    addWindowStateListener(new WindowLstnr());

    setVisible(true);
  }//end constructor
  //-------------------------------------------//

  //The next three methods are low-level event
  // handler methods that are new to V1.4.  These
  // methods are identical to methods having the
  // same names defined for the class named
  // FocusWindow02, except that the screen output
  // identifies the object as B rather than A.

  //Sample screen output for this method:
  // Low:processWindowEvent B
  // 205 WINDOW_ACTIVATED
  protected void processWindowEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                     "Low:processWindowEvent B");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowEvent(e);
  }//end processWindowEvent
  //-------------------------------------------//

  //Sample screen output for this method:
  // Low:processWindowFocusEvent B
  // 207 WINDOW_GAINED_FOCUS
  protected void processWindowFocusEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                "Low:processWindowFocusEvent B");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowFocusEvent(e);
  }//end processWindowFocusEvent
  //-------------------------------------------//

  //Sample screen output for this method:
  // Low:processWindowStateEvent B
  // 209 WINDOW_STATE_CHANGED
  protected void processWindowStateEvent(
                                  WindowEvent e){
    System.out.println();
    System.out.println(
                "Low:processWindowStateEvent B");
    System.out.print(e.getID() + " ");
    System.out.println(getEventType(e.getID()));
    super.processWindowStateEvent(e);
  }//end processWindowStateEvent
  //-------------------------------------------//

  //Method to convert event ID values to text
  // descriptions.
  String getEventType(int ID){
    if(ID == WindowEvent.WINDOW_ACTIVATED){
      return "WINDOW_ACTIVATED";
    }else if(ID == WindowEvent.WINDOW_CLOSED){
      return "WINDOW_CLOSED";
    }else if(ID == WindowEvent.WINDOW_CLOSING){
      return "WINDOW_CLOSING";
    }else if(ID ==
                 WindowEvent.WINDOW_DEACTIVATED){
      return "WINDOW_DEACTIVATED";
    }else if(ID ==
                 WindowEvent.WINDOW_DEICONIFIED){
      return "WINDOW_DEICONIFIED";
    }else if(ID == WindowEvent.WINDOW_ICONIFIED){
      return "WINDOW_ICONIFIED";
    }else if(ID == WindowEvent.WINDOW_OPENED){
      return "WINDOW_OPENED";
    }else if(ID ==
               WindowEvent.WINDOW_STATE_CHANGED){
      return "WINDOW_STATE_CHANGED";
    }else if(ID ==
                WindowEvent.WINDOW_GAINED_FOCUS){
      return "WINDOW_GAINED_FOCUS";
    }else if(ID ==
                  WindowEvent.WINDOW_LOST_FOCUS){
      return "WINDOW_LOST_FOCUS";
    }else{
      return "Unknown event type";
    }//end else
  }//end getEventType
//=============================================//

//Begin inner class definitions

class Display extends Canvas{

  Display(){//constructor
    //Set the focusable property to false to
    // guarantee that the JFrame contains no
    // focusable components.
    setFocusable(false);
  }//end constructor

  //Override the paint method to display the
  // coordinates on the screen near the location
  // specified by the coordinates.
  public void paint(Graphics g){
    super.paint(g);
    g.drawString(
        "" + xCoor + ", " + yCoor, xCoor, yCoor);
  }//end paint()
}//end class Display
//=============================================//

//This listener class monitors for key events,
// increments and displays the stored coordinates
// when the arrow keys are pressed.
class KeyListnr extends KeyAdapter{
  Display display;

  KeyListnr(Display display){//constructor
    this.display = display;//save ref to display
  }//end constructor
  //-------------------------------------------//

  //Override the keyPressed method to increment
  // or decrement the coordinates by five pixels
  // when an arrow key is pressed.  Then repaint
  // the canvas to cause the coordinate values to
  // be displayed. Remember y-coordinates are
  // displayed upside down.
  public void keyPressed(KeyEvent e){
    int code = e.getKeyCode();

    if(code == e.VK_UP){
      yCoor -= 5;
    }else if(code == e.VK_LEFT){
      xCoor -= 5;
    }else if(code == e.VK_RIGHT){
      xCoor += 5;
    }else if(code == e.VK_DOWN){
      yCoor += 5;
    }//end else if

    display.repaint();//Display coordinates
  }//end keyPressed()
}//end class KeyListnr
//=============================================//
}//end GraphicsGUI class
//=============================================//

Listing 25


Copyright 2005, Richard G. Baldwin.  Reproduction in whole or in
part in any form or medium without express written permission from Richard
Baldwin is prohibited.

About the author

Richard Baldwin
is a college professor (at Austin Community College in Austin, TX) and
private consultant whose primary focus is a combination of Java, C#, and
XML. In addition to the many platform and/or language independent benefits
of Java and C# applications, he believes that a combination of Java, C#,
and XML will become the primary driving force in the delivery of structured
information on the Web.

Richard has participated in numerous consulting projects, and he frequently
provides onsite training at the high-tech companies located in and around
Austin, Texas.  He is the author of Baldwin’s Programming
Tutorials,
which has gained a worldwide following among experienced and aspiring programmers.
He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of
practical experience in Digital Signal Processing (DSP).  His first
job after he earned his Bachelor’s degree was doing DSP in the Seismic Research
Department of Texas Instruments.  (TI is still a world leader in DSP.) 
In the following years, he applied his programming and DSP expertise to other
interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and
has many years of experience in the application of computer technology
to real-world problems.

[email protected]

-end-

Latest Posts

Related Stories