July 31, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Window Focus and State in Java, Part 2

  • May 17, 2005
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

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.

Baldwin@DickBaldwin.com

-end-






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel