Technical Article
The New Modality API in Java SE 6
By Artem Ananiev and Dana Nourie, January 2006
A dialog box is a top-level pop-up window with a title and a border that is typically used to take some form of input from the user. With JDK 5.0 and earlier, a dialog box must have either a frame or another dialog box defined as its owner when the dialog box is constructed, even if the box is invisible. When the user minimizes the owner window of a visible dialog box, this automatically hides the dialog box from the user. When the user subsequently restores the owner window, the dialog box becomes visible again.
A dialog box can be either modeless or modal. A modal dialog box is one that blocks input to some other top-level windows in the application, except for any windows created with the dialog box as their owner. The modal dialog box captures the window focus until it is closed, usually in response to a button press. A modeless dialog box, on the other hand, sits off on the side and allows you to change its state while other windows have focus. The latter is often used for a toolbar window, such as what you might find in an image-editing program.
This was the limit of the modality model in JDK 5.0 and earlier. However, this modality model was not without its problems. Perhaps the most famous issue involved JavaHelp tool windows. JavaHelp, an API to display help information from a Java application, uses a separate window to display all the necessary information. However, if an application shows any modal dialog box, such as a standard Save As dialog, the dialog box blocks the user from interacting with the JavaHelp tool window.
But Java Platform, Standard Edition (Java SE, formerly known as J2SE) version 6, has resolved this issue and several others with a new Abstract Window Toolkit (AWT) modality model. This new model allows the developer to scope, or limit, a dialog box's modality blocking, based on the modality type that the developer chooses. By doing so, the modality type also allows windows and dialog boxes to be truly parentless, that is, to have a null parent, which helps to limit the scope of the windows' and dialog boxes' modality.
Modality Types
Java SE 6 technology supports four modality types:
- Modeless. A modeless dialog box does not block any other window while it is visible.
- Document-modal. A document-modal dialog box blocks all windows from the same document, except those from its child hierarchy. In this context, a document is a hierarchy of windows -- frames, dialog boxes, and so on -- that share a common ancestor, the document root, which is the closest ancestor window without an owner.
- Application-modal. An application-modal dialog box blocks all windows from the same application, except for those from its child hierarchy. If several applets are launched in a browser environment, the browser is allowed to treat them either as separate applications or as a single application. The behavior is implementation-dependent.
- Toolkit-modal. A toolkit-modal dialog box blocks all windows that run in the same toolkit, except those from its child hierarchy. If several applets are launched, all of them run with the same toolkit. Hence, a toolkit-modal dialog box shown from an applet may affect other applets and all windows of the browser instance that embeds the Java runtime environment for this toolkit.
As with previous JDKs, a dialog box is modeless by default. But if you construct a modal dialog box in Java SE 6, it will now use the application-modal type by default. In addition, the behavior of both modal and modeless dialog boxes has been changed so that they always appear on top of their parent window.
Modality priority is defined by the strength of blocking. The modality priority helps in situations in which two dialog boxes are visible and could block each other. The priority in ascending order from weakest to strongest is modeless, document-modal, application-modal, and toolkit-modal. Such a priority naturally reflects the nesting of a dialog box's scope of blocking. A modeless dialog box has an empty scope of blocking. A document-modal dialog box's scope of blocking is complete in some applications. And all the applications are run in one toolkit.
Note that the new modality model does not implement a system modality, which would block all applications (Java or otherwise) that are displayed on the desktop while a modal dialog is active.
Learning the New Constructors
Adding the ability to offer truly parentless windows without breaking backward compatibility was a challenge for the AWT team. In version JDK 5.0 or earlier, you were allowed to pass null
as a parent for JDialog
or JWindow
, but that automatically meant that an invisible, shared-owner frame became a parent of this dialog box or window. The shared-owner frame was invented to give the illusion of creating parentless dialog boxes. This was fine until Java SE 6, which introduced new document-modal dialog boxes that block all the windows from the same document.
Consequently, the toolkit saw such dialog boxes or windows as not having a null parent. In Java SE 6, you are still allowed to pass null
as a parent to the older JDialog
or JWindow
constructors. And this accomplishes the same thing: The shared-owner frame again becomes the parent, in order to preserve backward compatibility. However, you can now pass null
to the Dialog
or Window
constructors as well as to the new JDialog
or JWindow
constructors, which means that the dialog boxes really will be parentless.
Some of the available constructors are as follows:
JDialog(Dialog owner)
Creates a modeless dialog without a title with the specified
Dialog
as its ownerJDialog(Dialog owner, boolean modal)
Creates a dialog box with the specified owner
Dialog
and modalityJDialog(Dialog owner, String title)
Creates a modeless dialog box with the specified title and with the specified owner dialog box
JDialog(Dialog owner, String title, boolean modal)
Creates a dialog box with the specified title, modality, and owner
Dialog
JDialog(Dialog owner, String title, boolean modal, GraphicsConfiguration gc)
Creates a dialog box with the specified title, owner
Dialog
, modality andGraphicsConfiguration
JDialog(Frame owner)
Creates a modeless dialog box without a title with the specified
Frame
as its ownerJDialog(Window owner, String title, Dialog.ModalityType modalityType)
Creates a dialog box with the specified title, owner
Window
, and modality
See the documentation for more constructors and details about each one.
Working With Owners
As we mentioned earlier, when a window or a dialog box is another's parent, that parent component is said to "own" its child. Here are a few things that you should be aware of when working with owners in the new modality model:
- Creating a document-modal dialog box without an owner. In this case, because
Dialog
is a subclass ofWindow
, aDialog
instance automatically becomes the root of the document if it has no owner. Thus, if such a dialog box is document-modal, its scope of blocking is empty, and it behaves the same way as would a modeless dialog box. - Creating an application-modal or toolkit-modal dialog box with an owner. The scope of blocking for an application-modal or toolkit-modal dialog box, as opposed to the scope of blocking for a document-modal dialog box, doesn't depend on its owner. In this case, the only thing that the owner affects is the Z-order, the relative order of top-level components. If you have two windows, one overlaps the other, with the first one above or on top of the second. The topmost window is usually an active window. A related notion is that of always on top, in which one window always appears above all other windows in the system. The dialog box always stays on top of its owner.
- Changing the modality type at runtime. Changing the modality type for a visible dialog box may have no effect until the dialog box is hidden and then shown again.
The following code example demonstrates the new modality API, including java.awt.Dialog.ModalExclusionType
and java.awt.Dialog.ModalityType
for the flexibility now available to dialog box windows. Figure 1 shows the end result when you run this code.
import java.awt.*;
import java.awt.event.*;
import sun.awt.*;
public class ModalityDemo2 {
// First document (red): frame, modeless dialog box,
// document-modal dialog box
private static Frame f1;
private static Dialog d11;
private static Dialog d12;
// Second document (blue): frame, modeless dialog box,
// document-modal dialog box
private static Frame f2;
private static Dialog d21;
private static Dialog d22;
// Third document (green): modal excluded frame
private static Frame f3;
// Fourth document (grey): frame, file dialog box
// application-modal dialog box
private static Frame f4;
private static FileDialog fd4;
private static WindowListener closeWindow = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
e.getWindow().dispose();
}
};
public static void main(String[] args) {
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
int sw = gc.getBounds().width - 64;
int sh = gc.getBounds().height - 64;
Label l;
Button b;
MenuBar mb;
Menu m;
MenuItem mi;
Font labelFont = new Font("Tahoma", 24, Font.PLAIN);
// First document
f1 = new Frame("Parent Frame");
f1.setBounds(32, 32, 300, 200);
f1.addWindowListener(closeWindow);
mb = new MenuBar();
m = new Menu("Test");
mi = new MenuItem("Show modeless");
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
d11.setVisible(true);
}
});
m.add(mi);
mb.add(m);
f1.setMenuBar(mb);
f1.setLayout(new BorderLayout());
l = new Label("FRAME");
l.setAlignment(Label.CENTER);
l.setFont(labelFont);
l.setBackground(Color.RED);
f1.add(l, BorderLayout.CENTER);
f1.setVisible(true);
d11 = new Dialog(f1, "Modeless Dialog");
// An old constructor. Because the flag "modal" is
// missed, the dialog box is modeless.
d11.setBounds(132, 132, 300, 200);
d11.addWindowListener(closeWindow);
d11.setLayout(new BorderLayout());
l = new Label("MODELESS");
l.setAlignment(Label.CENTER);
l.setFont(labelFont);
l.setBackground(Color.RED);
d11.add(l, BorderLayout.CENTER);
b = new Button("Show document-modal");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
d12.setVisible(true);
}
});
d11.add(b, BorderLayout.SOUTH);
d12 = new Dialog((Window)d11, "Document-modal Dialog",
Dialog.ModalityType.DOCUMENT_MODAL);
// New constructor with parameter for its modality type
// Parameter type is enum Dialog.ModalityType.
d12.setBounds(232, 232, 300, 200);
d12.addWindowListener(closeWindow);
d12.setLayout(new BorderLayout());
l = new Label("DOCUMENT_MODAL");
l.setAlignment(Label.CENTER);
l.setFont(labelFont);
l.setBackground(Color.RED);
d12.add(l, BorderLayout.CENTER);
// Second document
f2 = new Frame("Parent Frame");
f2.setBounds(sw - 300 + 32, 32, 300, 200);
f2.addWindowListener(closeWindow);
mb = new MenuBar();
m = new Menu("Test");
mi = new MenuItem("Show modeless");
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
d21.setVisible(true);
}
});
m.add(mi);
mb.add(m);
f2.setMenuBar(mb);
f2.setLayout(new BorderLayout());
l = new Label("FRAME");
l.setBackground(Color.BLUE);
l.setAlignment(Label.CENTER);
l.setFont(labelFont);
f2.add(l, BorderLayout.CENTER);
f2.setVisible(true);
d21 = new Dialog(f2, "Modeless Dialog");
d21.setBounds(sw - 400 + 32, 132, 300, 200);
d21.addWindowListener(closeWindow);
d21.setLayout(new BorderLayout());
l = new Label("MODELESS");
l.setBackground(Color.BLUE);
l.setAlignment(Label.CENTER);
l.setFont(labelFont);
d21.add(l, BorderLayout.CENTER);
b = new Button("Show document-modal");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
d22.setVisible(true);
}
});
d21.add(b, BorderLayout.SOUTH);
d22 = new Dialog((Window)d21, "Document-modal Dialog",
Dialog.ModalityType.DOCUMENT_MODAL);
Figure 1: Blocked and Unblocked Dialog Boxes
A dialog box that uses DOCUMENT_MODAL
blocks input to all top-level windows from the same document, except those from its own child hierarchy. A document is a top-level window without an owner. It may contain child windows that are treated as a single document together with the top-level window. Because every top-level window must belong to some document, its root can be found at the top-nearest window without an owner.
d22.setBounds(sw - 500 + 32, 232, 300, 200);
d22.addWindowListener(closeWindow);
d22.setLayout(new BorderLayout());
l = new Label("DOCUMENT_MODAL");
l.setBackground(Color.BLUE);
l.setAlignment(Label.CENTER);
l.setFont(labelFont);
d22.add(l, BorderLayout.CENTER);
// Third document
f3 = new Frame("Excluded Frame");
f3.setModalExclusionType(
Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
A dialog box set to APPLICATION_MODAL
blocks all top-level windows from the same Java application, except those from its own child hierarchy. If several applets are launched in a browser, they can be treated either as separate applications or as a single one. This behavior is implementation-dependent.
Note that here, f3
will not be blocked by APPLICATION_MODAL
and DOCUMENT_MODAL
dialog boxes.
f3.setBounds(32, sh - 200 + 32, 300, 200);
f3.addWindowListener(closeWindow);
f3.setLayout(new BorderLayout());
l = new Label("EXCLUDED FRAME");
l.setBackground(Color.GREEN);
l.setAlignment(Label.CENTER);
l.setFont(labelFont);
f3.add(l, BorderLayout.CENTER);
b = new Button("I'm alive!");
f3.add(b, BorderLayout.SOUTH);
f3.setVisible(true);
// Fourth document
f4 = new Frame("Parent Frame");
f4.setBounds(sw - 300 + 32, sh - 200 + 32, 300, 200);
f4.addWindowListener(closeWindow);
f4.setLayout(new BorderLayout());
l = new Label("FRAME");
l.setBackground(Color.GRAY);
l.setAlignment(Label.CENTER);
l.setFont(labelFont);
b = new Button("Show file dialog");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fd4.setVisible(true);
}
});
f4.add(b, BorderLayout.SOUTH);
f4.setVisible(true);
fd4 = new FileDialog(f4, "File Dialog", FileDialog.LOAD);
File dialog boxes are APPLICATION_MODAL
by default for backward compatibility.
fd4.setBounds(sw - 400 + 32, sh - 300 + 32, 300, 200);
}
}
Related AWT Features
Here are a few other AWT features to be aware of when using the new modality model.
Always on Top
When a modal dialog box that is not always on top blocks an always-on-top window, their relative Z-order is unspecified and platform-dependent. The following example demonstrates this issue:
JFrame f = new JFrame(...);
f.setAlwaysOnTop(true);
f.setVisible(true);
JDialog d = new JDialog(frame, "Dialog", true);
d.setVisible(true);
This code creates a contradiction: On one hand, d
must be on top of f
(because it is a modal dialog and should block f
). On the other hand, f
must be on top of d
because f
is set to be always on top, whereas d
is not. Such cases are unspecified. However, there is a way around this: If d
is set to be always on top as well (d.setAlwaysOnTop(true))
, then the dialog box will be on top of the frame at all times.
The toFront()
and toBack()
Methods
A modal dialog box should always be above all its blocked windows. Thus, if a blocked window is brought to the front, its blocking dialog box, if any, is also brought to the front and remains above the blocked window. Likewise, if a modal dialog box is sent to the back, all of its blocked windows are sent to the back to keep them underneath the blocking dialog box.
Minimizing, Maximizing, and Closing Blocked Windows
When a modal dialog box blocks a window, the user may not be able to minimize or maximize the blocked window. However, the actual behavior is unspecified and platform-dependent. In any case, the user can't close the blocked window interactively. But it can be closed programmatically by calling the setVisible(false)
or dispose()
methods on the blocked window.
Activating Blocked Windows
When the user selects a blocked window, it may be brought to the front, along with the blocking modal dialog box, which then becomes the active window. However, the actual behavior is unspecified and platform-dependent.
Hiding a Modal Dialog Box
When the modal dialog box that currently has focus is hidden, its owner, if unblocked, may become the active window. However, the actual behavior is unspecified and platform-dependent. If the modal dialog box to be hidden does not have focus, the active window remains unchanged.
Security
A special AWTPermission
, toolkitModality
, is required in order to show toolkit-modal dialog boxes. This would prevent, for example, modal dialog boxes shown from applets from blocking a browser or Java Web Start (JWS) software.
The same permission is required to exclude a window from toolkit modality. This would prevent, for example, a dialog box shown from an applet from being blocked by a browser's or JWS modal dialog box.
Platform Support
Two java.awt.Toolkit
methods allow you to check whether the current platform supports specific modality features:
isModalityTypeSupported(modalityType)
returns whether the specified modality type is supported on the current platform. If modeM
is not supported and a dialog box is set toM
-modal, it behaves as modeless.isModalExclusionTypeSupported(modalExclusionType)
returns whether the given modal exclusion type is supported on the current platform. If exclusion typeE
is not supported and a window is marked asE
-excluded, this has no effect.
Compatibility
The default modality type is application-modal. It is used by the API calls Dialog.setModal(true)
, Dialog(owner, true)
, and so on. Prior to JDK 6, the default type was toolkit-modal, but the only distinction between application modality and toolkit modality is for applets and applications launched from JWS software.
Note: Any API additions or other enhancements to the Java SE platform specification are subject to review and approval by the JSR 270 Expert Group.
About the Authors
Artem Ananiev is a Sun Microsystems software engineer in Saint Petersburg, Russia. He has been working in AWT for a couple of years, with his primary functional areas in modality, robot, and multiscreen systems. He also likes basketball and ping-pong.
Dana Nourie is a staff writer for JSC.