The Source for Java Technology Collaboration
User: Password:



   

The JModalWindow Project The JModalWindow Project

by Jene Jasper
09/07/2004


Contents
Parent and Child Windows
The InputBlocker Interface
Visualization and Blocking
Construction of ModalWindows
Activation and Blocking of the Parent Window
Deactivation and Unblocking of Parent Window
Blocked by Child Window
Behavior when Blocked
Unblocked by Child Window
Window Drag Support
Decorated Window Border
Support Utility
Latest Developments and Ideas
Conclusion and Credits

There are times when you want a modal window that implements window-specific modality rather than the application-wide modality provided by the standard JDialog class. This article explains the workings of the JModalWindow project, which provides two top-level components, called ModalWindows, that introduce such modality. The first ModalWindow class, JModalWindow, is a subclass of JWindow that's generally used for dialogs that block other windows. The second, JModalFrame, is a subclass of JFrame that can be used either as a blocked window or as a blocking window. Both classes implement an interface named InputBlocker.

Why create a ModalWindow instead of using the standard JDialog component? We were working on a pension-planner application to give users insight into their financial situations before and after retirement. This was done with the aid of a financial graphic. Throughout the application, help information for various pension-specific terms was available in a separate help window. In order to make comparisons, the user should be able to change different variables that influence pension savings. While doing this, the underlying financial graphic had to be blocked. A JDialog could have been used, but then the necessary help window would have also been blocked, and thus useless. Furthermore, the title bar presented by JDialog didn't fit in with the rest of the look and feel of the application.

I searched the Internet for a possible solution for our problem and found several suggestions, but they all had drawbacks or loopholes. That is why I decided to create my own modal window implementation based on the ideas that came closest to our needs. The JModalWindow project is an open source version of our solution to this challenge and is part of the JavaDesktop community at java.net.

Parent and Child Windows

It helps to have a common language when referring to the various windows involved. The window to be blocked is known as the parent window or owner; another term for blocked is busy. The window blocking the parent is the child window. A parent window can have more than one child window blocking it. Each child can block its parent and, in recently added functionality, some additional windows. Ideally, the parent window and the child window should both be ModalWindows; at the very least, they should both implement the InputBlocker interface.

An example will clarify these concepts. Here is a snapshot of a GUI produced by a JModalWindow that is modal with respect to a JModalFrame:

Figure 1
Figure 1. A snapshot of a GUI produced by a JModalWindow that is modal with respect to a JModalFrame.

As the preceding figure shows, a JModalFrame's busy status is marked using a blur effect and stop cursor. You can customize the following aspects of the display:

  • Stop cursor: By default, this is a stop sign, but you can specify a custom cursor.
  • Busy effect: The built-in effects are raster or line.
  • Initial position of dialog: The dialog can be initially centered onscreen, centered over a window, relative to a component, or at a specific X,Y location.

The following figure shows the same GUI as the preceding one, but with a line busy effect, custom stop cursor, and initial Y position relative to the bottom of the Update button that brought up the dialog. The X position of the dialog depends on the JModalWindow release. The dialog is be positioned at the same X position as the button, as long as the dialog stays onscreen; otherwise it will be moved to the left to keepWindowCompletelyOnScreen.

Figure 2
Figure 2. The same GUI as the preceding one, but with a line busy effect, custom stop cursor, and initial Y position relative to the bottom of the Update button that brought up the dialog.

The following code creates a dialog that is modal relative to the window (owner) containing returnFocusComponent and that is optionally placed relative to returnFocusComponent. The dialog has a single button, which closes the dialog.

private JModalWindow createStatusWindow(
        Component returnFocusComponent,
        boolean relative,
        String text) {
    Window owner = SwingUtilities.windowForComponent(returnFocusComponent);
    final JModalWindow jmw = new JModalWindow(owner, returnFocusComponent);
    jmw.getContentPane().setBackground(bg);
    jmw.getContentPane().setForeground(fg);
    jmw.getContentPane().setLayout(new GridBagLayout());

    JButton jbClose = createJButton("Cancel");
    jbClose.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
         jmw.dispose();
      }
    });

    BorderLayout bl = new BorderLayout();
    jmw.getContentPane().setLayout(bl);

    jmw.getContentPane().add(createLabel(text), BorderLayout.CENTER);
    jmw.getContentPane().add(jbClose, BorderLayout.SOUTH);

    jmw.setSize(300, 75);

    if (relative) {
        jmw.relativeToOwnerChild(returnFocusComponent);
    } else {
        jmw.centerOfOwner();
//      jmw.centerOfScreen();  //another positioning possibility
    }

    return jmw;
}

For the best results, the owner should be a ModalWindow. In the preceding code, the JModalWindow constructor sets up the dialog, and the relativeToOwnerChild method causes the dialog to be positioned just under the returnFocusComponent's onscreen representation.

The InputBlocker Interface

Both JModalFrame and JModalWindow implement an interface called InputBlocker. The interface defines the following two methods:

  • public boolean isBusy();
  • public void setBusy(boolean busy, Window blockingWindow);

With those methods, it is possible to check whether a window is currently blocked and let any child window signal that it is blocking or unblocking its parent.

Note: The draft version of this article was written based on the sources of version 1.02. But since then I have added some new functionality that is detailed in the section Latest Developments and Ideas. One of those new functionalities led to a third method definition in the InputBlocker interface:

  • public void addAdditionalModalToWindow(Window window);

With this method, it is possible to add additional windows that should be blocked at the same time as the parent window. This is the reason why in the next paragraphs the variable modalToWindows is plural instead of modalToWindow, which you would expect because a child window only has one parent window.

The isBusy and setBusy methods are useful for the parent window; the addAdditionalModalToWindow method is useful for the child window.

Visualization and Blocking

To block all keyboard and mouse action for the underlying window, a JBusyPanel object can be used as a GlassPane for the blocked window. The JBusyPanel, when activated, consumes all keyboard strokes for the underlying window and grabs the focus for any mouse action on it.

To make it obvious that the window is blocked, you can apply one of two types of blurring:

BLUR_STYLE_LINE
Blurring with horizontal lines. A bit of a legacy style, because the first raster implementation (drawing the separate dots) was too slow on older computers.
BLUR_STYLE_RASTER
Blurring with diagonal, parallel lines from top left to bottom right, which leads to a raster effect.

The desired blur style, gap, and color are applied by the paint method of the JBusyPanel. When blocked, the ModalWindow also changes the shape of the cursor (see getBusyCursor).

To block the FocusManager in JavaTM 1.3, JBusyPanel overrides the deprecated method isManagingFocus.

Construction of ModalWindows

The constructors for JModalWindow and JModalFrame accept the following parameters, as needed:

Window owner
To set the parent window for the newly constructed window.
Component returnFocus
To set the component that should get the focus when this window is closed.
String title (JModalFrame only)
To set a title for the frame.
boolean modal
To change the default modal setting for the window.

Each ModalWindow constructor performs the following actions:

  1. The appropriate super is called to set the title for the JFrame and the owner for the JWindow. (Note: If no owner is specified, the Swing SharedOwnerFrame is used.)

  2. The optional returnFocus is stored.

  3. The list modalToWindows is set to contain the supplied owner when this Window is constructed as being modal. Because the parent isn't blocked yet, the status variable notifiedModalToWindow is set to true.

  4. The list with blockingWindows is initialized. This Vector is used to make it possible to have multiple modal child windows.

  5. The JBusyPanel that will block this window is initialized with the following settings:

    • A color that is a bit darker than the default white background color.
    • A fixed BLUR_STEP of 2.
    • A BLUR_STYLE of the type raster.

    These settings were chosen because that combination looks best, in my humble opinion. However, if performance is an issue, these values can be changed in your own copy of the source code.

  6. Finally, the WINDOW_EVENT_MASK is used to activate the processing of WindowEvents.

Each JModalWindow also performs the following initialization:

  • Creates a raised border to indicate that the window can be dragged.

  • Activates MOUSE_MOTION_EVENT_MASK for the processing of MouseEvents, to support dragging of the window.

Each JModalFrame performs the following additional initialization:

  • Sets up a MinimumFrameSizeAdapter to keep the frame from being resized smaller than minWidth by minHeight when those values are supplied through the method setMinSize.

  • Checks whether a default icon, for which the resource location can be filed under the key swingx.frame.icon in the UIManager, is available. If this is the case, the support utility is used to fetch it.

Pages: 1, 2

Next Page » 

View all java.net Articles.

 Feed java.net RSS Feeds