Original source:
docs.oracle.com/javase/tutorial/reallybigindex.html
Working with the Focus Subsystem
Original source:
docs.oracle.com/javase/tutorial/uiswing/misc/focus.html
Most Swing components—including those primarily operated with the mouse like buttons—can be controlled via keyboard input. For keystrokes to affect a component, that component must possess keyboard focus.
From a user's perspective, the component with keyboard focus is usually visually distinguished—for example, with a dashed or solid border. The window containing that component also appears more prominent than other windows on screen. These visual cues inform the user wich component will receive typed input. Only one component across the entire windowing system can have keyboard focus at any given time.
How a window acquires focus varies depending on the underlying windowing system. No absolute method guarantees focus acquisition across all platforms. On Microsoft Windows, bringing a window to the foreground typically grants it focus—in these cases, the Window.toFront() method moves the window forward and consequently assigns focus. However, on operating systems like Solaris, the window manager might select the focused window based on cursor position, leading to different behavior when calling toFront().
Components typically gain focus when users click them, tab between them, or otherwise interact with them. Components can also receive focus programmatically, such as when their containing frame or dialog becomes visible. The following pattern demonstrates how to consistently direct focus to a specific component whenever the window gains focus:
frame.addWindowFocusListener(new WindowAdapter() {
public void windowGainedFocus(WindowEvent e) {
textField.requestFocusInWindow();
}
});
To guarantee that a particular component receives focus when the window first activates, call requestFocusInWindow() on that component after implementing it but before displaying the frame. The following illustrates this approach:
*//...During component initialization...*
JFrame frame = new JFrame("Test");
JPanel panel = new JPanel(new BorderLayout());
*//...Instantiate various components...*
//Component that should receive initial focus
JButton button = new JButton("I am first");
panel.add(button);
frame.getContentPane().add(panel);
frame.pack();
//Grant initial focus to this button
button.requestFocusInWindow();
frame.setVisible(true);
Alternatively, you can apply a custom FocusTraversalPolicy to the frame and invoke the getDefaultComponent() method to determine which component receives focus.
Focus Subsystem Overview
The focus subsystem performs correct operations as unobtrusively as possible. In most scenarios, it behaves reasonably; when it doesn't, you can adjust its behavior in various ways. Common scenarios include:
- Sorting is correct, but focus isn't set on the first component. As shown in the previous code snippet, you can use
requestFocusInWindow()to set focus on a component when the window becomes visible. - Sorting is incorrect. Solutions include modifying the containment hierarchy, changing the order in which components are added to their container, or creating a custom focus traversal policy.
- A component must prevent losing focus, or check a value before focus changes. Input validation addresses this requirement.
- A custom component doesn't receive focus. Ensure it meets all requirements outlined in making custom components focusable.
The FocusConceptsDemo example demonstrates these concepts.
Try this:
-
Click the Launch button to run FocusConceptsDemo using Java Web Start. Alternatively, compile and run the example yourself.
-
Click the window to give it focus if needed.
-
Navigate between components using the Tab key.
Notice how focus stays within the text area when it gains focus.
-
Press Control-Tab to move focus out of the text area.
-
Press Shift-Tab to navigate in the opposite direction.
-
Press Control-Shift-Tab to exit the text area in the opposite direction.
KeyboardFocusManager serves as the central element of the focus subsystem, managing state and initiating changes. The keyboard manager tracks the focus owner—the component receiving keyboard input. The focus window contains the focus owner.
JWindow and Focus: When using JWindow in a GUI, the owning frame of the JWindow must be visible for any components within the window to receive focus. By default, if you don't specify an owning frame for a JWindow, the system creates an invisible owning frame. Consequently, components inside the JWindow may be unable to gain focus. Solutions include specifying a visible owning frame when creating the JWindow or using an undecorated JFrame instead.
A focus cycle (or focus traversal cycle) is a group of components sharing a common ancestor in the containment hierarchy. A focus cycle root is the root container of a particular focus traversal cycle. By default, each JWindow and JInternalFrame can serve as a focus cycle root. A focus cycle root may itself contain one or more focus cycle roots. The following Swing objects can be focus cycle roots: JApplet, JDesktopPane, JDialog, JEditorPane, JFrame, JInternalFrame, and JWindow. Although JTable and JTree objects might appear to be focus cycle roots, they are not.
A focus traversal policy determines the order in which a group of components is navigated. Swing provides the LayoutFocusTraversalPolicy class, which determines navigation order based on layout manager-related factors such as component size, position, and orientation. Within a focus cycle, components can be navigated forward or backward. When traversing upward through the hierarchy of focus cycle roots, focus moves from the current cycle to its parent cycle.
In most look and feel implementations, navigation between components uses Tab and Shift-Tab. These keys serve as the default focus traversal keys and can be modified programmatically. For instance, you can add Enter as a forward focus traversal key with these four lines:
Set forwardKeys = getFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
Set newForwardKeys = new HashSet(forwardKeys);
newForwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
newForwardKeys);
Tab moves focus forward; Shift-Tab moves focus backward. For example, in FocusConceptsDemo, the first button has initial focus. Tabbing moves focus to the button within the text area. Additional tabs move the cursor within the text area but don't exit because within the text area, Tab is not a focus traversal key. However, Control-Tab exits the text area into the first text field. Similarly, Control-Shift-Tab exits the text area into the previous component. By convention, the Control key is used to exit any component that treats Tab specially, such as JTable.
Input Validation
A common GUI design requirement involves restricting user input—for example, allowing only numeric input in decimal format (like currency) or restricting a postal code field to exactly five digits. A well-designed formatted text field component allows input constraints for various localized formats. You can also specify a custom formatter for text fields, which can perform special validation such as determining that values are not only correctly formatted but also sensible.
You can use input validators as an alternative to custom formatters, or when you have a component that isn't a text field. Input validators allow you to reject specific values—like correctly formatted but invalid postal codes—or values outside the required range, such as a body temperature above 110°F. To use an input validator, create a subclass of InputVerifier, instantiate it, and assign that instance as the input verifier for one or more components.
A component's input verifier is queried when the component is about to lose focus. If the component's value is unacceptable, the input verifier can take appropriate action, such as refusing to transfer focus to the component or replacing the user's input with the last valid value, then allowing focus to transfer to the next component. However, InputVerifier is not invoked when focus transfers to another top-level component.
The following two examples demonstrate mortgage calculators. One uses formatted text fields; the other uses standard text fields with input validation.
Try this:
- Click the Launch button to run FormattedTextFieldDemo. Alternatively, compile and run the example yourself.
- Click the Launch button to run InputVerificationDemo.
- Place the two mortgage calculators side by side. The input validation demo specifies valid input values for each editable text field's associated label. Try entering incorrectly formatted values in both examples to observe behavior. Then enter correctly formatted but unacceptable values.
You can find the input validation demo code in InputVerificationDemo.java. The following shows the InputVerifier subclass code for MyVerifier:
class MyVerifier extends InputVerifier
implements ActionListener {
double MIN_LOAN = 15000.0;
double MAX_LOAN = 15000000.0;
double MIN_INTEREST = 0.0;
int MIN_YEARS = 1;
int MAX_YEARS = 50;
public boolean shouldYieldFocus(JComponent input) {
boolean validationPassed = verify(input);
formatInput(input);
recalculatePayment();
if (validationPassed) {
return true;
} else {
Toolkit.getDefaultToolkit().beep();
return false;
}
}
protected void recalculatePayment() {
double principal = DEFAULT_PRINCIPAL;
double rate = DEFAULT_RATE;
int years = DEFAULT_YEARS;
double payment = 0.0;
//Parse input values.
try {
principal = currencyFormat.parse(loanField.getText()).
doubleValue();
} catch (ParseException pe) {pe.printStackTrace();}
try {
rate = percentageFormat.parse(rateField.getText()).
doubleValue();
} catch (ParseException pe) {pe.printStackTrace();}
try {
years = integerFormat.parse(yearsField.getText()).
intValue();
} catch (ParseException pe) {pe.printStackTrace();}
//Compute result and update GUI.
payment = computePayment(principal, rate, years);
paymentField.setText(currencyFormat.format(payment));
}
//This method validates input without causing side effects.
public boolean verify(JComponent input) {
return validateField(input, false);
}
protected void formatInput(JComponent input) {
validateField(input, true);
}
protected boolean validateField(JComponent input, boolean applyFix) {
if (input == loanField) {
return validateLoanField(applyFix);
} else if (input == rateField) {
return validateRateField(applyFix);
} else if (input == yearsField) {
return validateYearsField(applyFix);
} else {
return true; //should not occur
}
}
//Validates the loan amount field. Returns true if valid,
//false otherwise. When the applyFix argument is true,
//this method clamps the value to minimum or maximum if needed
//and (even if not) reformats it to look correct.
protected boolean validateLoanField(boolean applyFix) {
boolean wasValid = true;
double principal = DEFAULT_PRINCIPAL;
//Parse the value.
try {
principal = currencyFormat.parse(loanField.getText()).
doubleValue();
} catch (ParseException pe) {
pe.printStackTrace();
wasValid = false;
}
//Value was out of range.
if ((principal < MIN_LOAN) || (principal > MAX_LOAN)) {
wasValid = false;
if (applyFix) {
if (principal < MIN_LOAN) {
principal = MIN_LOAN;
} else {
principal = MAX_LOAN;
}
}
}
//Format value regardless of validity.
if (applyFix) {
loanField.setText(currencyFormat.format(principal));
loanField.selectAll();
}
return wasValid;
}
//Validates the interest rate field.
protected boolean validateRateField(boolean applyFix) {
*...//Similar to validateLoanField...*
}
//Validates the years field.
protected boolean validateYearsField(boolean applyFix) {
*...//Similar to validateLoanField...*
}
public void actionPerformed(ActionEvent e) {
JTextField source = (JTextField)e.getSource();
shouldYieldFocus(source);
source.selectAll();
}
}
Notice that verify() checks for invalid values but performs no other actions. verify() determines only whether input is valid and should not trigger dialogs or cause other side effects. shouldYieldFocus() invokes verify() and, if the value is invalid, clamps it to minimum or maximum. shouldYieldFocus() permits side effects—in this case, always formatting the text field and potentially modifying its value. In our example, shouldYieldFocus() always returns true to ensure focus transfer is never blocked. This is merely one way validation can be implemented. Another version called InputVerificationDialogDemo displays a dialog when users enter invalid values, demanding legal input.
Install an input verifier using the setInputVerifier() method of the JComponent class. For example, InputVerificationDemo has this code:
private MyVerifier validator = new MyVerifier();
...
loanField.setInputVerifier(validator);
Making Custom Components Focusable
For a component to gain focus, three requirements must be met: visible, enabled, and focusable. Input maps can also be provided. For more about input maps, read how to use key bindings.
The TrackFocusDemo example defines a simple Picture component. Its constructor appears as follows:
public Picture(Image image) {
this.image = image;
setFocusable(true);
addMouseListener(this);
addFocusListener(this);
}
Calling setFocusable(true) makes the component focusable. If key bindings are explicitly specified for the component in its WHEN_FOCUSED input map, calling setFocusable() isn't necessary.
To provide visual feedback when focus changes (drawing a red border only when the component has focus), Picture includes a focus listener.
When users click the picture to give it focus, the component has a mouse listener. The listener's mouseClicked() method requests focus transfer to the picture:
public void mouseClicked(MouseEvent e) {
requestFocusInWindow();
}
Custom Focus Traversal
The focus subsystem determines the default order applied when navigating with focus traversal keys like Tab. Swing applications use LayoutFocusTraversalPolicy. You can set a focus traversal policy on any Container using the setFocusCycleRoot() method. However, if the container isn't a focus cycle root, effects may not be obvious. Alternatively, you can pass a focus traversal policy provider instead of a focus cycle root to the FocusTraversalPolicy method. Use isFocusTraversalPolicyProvider() to determine whether a Container is a focus traversal policy provider. Use setFocusTraversalPolicyProvider() to set a container to provide focus traversal policy.
The FocusTraversalDemo example demonstrates customizing focus behavior.
Try this:
- Click the Launch button to run FocusTraversalDemo using Java Web Start.
- Click the window to give it focus if needed.
- Tab through the components and note the focus order. Focus order follows the order components were added to the content pane. Also note that the checkbox never receives focus—we removed it from the focus cycle.
- Use Control-Tab or Control-Shift-Tab to exit the table.
- Click the Custom FocusTraversalPolicy checkbox. This installs a custom focus traversal policy on the frame.
- Tab through the components again. Note that focus order now follows left-to-right, top-to-bottom order.
You can find the demo code in FocusTraversalDemo.java.
This line removes the checkbox from the focus cycle:
togglePolicy.setFocusable(false);
Here's the application's custom FocusTraversalPolicy:
...
JTextField field1 = new JTextField("Field 1");
JTextField field2 = new JTextField("A Bigger Field 2");
JTextField field3 = new JTextField("Field 3");
JTextField field4 = new JTextField("A Bigger Field 4");
JTextField field5 = new JTextField("Field 5");
JTextField field6 = new JTextField("A Bigger Field 6");
JTable grid = new JTable(4,3);
...
public FocusTraversalDemo() {
super(new BorderLayout());
JTextField field1 = new JTextField("Field 1");
JTextField field2 = new JTextField("A Bigger Field 2");
JTextField field3 = new JTextField("Field 3");
JTextField field4 = new JTextField("A Bigger Field 4");
JTextField field5 = new JTextField("Field 5");
JTextField field6 = new JTextField("A Bigger Field 6");
JTable grid = new JTable(4,3);
togglePolicy = new JCheckBox("Custom FocusTraversalPolicy");
togglePolicy.setActionCommand("toggle");
togglePolicy.addActionListener(this);
togglePolicy.setFocusable(false);
label = new JLabel("<html>Use Tab (or Shift-Tab) to navigate from component to component.<p>Control-Tab (or Control-Shift-Tab) allows you to break out of the JTable.</html>");
JPanel leftPanel = new JPanel(new GridLayout(3,2));
leftPanel.add(field1, BorderLayout.PAGE_START);
leftPanel.add(field3, BorderLayout.CENTER);
leftPanel.add(field5, BorderLayout.PAGE_END);
leftPanel.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
JPanel rightPanel = new JPanel(new GridLayout(3,2));
rightPanel.add(field2, BorderLayout.PAGE_START);
rightPanel.add(field4, BorderLayout.CENTER);
rightPanel.add(field6, BorderLayout.PAGE_END);
rightPanel.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
JPanel gridPanel = new JPanel(new GridLayout(0,1));
gridPanel.add(grid, BorderLayout.CENTER);
gridPanel.setBorder(BorderFactory.createEtchedBorder());
JPanel bottomPanel = new JPanel(new GridLayout(2,1));
bottomPanel.add(togglePolicy, BorderLayout.PAGE_START);
bottomPanel.add(label, BorderLayout.PAGE_END);
add(leftPanel, BorderLayout.LINE_START);
add(rightPanel, BorderLayout.CENTER);
add(gridPanel, BorderLayout.LINE_END);
add(bottomPanel, BorderLayout.PAGE_END);
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
Vector<Component> traversalOrder = new Vector<Component>(7);
traversalOrder.add(field1);
traversalOrder.add(field2);
traversalOrder.add(field3);
traversalOrder.add(field4);
traversalOrder.add(field5);
traversalOrder.add(field6);
traversalOrder.add(grid);
newPolicy = new CustomFocusTraversalPolicy(traversalOrder);
}
To use a custom FocusTraversalPolicy, implement this code on any focus cycle root:
CustomFocusTraversalPolicy newPolicy = new CustomFocusTraversalPolicy();
frame.setFocusTraversalPolicy(newPolicy);
You can remove a custom focus traversal policy by setting it to null, which restores the default policy.
Tracking Focus Changes Across Multiple Components
Sometimes an application needs to track which component has focus. This information might dynamically update menus or a status bar. If you only need to track focus on specific components, implementing focus event listeners may be appropriate.
If focus listeners aren't suitable, you can register a PropertyChangeListener on the KeyboardFocusManager. Property change listeners notify you of every focus-related change, including focus owner, focused window, and default focus traversal policy changes. See the KeyboardFocusManager Properties table for the complete list.
The following example demonstrates tracking the focus owner by installing a property change listener on the keyboard focus manager.
Try this:
- Click the Launch button to run TrackFocusDemo.
- Click the window to give it focus if needed.
- The window displays six images, each displayed by a
Picturecomponent. ThePicturewith focus is identified by a red border. The label at the bottom of the window describes whichPicturehas focus. - Move focus to another
Pictureby tabbing or shift-tabbing, or by clicking an image. Because a property change listener is registered on the keyboard focus manager, focus changes are detected and the label updates accordingly.
You can view the demo code in TrackFocusDemo.java. The custom component responsible for drawing images is in Picture.java. Here's the code that defines and installs the property change listener:
KeyboardFocusManager focusManager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (("focusOwner".equals(prop)) &&
((e.getNewValue()) instanceof Picture)) {
Component comp = (Component)e.getNewValue();
String name = comp.getName();
Integer num = new Integer(name);
int index = num.intValue();
if (index < 0 || index > descriptions.length) {
index = 0;
}
info.setText(descriptions[index]);
}
}
}
);
The custom Picture component handles image drawing. All six components are defined like this:
pic1 = new Picture(createImageIcon("images/" +
mayaString + ".gif", mayaString).getImage());
pic1.setName("1");
Timed Focus Transfer
Focus transfer is asynchronous. This characteristic can cause strange timing-related problems and assumptions, particularly during automatic focus transfer. For example, imagine an application with a window containing a "Start" button, a "Cancel" button, and a text field. These components are added in this order:
- Start button
- Text field
- Cancel button
When the application starts, LayoutFocusTraversalPolicy determines the focus traversal policy—in this case, the order components were added to the container. In this example, the expected behavior is for the Start button to have initial focus; when the Start button is clicked, it becomes disabled, and the Cancel button receives focus. The correct way to implement this behavior is to add components to the container in the desired order, or create a custom focus traversal policy. If that's not possible for some reason, you can implement this behavior with the following code:
public void actionPerformed(ActionEvent e) {
start.setEnabled(false);
cancel.requestFocusInWindow();
}
As expected, focus transfers from the Start button to the Cancel button, not the text field. However, calling the same methods in reverse order produces different results:
public void actionPerformed(ActionEvent e) {
cancel.requestFocusInWindow();
start.setEnabled(false);
}
In this case, focus for the Cancel button is requested before the Start button loses it. Calling requestFocusInWindow() initiates focus transfer but doesn't immediately move focus to the Cancel button. When the Start button becomes disabled, focus transfers to the next component (so there's always a focused component), which in this case is the text field, not the Cancel button.
Several situations require issuing focus requests after all other changes that might affect focus:
- Hiding the focus owner.
- Making the focus owner unfocusable.
- Calling
removeNotify()on the focus owner. - Performing any of the above on the focus owner's container, or causing a focus policy change such that the container no longer accepts that component as the focus owner.
- Disposing of the top-level window containing the focus owner.
Focus API
The following tables list constructors and methods related to focus. Focus API is divided into four categories:
- Useful Component Methods
- Creating and Using Custom Focus Traversal Policies
- Input Verification API
- KeyboardFocusManager Properties
Useful Component Methods
Creating and Using Custom Focus Traversal Policies
Input Verification API
KeyboardFocusManager Properties
This table defines the bound properties of KeyboardFocusManager. Register listeners for these properties by calling the addPropertyChangeListener method.
Focus Examples
How to Use Key Bindings
Original source:
docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html
The JComponent class supports key bindings as a way to respond to individual keystrokes from users. Here are some scenarios where key bindings apply:
-
You're creating a custom component and want to support keyboard access.
For example, you might want the component to react when it has focus and the user presses the spacebar.
-
You want to override the behavior of an existing key binding.
For example, if your application normally reacts to F2 in a particular way, you might want it to do something different or ignore the key press.
-
You want to provide a new key binding for an existing action.
For example, you might strongly feel that Control-Shift-Insert should perform a paste operation.
You typically don't need to use key bindings directly. They work behind the scenes for mnemonics (supported by all buttons and tab panes and JLabel) and accelerators (supported by menu items). You can find coverage of mnemonics and accelerators in the enabling keyboard operation section.
An alternative to key bindings is using key listeners. Key listeners have their place as a low-level interface to keyboard input, but for responding to individual keys, key bindings are more appropriate and easier to maintain. Key listeners also become cumbersome when you want the key binding to be active when the component doesn't have focus. Some advantages of key bindings include being somewhat self-documenting, respecting the containment hierarchy, encouraging reusable code blocks (Action objects), and allowing easy removal, customization, or sharing of operations. Additionally, they make it easy to change the key bound to an operation. Another advantage of Action is that it has an enabled state, providing an easy way to disable an operation without tracking which components it's attached to.
How Key Bindings Work
The key binding support provided by JComponent relies on InputMap and ActionMap classes. An input map maps keyboard keys to action names, and an action map specifies the action corresponding to each action name. Technically, you don't need to use action names in the maps; you can use any object as the "key" in the map. However, by convention, you use strings that name the action as the "key."
Each InputMap/ActionMap has a parent that usually comes from the UI. Parents are reset whenever the look and feel changes. This way, any bindings specified by the developer aren't lost when the look and feel changes.
Each JComponent has one action map and three input maps. The input maps correspond to the following focus situations:
JComponent.WHEN_FOCUSED
The component has keyboard focus. WHEN_FOCUSED input maps are typically used when the component has no children. For example, buttons use WHEN_FOCUSED to bind the Space key.
These bindings are active only when the component has focus.
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
The component contains (or is) the component that has focus. This input map is typically used for composite components—ones whose implementation relies on child components. For example, JTable uses WHEN_ANCESTOR_OF_FOCUSED_COMPONENT for all bindings so that if the user is editing, arrow keys (for example) still change the selected cell.
JComponent.WHEN_IN_FOCUSED_WINDOW
The component's window has focus or contains the component that has focus. This input map is typically used for mnemonics or accelerators, which need to be active regardless of where focus is in the window.
When a user presses a key, the JComponent key event handling code searches through one or more input maps for a valid binding for the key. When a binding is found, it looks up the corresponding action in the action map. If the action is enabled, the binding is active and the action is performed. If it's disabled, the search for a valid binding continues.
If a key has multiple bindings, only the first valid binding found is used. Input maps are checked in this order:
- The focused component's
WHEN_FOCUSEDinput map. - The focused component's
WHEN_ANCESTOR_OF_FOCUSED_COMPONENTinput map. - The focused component's parent's
WHEN_ANCESTOR_OF_FOCUSED_COMPONENTinput map, then its parent's parent, and so on, continuing up the containment hierarchy. Note: Input maps of disabled components are skipped. - All enabled
WHEN_IN_FOCUSED_WINDOWinput maps in the focused window are searched. Because the order in which components are searched is unpredictable, avoid duplicateWHEN_IN_FOCUSED_WINDOWbindings!
Let's consider two typical key binding scenarios: a button reacting to Space, and a frame with a default button reacting to Enter.
In the first scenario, assume the user presses Space while a JButton has keyboard focus. First, the button's key listener receives notification of the event. Assuming no key listener consumes the event (by calling the consume method on the KeyEvent), the button's WHEN_FOCUSED input map is consulted. A binding is found because JButton uses that input map to bind Space to an action name. The action name is looked up in the button's action map, and the action's actionPerformed method is called. The KeyEvent is consumed, and processing stops.
In the second scenario, assume Enter is pressed anywhere within a frame with a default button (set using JRootPane's setDefaultButton method). First, whichever component has focus, its key listener is notified. Assuming none of them consumed the key event, the focused component's WHEN_FOCUSED input map is consulted. If it doesn't have a binding for that key, or the action bound to that key is disabled, the focused component's WHEN_ANCESTOR_OF_FOCUSED_COMPONENT input map is consulted, and then (if no binding is found or the action is disabled) the WHEN_ANCESTOR_OF_FOCUSED_COMPONENT input map of each ancestor in the containment hierarchy. Eventually, the root pane's WHEN_ANCESTOR_OF_FOCUSED_COMPONENT input map is consulted. Because that input map has a valid binding for Enter, the action is performed, resulting in the default button being clicked.
How to Create and Remove Key Bindings
Here's an example specifying that a component should react to F2:
component.getInputMap().put(KeyStroke.getKeyStroke("F2"),
"performAction");
component.getActionMap().put("performAction",
anAction);
//where anAction is a javax.swing.Action
As shown in the preceding code, to get a component's action map, you use the getActionMap method (inherited from JComponent). To get an input map, you use the getInputMap(int) method, where the integer is one of the JComponent.WHEN_*FOCUSED* constants shown in the list. Alternatively, when the constant is typically JComponent.WHEN_FOCUSED, you can directly use getInputMap with no arguments.
To add an entry to one of the maps, use the put method. You can use KeyStroke.getKeyStroke(String) to get a KeyStroke object specifying the key. You can find examples of creating Action objects (to put in the action map) in how to use actions.
Here's a slightly more complex example, specifying that a component should react to Space as if the user had clicked the mouse:
component.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),
"buttonPressed");
component.getInputMap().put(KeyStroke.getKeyStroke("released SPACE"),
"buttonReleased");
component.getActionMap().put("buttonPressed",
pressedAction);
component.getActionMap().put("buttonReleased",
releasedAction);
//where pressedAction and releasedAction are javax.swing.Action objects
To make a component ignore a key it would normally react to, you can use the special action name "none". For example, the following code makes the component ignore F2:
component.getInputMap().put(KeyStroke.getKeyStroke("F2"),
"none");
Note:
The preceding code doesn't prevent searching the associated WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and WHEN_IN_FOCUSED_WINDOW input maps for F2 bindings. To prevent this search, use a valid action instead of "none":
Action noOp = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
//do nothing
}
};
component.getInputMap().put(KeyStroke.getKeyStroke("F2"),
"doNothing");
component.getActionMap().put("doNothing",
noOp);
Key Bindings API
The following table lists commonly used key bindings API. Also see the API table for creating and using actions in the how to use actions section.
Creating and Using InputMaps
Creating and Using ActionMaps
Key Bindings Examples
How to Use Modality in Dialogs
Translation source:
docs.oracle.com/javase/tutorial/uiswing/misc/modality.html
Java SE 6 addressed modality problems that existed in earlier versions of the platform. The new modality model allows developers to scope the modal blocking of dialog boxes.
Before continuing with the new modality model, review these terms:
- Dialog — A top-level pop-up window with a title and border, typically gathering some form of input from the user. Dialogs can be modal or non-modal. For more about dialogs, see creating dialogs in the dialog overview page.
- Modal dialog — A dialog that blocks input to other top-level windows in the application, except for windows created with the dialog as their owner. Modal dialogs capture window focus until they are closed, usually in response to a button press.
- Non-modal dialog — A dialog that allows you to operate with other windows while this dialog is displayed.
In Java SE 6, the behavior of modal and non-modal dialogs changed so they always appear on top of all windows they block, not just on top of their parent windows.
Java SE 6 supports the following modality types:
- Non-modal type — Non-modal dialogs block no other windows when visible.
- Document-modal type — Document-modal dialogs block all windows of the same document, except for windows in its child hierarchy. In this context, a document is a window hierarchy that shares a common ancestor called the document root.
- Application-modal type — Application-modal dialogs block all windows of the same application, except for windows in its child hierarchy. If several applets are launched in a browser environment, the browser can treat them as separate applications or as a single application. This behavior is implementation-dependent.
- Toolkit-modal type — Toolkit-modal dialogs block all windows running in the same toolkit, except for windows in its child hierarchy. If several applets are launched, they all use the same toolkit. Therefore, a toolkit-modal dialog shown from an applet might affect all windows of the applet and the browser instance embedding the Java runtime.
Additionally, you can set modality exclusion modes:
- Exclusion mode — Any top-level window can be marked to not be blocked by modal dialogs. This property allows you to set modality exclusion mode. The
Dialog.ModalExclusionTypeenum specifies the possible modality exclusion types.
Note: The new modality model does not implement system modality, which would block all applications displayed on the desktop (including Java applications) when a modal dialog is active.
The ModalityDemo example demonstrates the first three modality types.
This image has been reduced to fit on the page. Click the image to view its natural size.
Try this:
-
Click the Launch button to run ModalityDemo.
-
The following windows appear:
- Book 1 (parent frame)
- Book 2 (parent frame)
- Feedback (parent frame)
- Classics (excluded frame)
-
Switch to the Book 1 frame and select a biography title for that book, then select OK.
-
The biography title appears in the dialog's title. Enter a name in the text field, for example "John".
-
Switch to the Book 1 frame and change the title to Funny Tale, then select OK. Because the name input dialog is non-modal, you can easily switch to its parent frame.
Note: The non-modal dialog title has changed to Funny Tale.
-
Select OK on the non-modal dialog.
-
The document-modal dialog for Funny Tale appears.
-
Enter some text in the text field. Note it is signed with the name you entered in the non-modal dialog.
-
Switch to the non-modal dialog and try to change your name. You cannot because the document-modal dialog blocks all windows in its parent hierarchy.
-
Perform the same sequence of steps (3-9) for the Book 2 parent frame.
-
Try switching to different dialogs. You'll notice you can switch to the Classics frame or the Feedback frame, as well as to the Book 1 or Book 2 frame dialogs.
-
Switch to the Feedback parent frame. Select Rate yourself.
-
A confirmation dialog appears. Try switching to different dialogs. You can only switch to the Classics dialog because the standard confirmation dialog is application-modal, blocking all windows of the same application. However, you'll notice you can select your favorite classical writer in the Classics frame. This frame was created using the
APPLICATION_EXCLUDEmodality exclusion type, which prevents all top-level windows from being blocked by any application-modal dialog.
The following code snippets show how to create dialogs of different modality types:
//The Book 1 parent frame
f1 = new JFrame("Book 1 (parent frame)");
...
//The non-modal dialog box
d2 = new JDialog(f1);
...
//The document-modal dialog box
d3 = new JDialog(d2, "", Dialog.ModalityType.DOCUMENT_MODAL);
...
//The Book2 parent frame
f4 = new JFrame("Book 2 (parent frame)");
...
//The non-modal dialog box
d5 = new JDialog(f4);
...
//The document-modality dialog box
d6 = new JDialog(d5, "", Dialog.ModalityType.DOCUMENT_MODAL);
...
//The excluded frame
f7 = new JFrame("Classics (excluded frame)");
f7.setModalityExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDED);
...
//The Feedback parent frame and Confirm Dialog box
f8 = new JFrame("Feedback (parent frame)");
...
JButton rateButton = new JButton("Rate yourself");
rateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showConfirmationDialog(null,
"I really like my book",
"Question (application-modal dialog)",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
}
});
Find the complete code for the demo in ModalityDemo.java.
In Java SE 6, you can create a document-modal dialog without a parent. Because Dialog is a subclass of Window, a Dialog instance without an owner automatically becomes the root of a document. Therefore, if such a dialog is document-modal, its blocking scope is empty, and it behaves like a non-modal dialog.
Modality API
JDialog constructors enable you to create dialogs of different modality types.
The following table lists methods inherited from the java.awt.Dialog class.
Modality API Examples
How to Print Tables
Original source:
docs.oracle.com/javase/tutorial/uiswing/misc/printtable.html
The JTable class provides printing support. The JTable printing API includes methods that allow you to implement basic and advanced printing tasks. For common printing tasks when you only need to print a table simply, use the print method directly. The print method comes in multiple forms with different parameter sets. This method prepares your table, obtains the appropriate Printable object, and sends it to the printer.
If the default Printable object's implementation doesn't meet your needs, you can customize the print layout by overriding the getPrintable method to wrap the default Printable or replace it entirely.
The simplest way to print a table is to call the print method with no arguments:
try {
boolean complete = table.print();
if (complete) {
/* show a success message */
...
} else {
/*show a message indicating that printing was cancelled */
...
}
} catch (PrinterException pe) {
/* Printing failed, report to the user */
...
}
When you call the print method with no arguments, a print dialog is displayed, then your table is printed interactively in FIT_WIDTH mode with no headers or footers. The following shows the print method signature with the complete parameter set:
boolean complete = table.print(JTable.PrintMode printMode,
MessageFormat headerFormat,
MessageFormat footerFormat,
boolean showPrintDialog,
PrintRequestAttributeSet attr,
boolean interactive,
PrintService service);
When you call the print method with all arguments, you explicitly choose print features such as print mode, header and footer text, print attributes, target print service, whether to show a print dialog, and whether to print interactively or non-interactively. To decide which parameters best suit your needs, see the descriptions of available features below.
The JTable printing API provides the following features:
- Interactive or non-interactive printing
- Showing a print dialog
- Adding headers or footers (or both) to the print layout
- Selecting print mode
- Automatic layout and pagination
Interactive or Non-interactive Printing
In interactive mode, a progress dialog with an abort option is displayed during printing. Here's an example of a progress dialog.
This dialog allows users to track printing progress. The progress dialog is modal, meaning users cannot interact with the table while it's on screen. During printing, it's important that your table remains unchanged; otherwise, print behavior is undefined. However, interactive printing doesn't prevent other developers' code from modifying the table. For example, another thread might post updates using SwingUtilities.invokeLater. Therefore, to ensure correct print behavior, make sure your own code doesn't modify the table during printing.
Alternatively, you can print a table non-interactively. In this mode, printing begins immediately on the event dispatch thread and completely blocks any event processing. On one hand, this mode safely guards the table against any modifications until printing completes. On the other hand, this mode completely deprives users of any interaction with the GUI. That's why non-interactive printing is recommended only when printing from an application with an invisible GUI.
Print Dialog
You can show a standard print dialog that allows users to:
- Select a printer
- Specify the number of copies
- Change print attributes
- Cancel printing before starting
- Begin printing
You might notice that the print dialog doesn't specify the total number of pages in the print output. This is because the table printing implementation uses the Printable API, and the total page count isn't known at print time.
Adding Headers or Footers (or Both) to the Print Layout
Headers and footers are provided via MessageFormat parameters. These parameters allow for localization of headers and footers. Read the documentation for the MessageFormat class because some characters, like single quotes, are special and need escaping. Both header and footer are centered. You can use {0} to insert a page number.
MessageFormat footer = new MessageFormat("- {0} -");
Because the total page count of the output isn't known at print time, you cannot specify a format like "Page 1 of 5".
Print Modes
Print mode handles scaling output and distributing it across pages. You can print a table in one of the following modes:
PrintMode.NORMALPrintMode.FIT_WIDTH
In NORMAL mode, the table prints at its current size. If columns don't fit on a page, they extend across additional pages based on the table's ComponentOrientation. In FIT_WIDTH mode, the table is reduced in size if necessary so that all columns fit on each page. Note that both width and height are proportionally scaled to provide output with the same aspect ratio. In both modes, rows span multiple pages sequentially, with as many rows as possible on each page.
Automatic Layout and Pagination
With the JTable printing API, you don't need to worry about layout and pagination. You only specify appropriate parameters for the print method, such as print mode and footer text format (if you want to insert page numbers in the footer). As shown earlier, you can specify page numbers in the footer by including "{0}" in the string provided to the MessageFormat footer parameter. In the printed output, {0} is replaced with the current page number.
Table Printing Example
Let's examine an example called TablePrintDemo1. The complete code for this program can be found in TablePrintDemo1.java. The rich GUI for this demo was automatically generated by the NetBeans IDE GUI builder. Here's a picture of the TablePrintDemo1 application.
Try this:
- Click the Launch button to run TablePrintDemo1.
- Each checkbox at the bottom of the application window has a tooltip. Hover over the checkboxes to find their purpose.
- Edit text in the Header or Footer checkboxes, or both, to provide different headers or footers.
- Uncheck the Header or Footer checkbox, or both, to turn off headers or footers.
- Uncheck the Show Print Dialog checkbox to turn off the print dialog.
- Uncheck the Fit Print Page Width checkbox to choose printing in
NORMALmode. - Uncheck the Interactive (show status dialog) checkbox to turn off the progress dialog.
- Click the Print button to print the table according to the selected options.
Whenever a Web Start-enabled application attempts to print, Java Web Start displays a security dialog asking the user for permission to print. To continue printing, the user must accept the request.
When you uncheck the interactive checkbox, a message appears warning the user about the drawbacks of non-interactive printing. You can find the printing code in the PrintGradesTable method. When called, this method first gets the selected option set from GUI components, then calls the print method as follows:
boolean complete = gradesTable.print(mode, header, footer,
showPrintDialog, null,
interactive, null);
The return value of the print method is then used to display a success message or a message indicating the user cancelled printing.
Another important feature is that the table printing API uses the table renderer. By using the table's renderer, the API provides printed output that looks like the table on screen. Look at the last column of the table on screen. It contains custom images representing each student's pass or fail status. Now look at the print output. You'll find the checkmarks and X's look the same.
Here's a picture of TablePrintDemo1's print output in FIT_WIDTH mode.
This image has been reduced to fit on the page. Click the image to view its original size.
TablePrintDemo2 Example
The TablePrintDemo2 example is based on the previous demo and has the same interface. The only difference is in the print output. If you look more closely at TablePrintDemo1's print output, you might notice the checkmarks and X's are somewhat blurry. The TablePrintDemo2 example shows how to customize the table to make images clearer in table printing. In this demo, the overridden getTableCellRendererComponent method determines whether the table is being printed and returns a clearer black-and-white image. If the table isn't being printed, it returns the colored image seen on screen.
Click the Launch button to run TablePrintDemo2. Alternatively, compile and run the example yourself.
The isPaintingForPrint method defined in the JComponent class allows us to customize the difference between print content and what's seen on screen. The code for the custom cell renderer extracted from TablePrintDemo2.java appears below. This code chooses which image to use based on what isPaintingForPrint returns:
/**
* A custom cell renderer that extends TablePrintDemo1's renderer,
* returning clearer black and white versions of icons when printing.
*/
protected static class MonochromeStatusRenderer extends StatusRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, column);
/* if we're currently printing, use the black and white icons */
if (table.isPaintingForPrint()) {
boolean status = (Boolean)value;
setIcon(status ? passedIconBW : failedIconBW);
} /* otherwise, the superclass (colored) icons are used */
return this;
}
}
Here's a picture of TablePrintDemo2's print output in FIT_WIDTH mode.
This image has been reduced to fit on the page. Click the image to view its original size.
TablePrintDemo3 Example
The TablePrintDemo3 example is based on the previous two demos. This example shows how to provide a custom Printable implementation by wrapping the default Printable object and adding extra decoration. This demo has a similar interface, but the header and footer checkboxes are disabled because the custom printable provides its own header and footer.
Click the Launch button to run TablePrintDemo3.
This example prints the table inside a clipboard image. Here's a picture of the print output in FIT_WIDTH mode.
This image has been reduced to fit on the page. Click the image to view its original size.
The complete code for this program can be found in TablePrintDemo3.java. In this demo, a custom subclass of JTable called FancyPrintingJTable is used. This class overrides the getPrintable method to return a custom printable that wraps the default printable with its own decoration, header, and footer. Here's the implementation of the getPrintable method:
public Printable getPrintable(PrintMode printMode,
MessageFormat headerFormat,
MessageFormat footerFormat) {
MessageFormat pageNumber = new MessageFormat("- {0} -");
/* Fetch the default printable */
Printable delegate = super.getPrintable(printMode, null, pageNumber);
/* Return a fancy printable that wraps the default */
return new DecorativePrintable(delegate);
}
The DecorativePrintable class wraps the default printable in another printable and draws the clipboard image. When an instance of this class is instantiated, it loads the images needed to assemble the clipboard image, calculates the area needed for the clipboard image, calculates the reduced area for the table, prints the table into the smaller area, and assembles and prints the clipboard image.
Notice how the code handles flexibility in page size when assembling the clipboard image. The code accounts for the actual page dimensions and assembles auxiliary images, stretching some of them as needed so the final clipboard image fits the actual page dimensions. The following shows the auxiliary images and indicates how these images form the final output.
This image has been reduced to fit on the page. Click the image to view its original size.
Table Printing API
This section lists methods defined in the JTable class that allow you to print tables.
Table Printing Examples
How to Print Text
Original source:
docs.oracle.com/javase/tutorial/uiswing/misc/printtext.html
The JTextComponent class provides printing support for text documents. The JTextComponent API includes methods that allow you to implement basic and advanced printing tasks. Supported formats include HTML, RTF, and plain text. For common printing tasks such as simply printing a text document, use the print method directly. The print method comes in multiple forms with different parameter sets. This method prepares your text document, obtains the appropriate Printable object, and sends it to the printer.
If the default Printable implementation doesn't meet your needs, you can customize the print layout by overriding the getPrintable method to wrap the default Printable or replace it entirely.
The simplest way to print a text component is to call the print method with no arguments:
try {
boolean complete = textComponent.print();
if (complete) {
/* show a success message */
...
} else {
/*show a message indicating that printing was cancelled */
...
}
} catch (PrinterException pe) {
/* Printing failed, report to the user */
...
}
When you call the print method with no arguments, a print dialog is displayed, then your text component is printed interactively with no headers or footers. The following shows the print method signature with the complete parameter set:
boolean complete = textComponent.print(MessageFormat headerFormat,
MessageFormat footerFormat,
boolean showPrintDialog,
PrintService service,
PrintRequestAttributeSet attributes,
boolean interactive);
When you call the print method with all arguments, you explicitly choose print features such as header and footer text, print attributes, target print service, whether to show a print dialog, and whether to print interactively or non-interactively. To decide which parameters best suit your needs, see the descriptions of available features below.
The JTextComponent printing API provides the following features:
- Interactive or non-interactive printing
- Showing a print dialog
- Adding headers or footers (or both) to the print layout
- Automatic layout and pagination
Interactive or Non-interactive Printing
In interactive mode, a progress dialog with an abort option is displayed during printing. Here's an example of a progress dialog.
This dialog allows users to track printing progress. The progress dialog is modal when the print method is called on the event dispatch thread, otherwise it's non-modal. During printing, it's important that your document remains unchanged; otherwise, print behavior is undefined. The print method ensures your document isn't modified and disables the component during printing.
If you call print non-interactively on the event dispatch thread, all events, including repainting, are blocked. That's why non-interactive printing on the EDT is recommended only for applications with an invisible GUI.
Print Dialog
You can show a standard print dialog that allows users to:
- Select a printer
- Specify the number of copies
- Change print attributes
- Cancel printing before starting
- Begin printing
You might notice that the print dialog doesn't specify the total number of pages in the print output. This is because the text printing implementation uses the Printable API, and the total page count isn't known at print time.
Adding Headers or Footers (or Both) to the Print Layout
Headers and footers are provided via MessageFormat parameters. These parameters allow for localization of headers and footers. Read the documentation for the MessageFormat class because characters like single quotes are special and need escaping. Both header and footer are centered. You can use {0} to insert a page number.
MessageFormat footer = new MessageFormat("- {0} -");
Because the total page count of the output isn't known at print time, you cannot specify a format like "Page 1 of 5".
Automatic Layout and Pagination
With the JTextComponent printing API, you don't need to worry about layout and pagination. Both layout and pagination are performed automatically. Document content is formatted to fit page size and spreads across multiple pages. If you want to insert page numbers in the footer, specify appropriate footer text format for the print method. As demonstrated earlier, you can specify page numbers in the footer by including "{0}" in the string provided to the MessageFormat footer parameter. In the printed output, {0} is replaced with the current page number.
Text Area Printing Example
Let's examine an example called TextAreaPrintingDemo. The main feature of this demo is printing text documents on the event dispatch thread or a background thread based on user selection. This demo displays a text area, allows selecting several print features, and prints the text area's contents according to the selected options. The complete code for this program can be found in TextAreaPrintingDemo.java. The rich GUI for this demo was built using the NetBeans IDE GUI builder. Here's a picture of the TextAreaPrintingDemo application.
Try this:
- Click the Launch button to run TextAreaPrintingDemo.
- Edit text in the Header or Footer checkboxes to provide different headers or footers.
- Clear the Show Progress Dialog checkbox if you want to print without displaying a progress dialog, meaning non-interactive printing. Note that once printing starts, you cannot cancel it.
- Clear the Background Printing checkbox to choose printing on the event dispatch thread. Note that non-interactive printing on the EDT will make your application unresponsive—interaction with your application will be blocked during printing.
- Click the Print button to print the text area's contents according to the selected options.
Whenever a Web Start-enabled application attempts to print, Java Web Start displays a security dialog asking for permission to print unless this permission has already been granted in the system settings. To continue printing, the user must accept the request.
An action listener is registered for the Print button. When users click the Print button, the actionPerformed method calls the print method, initiating the print task. The print task is a SwingWorker object. The following shows the implementation of the PrintingTask class:
private class PrintingTask extends SwingWorker<Object, Object> {
private final MessageFormat headerFormat;
private final MessageFormat footerFormat;
private final boolean interactive;
private volatile boolean complete = false;
private volatile String message;
public PrintingTask(MessageFormat header, MessageFormat footer,
boolean interactive) {
this.headerFormat = header;
this.footerFormat = footer;
this.interactive = interactive;
}
@Override
protected Object doInBackground() {
try {
complete = text.print(headerFormat, footerFormat,
true, null, null, interactive);
message = "Printing " + (complete ? "complete" : "canceled");
} catch (PrinterException ex) {
message = "Sorry, a printer error occurred";
} catch (SecurityException ex) {
message =
"Sorry, cannot access the printer due to security reasons";
}
return null;
}
@Override
protected void done() {
message(!complete, message);
}
}
The following shows how the print method gets the selected option set from GUI components, creates an instance of the PrintingTask class, and executes the print operation:
private void print(java.awt.event.ActionEvent evt) {
MessageFormat header = createFormat(headerField);
MessageFormat footer = createFormat(footerField);
boolean interactive = interactiveCheck.isSelected();
boolean background = backgroundCheck.isSelected();
PrintingTask task = new PrintingTask(header, footer, interactive);
if (background) {
task.execute();
} else {
task.run();
}
}
The bold code illustrates calling the method of PrintingTask based on the value of the background parameter. Whenever the user prefers to print on a background thread, the execute method is called, which schedules the print task to run on a background thread. Otherwise, the run method executes the print task on the EDT.
Since printing large documents is time-consuming, performing printing operations on a background thread is recommended.
Text Batch Printing Example
The TextBatchPrintingDemo example demonstrates printing invisible HTML text documents on a background thread. On startup, this demo displays a page with a list of URLs. You can navigate to an HTML page, add the displayed page to the print list, and once you've selected all the pages you need, print them all at once on a background thread. The complete code for this program can be found in TextBatchPrintingDemo.java. Here's a picture of the TextBatchPrintingDemo application.
Try this:
- Click the Launch button to run TextBatchPrintingDemo.
- Click any link to view the corresponding HTML page.
- Press ALT+A or select File > Add Page menu item to add the displayed page to the print list on the right.
- Press ALT+H or select File > Home menu item to return to the demo's home page.
- Add the needed pages to the print list.
- Press ALT+C or select File > Clear Selection menu item if you need to clear and rebuild the print list.
- Press ALT+P or select File > Print Selected menu item to print the selected pages.
- Press ALT+Q or select File > Quit menu item to exit the application.
You can find the printing code in the printSelectedPages method. When called, this method first gets the number of pages selected for printing. The following shows how the printSelectedPages method creates a Runnable object for each page, then prints the current page on a separate thread:
for (int i = 0; i < n; i++) {
final PageItem item = (PageItem) pages.getElementAt(i);
// This method is called from EDT. Printing is a time-consuming
// task, so it should be done outside EDT, in a separate thread.
Runnable printTask = new Runnable() {
public void run() {
try {
item.print(
// Two "false" args mean "no print dialog" and
// "non-interactive" (ie, batch-mode printing).
null, null, false, printService, null, false);
} catch (PrinterException pe) {
JOptionPane.showMessageDialog(null,
"Error printing " + item.getPage() + "\n" + pe,
"Print Error", JOptionPane.WARNING_MESSAGE);
}
}
};
new Thread(printTask).start();
Text Printing API
This section lists methods defined in the JTextComponent class that allow you to print text documents.
Text Printing Examples
How to Create a Splash Screen
Original source:
docs.oracle.com/javase/tutorial/uiswing/misc/splashscreen.html
Nearly all modern applications have a splash screen. A splash screen typically serves these purposes:
- Advertising the product
- Indicating to users that the application is starting during long startup times
- Providing information that needs to be seen only once per visit
The Java Foundation Classes (including Swing and the Abstract Window Toolkit) enable developers to create splash screens in Java technology applications. However, because the primary purpose of a splash screen is to provide users with feedback about application startup, the delay between application startup and splash screen appearance should be minimal. Before the splash screen appears, the application must load and initialize the Java Virtual Machine (JVM), AWT, Swing, and sometimes application-related libraries. The resulting several-second delay makes using Java-based splash screens less than ideal.
Fortunately, Java SE 6 provides a solution allowing applications to display a splash screen much earlier, even before the virtual machine starts. The Java application launcher can decode an image and display it in a simple undecorated window.
The splash screen can display any gif, png, or jpeg image with transparency, translucency, and animation support. The following shows an example of a Java application splash screen developed as an animated gif file.
The SplashScreen class is used to close the splash screen, change the splash screen image, get the image location or size, and draw on the splash screen. Applications cannot create instances of this class. Only one instance of this class can exist, and you can get this instance using the getSplashScreen() static method. If the application didn't create a splash screen at startup through a command line or manifest file option, the getSplashScreen method returns null.
Typically, developers want to keep the splash screen image on screen and display some content on it. The splash screen window has an overlay with an alpha channel, and you can access this overlay using the traditional Graphics2D interface.
The following code snippet shows how to get a SplashScreen object, then how to create a graphics context using the createGraphics() method:
...
final SplashScreen splash = SplashScreen.getSplashScreen();
if (splash == null) {
System.out.println("SplashScreen.getSplashScreen() returned null");
return;
}
Graphics2D g = splash.createGraphics();
if (g == null) {
System.out.println("g is null");
return;
}
...
Find the complete code for the demo in the SplashDemo.java file.
Note:
The SplashDemo application uses fixed coordinates to display overlay information. These coordinates are image-dependent and calculated individually for each splash screen.
The native splash screen can be displayed via:
- Command line argument
- Java Archive (JAR) file with a manifest option
How to Display a Splash Screen with a Command Line Argument
To display a splash screen from the command line, use the -splash: command line argument. This argument is a Java application launcher option that displays the splash screen:
java -splash:*<file name> <class name>*
Try this:
-
Save the
SplashDemo.javafile in a directory namedmisc. -
Compile the file as follows:
javac misc/SplashDemo.java -
Save the
splash.gifimage in animagesdirectory. -
Run the application from the command line with the following parameter:
java -splash:images/splash.gif misc.SplashDemo -
Wait until the splash screen is fully displayed.
-
The application window appears. To close the window, select File | Exit from the pop-up menu, or click X.
-
Change the splash screen name to an image that doesn't exist, for example
nnn.gif. Run the application as follows:java -splash:images/nnn.gif misc.SplashDemo -
You'll see the following output:
SplashScreen.getSplashScreen() returned null
How to Display a Splash Screen with a JAR File
If your application is packaged in a JAR file, you can display a splash screen using the SplashScreen-Image option in the manifest file. Place the image inside the JAR file and specify the path in the option as follows:
Manifest-Version: 1.0
Main-Class: *<class name>*
SplashScreen-Image: *<image name>*
Try this:
-
Save the
SplashDemo.javafile in a directory namedmisc. -
Compile the file as follows:
javac misc/SplashDemo.java -
Save the
splash.gifimage in animagesdirectory. -
Prepare the
splashmanifest.mffile as follows:Manifest-Version: 1.0 Main-Class: misc.SplashDemo SplashScreen-Image: images/splash.gif -
Create a JAR file with the following command:
jar cmf splashmanifest.mf splashDemo.jar misc/SplashDemo*.class images/splash.gifFor more information about JAR files, see using JAR files in the packaging programs in JAR files page.
-
Run the application:
java -jar splashDemo.jar -
Wait until the splash screen is fully displayed.
-
The application window appears. To close the window, select File | Exit from the pop-up menu, or click X.
Splash Screen API
The SplashScreen class cannot be used to create a splash screen. Only one instance of this class can exist.
Splash Screen API Examples
How to Use the System Tray
Original source:
docs.oracle.com/javase/tutorial/uiswing/misc/systemtray.html
The system tray is a dedicated area of the desktop where users can access programs currently running. This area is known by different names on various operating systems. On Microsoft Windows, the system tray is called the taskbar status area; on the GNOME desktop, it's called the notification area; on KDE, this area is called the system tray. However, on each system, the tray area is shared by all running applications on the desktop.
The java.awt.SystemTray class, introduced in Java SE version 6, represents the system tray of the desktop. You can access the system tray by calling the static method SystemTray.getSystemTray(). Before calling this method, check whether the system tray is supported by using the static method isSupported(). If the platform doesn't support the system tray, the isSupported() method returns false. If an application attempts to call getSystemTray() in this situation, the method throws java.lang.UnsupportedOperationException.
Applications cannot create instances of the SystemTray class. Only one instance of this class can exist, and you can get this instance using the getSystemTray() method.
The system tray contains one or more tray icons, which can be added to the tray using the add(java.awt.TrayIcon) method. They can be removed using the remove(java.awt.TrayIcon) method when no longer needed.
Note: The add() method may throw AWTException if the operating system or Java runtime determines that an icon cannot be added to the system tray. For example, the X-Window desktop throws AWTException if the system tray doesn't exist on the desktop.
The TrayIcon class functionality is not limited to the icon displayed in the tray. It also includes a text tooltip, a pop-up menu, balloon messages, and a set of associated listeners. TrayIcon objects generate various mouse events and support adding corresponding listeners to receive notifications of these events. The TrayIcon class itself handles some events. For example, by default, when you right-click on the tray icon, it shows the specified pop-up menu. When you double-click, the TrayIcon object generates an ActionEvent to launch the application. When the mouse pointer hovers over the tray icon, the tooltip is shown. The icon image is automatically resized to fit the space allocated for it in the tray.
The following demo uses the AWT package to demonstrate the functionality of the SystemTray and TrayIcon classes.
Unfortunately, the current implementation of the TrayIcon class has limited support for Swing pop-up menus (JPopupMenu class) and doesn't allow applications to use all features of the javax.swing package. A solution to this issue is described in the bug database—see Bug ID 6285881.
Try this:
- Place the
bulb.gifimage file in theimagedirectory. Compile and run the example. - The tray icon appears in the system tray.
- Double-click the tray icon to launch the corresponding application. A dialog appears.
- Hover over the tray icon and right-click the mouse. A pop-up menu appears.
- Select the Set auto size checkbox menu item. Note the icon appearance changes.
- Select the Set tooltip checkbox menu item. Hover over the tray icon. The tooltip appears.
- Select the About menu item. A dialog appears. Close the dialog.
- Select any of the Display submenu items. Each of these displays a specific type of message dialog: error, warning, info, or none.
- Use the Exit menu item to quit the application.
The following code snippet shows how to add a tray icon to the system tray and apply a pop-up menu:
...
//Check if the SystemTray is supported
if (!SystemTray.isSupported()) {
System.out.println("SystemTray is not supported");
return;
}
final PopupMenu popup = new PopupMenu();
final TrayIcon trayIcon =
new TrayIcon(createImage("images/bulb.gif", "tray icon"));
final SystemTray tray = SystemTray.getSystemTray();
// Create pop-up menu components
MenuItem aboutItem = new MenuItem("About");
CheckboxMenuItem autoSizeItem = new CheckboxMenuItem("Set auto size");
CheckboxMenuItem tooltipItem = new CheckboxMenuItem("Set tooltip");
Menu displayMenu = new Menu("Display");
MenuItem errorItem = new MenuItem("Error");
MenuItem warningItem = new MenuItem("Warning");
MenuItem infoItem = new MenuItem("Info");
MenuItem noneItem = new MenuItem("None");
MenuItem exitItem = new MenuItem("Exit");
//Add components to pop-up menu
popup.add(aboutItem);
popup.addSeparator();
popup.add(autoSizeItem);
popup.add(tooltipItem);
popup.addSeparator();
popup.add(displayMenu);
displayMenu.add(errorItem);
displayMenu.add(warningItem);
displayMenu.add(infoItem);
displayMenu.add(noneItem);
popup.add(exitItem);
trayIcon.setPopupMenu(popup);
try {
tray.add(trayIcon);
} catch (AWTException e) {
System.out.println("TrayIcon could not be added.");
}
...
The complete code for this demo can be found in the TrayIconDemo.java file. This demo also uses the bulb.gif image file.
Removing the current restriction on Swing components for tray icons would enable developers to add components such as JMenuItem (with images), JRadioButtonMenuItem, and JCheckBoxMenuItem.
SystemTray API
Only one instance of the SystemTray class can exist.
TrayIcon API
A TrayIcon object represents an icon that can be added to the system tray. TrayIcon objects can have a tooltip (text), image, pop-up menu, and a set of associated listeners.
SystemTray API Examples
Solving Common Problems with Other Swing Features
Original source:
docs.oracle.com/javase/tutorial/uiswing/misc/problems.html
Problem: My application doesn't show the look and feel I requested via UIManager.setLookAndFeel.
You may have either set an invalid look and feel, or set the look and feel after the UI manager loaded the default look and feel. If you're certain the look and feel you specified is valid and setting the look and feel is the first thing your program does (for example, at the top of its main method), check whether a static field of a Swing class is being referenced. This reference could cause the default look and feel to be loaded before you specify one. For more information, including how to set the look and feel after creating the GUI, see the look and feel section.
Problem: Why isn't my component gaining focus?
- Is it a custom component you created (for example, a direct subclass of
JComponent)? If so, you may need to provide input maps and a mouse listener for your component. For more information and a demo, see making custom components focusable. - Is the component inside a
JWindowobject? The focus system requires that the owning frame of theJWindowbe visible for any component inside theJWindowto gain focus. By default, if you don't specify an owning frame for aJWindowobject, an invisible owning frame is created for it. The solution is either to specify a visible, focusable owning frame when creating theJWindowobject, or use aJDialogorJFrameobject instead.
Problem: Why isn't my dialog receiving the event generated when the user presses the Escape key?
If your dialog contains text fields, they may be consuming the event.
- If you want to receive the Escape event regardless of whether components consume it, use
KeyEventDispatcher. - If you only want to receive the Escape event when components haven't consumed it, register a key binding on any
JComponentcomponent in theJDialogobject using theWHEN_IN_FOCUSED_WINDOWinput map. For more information, see how to use key bindings.
Problem: Why can't I apply Swing components to a tray icon? The current implementation of the TrayIcon class supports PopupMenu components but not its Swing counterpart JPopupMenu. This restriction limits the ability to use other Swing features such as menu icons. See Bug ID 6285881.
- To eliminate this inconvenience, a new
JTrayIconclass will be created. Until then, use AWT components to add menu items, checkbox menu items, or submenus.
If you don't find your problem in this section, see solving common component problems.
Laying Out Components Within a Container
Original source:
docs.oracle.com/javase/tutorial/uiswing/layout/index.html
Example index
This lesson teaches you how to use layout managers provided by the Java platform. It also tells you how to use absolute positioning (no layout manager) and provides examples of writing custom layout managers. For each layout manager (or lack thereof), this lesson points to an example you can run using Java Web Start. By resizing the example windows, you can see how resizing affects the layout.
Note: This lesson covers writing layout code manually, which can be challenging. If you don't want to learn all the details of layout management, you might prefer using the GroupLayout layout manager together with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to manually code and don't want to use GroupLayout, GridBagLayout is recommended as the next most flexible and powerful layout manager.
If you're interested in creating GUIs with JavaFX, see using layout in JavaFX.
Visual Guide to Layout Managers
This section shows examples of the standard layout managers and points to the how-to sections for each layout manager. You can find links to run examples in the how-to sections and the example index.
Using Layout Managers
This section provides general rules for using the standard layout managers. It includes how to set a layout manager, add components to a container, give size and alignment hints, put space between components, and set a container's layout orientation to suit the locale where the program runs. It also gives hints on choosing the right layout manager.
How Layout Managers Work
This section introduces the typical layout sequence, then describes what happens when component sizes change.
How to Use...
This series of sections tells you how to use each of the general-purpose layout managers provided by the Java platform.
Creating Custom Layout Managers
You can write your own layout manager instead of using one of the Java platform's layout managers.
A layout manager must implement the LayoutManager interface, which specifies five methods that each layout manager must define. Optionally, a layout manager can implement LayoutManager2, which is a subinterface of LayoutManager.
Using No Layout Manager (Absolute Positioning)
If necessary, you can position components without using a layout manager. Typically, this solution is used to give components absolute size and position.
Solving Common Layout Problems
Some of the most common layout problems involve components that appear too small or don't appear at all. This section tells you how to solve these and other common layout problems.
Questions and Exercises
Try these questions and exercises to test your understanding of what you've learned in this lesson.
If you're interested in using JavaFX to create your GUI, see using layout in JavaFX.
Visual Guide to Layout Managers
Original source:
docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
Several AWT and Swing classes provide layout managers for general use:
BorderLayoutBoxLayoutCardLayoutFlowLayoutGridBagLayoutGridLayoutGroupLayoutSpringLayout
This section shows examples of GUIs using these layout managers and tells you where to find the how-to page for each layout manager. You can find links to run examples in the how-to pages and the example index.
Note: This lesson covers writing layout code manually, which can be challenging. If you're not interested in learning all the details of layout management, you might prefer using the GroupLayout layout manager together with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to manually write code and don't want to use GroupLayout, GridBagLayout is recommended as the next most flexible and powerful layout manager.
If you're interested in creating GUIs with JavaFX, see using layout in JavaFX.
BorderLayout
Every content pane is initialized to use BorderLayout. (As explained in using top-level containers, the content pane is the main container in every frame, applet, and dialog.) BorderLayout places components in up to five areas: top, bottom, left, right, and center. All extra space goes to the center area. Toolbars created with JToolBar must be created inside a BorderLayout container if you want to be able to drag them from their starting position to another position. For more details, see how to use BorderLayout.
BoxLayout
The BoxLayout class places components in a single row or column. It respects the components' maximum size requests and also lets you align components. For more details, see how to use BoxLayout.
CardLayout
The CardLayout class lets you implement an area that shows different components at different times. CardLayout is often controlled by a combo box, whose state determines which panel (group of components) CardLayout shows. An alternative to using a tabbed pane is using CardLayout, which provides similar functionality with a predefined GUI. For more details, see how to use CardLayout.
FlowLayout
FlowLayout is the default layout manager for every JPanel. It simply lays out components in a row, starting a new row when its container's width is insufficient. Both panels in CardLayoutDemo, shown earlier, use FlowLayout. For more details, see how to use FlowLayout.
GridBagLayout
GridBagLayout is a complex, flexible layout manager. It aligns components by placing them in a grid of cells, allowing components to span multiple cells. The rows of the grid can have different heights, and grid columns can have different widths. For more details, see how to use GridBagLayout.
GridLayout
GridLayout simply makes a group of components the same size and displays them in the requested number of rows and columns. For more details, see how to use GridLayout.
GroupLayout
GroupLayout is a layout manager that was developed for GUI builders but can also be used manually. GroupLayout handles horizontal and vertical layouts separately. Layouts are defined independently for each dimension. Therefore, each component needs to be defined twice in the layout. The find window shown above is an example of GroupLayout. For more details, see how to use GroupLayout.
SpringLayout
SpringLayout is a flexible layout manager designed for GUI builders. It allows you to specify the exact relationships between the edges of components it controls. For example, you can define the distance between a component's left edge and another component's right edge (which can be calculated dynamicallly). SpringLayout lays out the children of its associated container according to a set of constraints, as shown in how to use SpringLayout.