DOC

how to use focus system

By Juan Robinson,2014-10-16 17:45
9 views 0
how to use focus system

How to Use the Focus Subsystem

    Many components even those primarily operated with the mouse, such as buttons can be operated with the keyboard. For a key press to affect a component, the component must have the keyboard focus.

    From the user's point of view, the component with the keyboard focus is generally prominent with a dotted or black border, for example. The window containing the component is also more prominent than other windows onscreen. These visual cues let the user know to which component any typing will relate. Only one component at a time in the window system can have the keyboard focus.

    Exactly how a window gains the focus depends on the windowing system. There is no foolproof way, across all platforms, to ensure that a window gains the focus. On some operating systems, such as Microsoft Windows, the front window usually becomes the focused window. In these cases, the Window.toFront method moves the window to the front, thereby giving it the focus. However, on other operating systems, such as Solaris? Operating System, the window manager may choose the focused window based on cursor position, and in these cases the behavior of the Window.toFront method is different.

    A component generally gains the focus when the user clicks it, or when the user tabs between components, or otherwise interacts with a component. A component can also be given the focus programmatically, such as when its containing frame or dialog-box is made visible. This code snippet shows how to give a particular component the focus every time the window gains the focus:

    //Make textField get the focus whenever frame is activated. frame.addWindowFocusListener(new WindowAdapter() {

     public void windowGainedFocus(WindowEvent e) {

     textField.requestFocusInWindow();

     }

    });

    If you want to ensure that a particular component gains the focus the first time a window is activated, you can call the requestFocusInWindow method

    on the component after the component has been realized, but before the frame is displayed. The following sample code shows how this operation can be done:

     //...Where initialization occurs...

     JFrame frame = new JFrame("Test");

     JPanel panel = new JPanel(new BorderLayout());

     //...Create a variety of components here...

     //Create the component that will have the initial focus.

     JButton button = new JButton("I am first");

     panel.add(button);

     frame.getContentPane().add(panel); //Add it to the panel

     frame.pack(); //Realize the components.

     //This button will have the initial focus.

     button.requestFocusInWindow();

     frame.setVisible(true); //Display the window.

    Alternatively, you can apply a custom FocusTraversalPolicy to the frame and call the getDefaultComponent method to determine which component will gain the focus.

    Version note: This section describes the focus architecture implemented in JDK 1.4. Prior to the 1.4 release, JComponent methods, such as setNextFocusableComponent, getNextFocusableComponent,

    requestDefaultFocus, and isManagingFocus, were used to manage the keyboard focus. These methods are now deprecated. Another method, requestFocus, is discouraged because it tries to give the focus to the component's window, which is not always possible. As of JDK 1.4, you should instead use the requestFocusInWindow method, which does not attempt to make the component's window focused. The method returns a boolean value indicating whether the method succeeded.

The rest of this section covers the following topics:

    ; Introduction to the Focus

    Subsystem

    ; Validating Input

    ; Making a Custom Component

    Focusable

    ; Customizing Focus Traversal

    ; Tracking Focus Changes to

    Multiple Components

    ; Timing Focus Transfers

    ; The Focus API

    ; Focus Examples

    Introduction to the Focus Subsystem

    The focus subsystem is designed to do the right thing as invisibly as

    possible. In most cases it behaves in a reasonable manner, and if it does

    not you can tweak its behavior in various ways. Some common scenarios might

    include:

    ; The ordering is right but the

    first component with the

    focus is not set. As shown in

    a code snippet in the

    preceding section, you can

    use the requestFocusInWindow

    method to set the focus on a

    component when the window

    becomes visible.

    ; The ordering is wrong. To fix

    this issue, you can change

    the containment hierarchy,

    you can change the order that

    the components are added to

    their containers, or you can

    create a custom focus

    traversal policy. For more

    details see Customizing

    Focus Traversal.

    ; A component must to be

    prevented from losing focus,

    or you need to check a value

    in a component before it

    loses focus. Input

    verification is a solution to

    this problem.

    ; A custom component is not

    getting the focus. To fix

    this issue, you need to make

    sure that it satisfies all

    the requirements outlined in

    Making a Custom Component

    Focusable.

    The FocusConceptsDemo example illustrates a few concepts.

    Try this:

    1. Click the Launch

    button to run

    FocusConceptsDemo

    using Java? Web Start

    (download JDK 6).

    Alternatively, to

    compile and run the

    example yourself,

    consult the example

    index.

    2. If necessary, click

    the window to give it

    the focus.

    3. Move the focus from

    component to component

    using the Tab key.

    You will notice that

    when the focus moves

    into the text area, it

    stays in the text area.

    4. Move the focus out of

    the text area using

    Control-Tab.

    5. Move the focus in the

    opposite direction

    using Shift-Tab.

    6. Move the focus out of

    the text area in the

    opposite direction

    using

    Control-Shift-Tab.

    The KeyboardFocusManager is a critical element of the focus subsystem. It manages state and initiates changes. The keyboard manager tracks the focus owner the component that receives typing from the keyboard. The focused window is the window that contains the focus owner.

    To use a JWindow component in your GUI, you should know JWindow and focus:

    that the JWindow component's owning frame must be visible in order for any components in the window to get the focus. By default, if you do not specify an owning frame for a JWindow component, an invisible owning frame is created for it. The result is that components in the JWindow component might not be able to get the focus. The solution is either to specify a visible owning frame when creating the JWindow component, or to use an

    undecorated JFrame component instead.

A focus cycle (or focus traversal cycle) is a set of components that share

    a common ancestor in the containment hierarchy. The focus cycle root is

    the container that is the root for a particular focus traversal cycle. By default, every JWindow and JInternalFrame component can be a focus cycle root. A focus cycle root can 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. While it might appear that JTable and JTree objects are focus cycle roots, they are not.

    A focus traversal policy determines the order in which a group of

    components are navigated. Swing provides the LayoutFocusTraversalPolicy

    class, which decides the order of navigation based on layout manager-dependent factors, such as size, location, and orientation of components. Within a focus cycle, components can be navigated in a forward

    or backward direction. In a hierarchy of focus cycle roots, upwards traversal takes the focus out of the current cycle into the parent cycle. In most Look and Feel models, components are navigated using the Tab and Shift-Tab keys. These keys are the default focus traversal keys and can

    be changed programmatically. For example, you can add Enter as a forward focus traversal key with the following four lines of code: 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 shifts the focus in the forward direction. Shift-Tab moves the focus in the backward direction. For example, in FocusConceptsDemo, the first button has the initial focus. Tabbing moves the focus through the buttons into the text area. Additional tabbing moves the cursor within the text area but not out of the text area because, inside a text area, Tab is not

    a focus traversal key. However, Control-Tab moves the focus out of the text area and into the first text field. Likewise, Control-Shift-Tab moves the focus out of the text area and into the previous component. The Control key is used by convention to move the focus out of any component that treats Tab in a special way, such as JTable.

    You have just received a brief introduction to the focus architecture. If you want more details, see the specification for the Focus Subsystem.

    Validating Input

    A common requirement of GUI design is a component that restricts the user's input for example, a text field that allows only numeric input in decimal format (money, for example) or a text field that allows only 5 digits for a zip code. Release 1.4 provides a handy, easy-to-use formatted

    text field component that allows input to be restricted to a variety of localizable formats. You can also specify a custom formatter for the text

    field, which can perform special checking such as determining whether values are not only formatted correctly, but also reasonable. You can use an input verifier as an alternative to a custom formatter, or when you have a component that is not a text field. An input verifier allows you to reject specific values, such as a properly formatted but invalid zip code, or values outside of a desired range, for example a body temperature higher than 110?F. To use an input verifier, you create a

subclass of InputVerifier (a class introduced in JDK 1.3), create an

    instance of your subclass, and set the instance as the input verifier for one or more components.

    A component's input verifier is consulted whenever the component is about to lose the focus. If the component's value is not acceptable, the input verifier can take appropriate action, such as refusing to yield the focus on the component or replacing the user's input with the last valid value and then allowing the focus to transfer to the next component. However, InputVerifier is not called when the focus is transferred to another toplevel component.

    The following two examples show mortgage calculators. One uses formatted text fields and the other uses input verification with standard text fields.

Try this:

    1. Click the Launch

    button to run the

    FormattedTextFieldDem

    o using Java? Web Start

    (download JDK 6).

    Alternatively, to

    compile and run the

    example yourself,

    consult the example

    index.

    2. Click the Launch

    button to run the

    InputVerificationDemo

    using Java? Web Start

    (download JDK 6).

    Alternatively, to

    compile and run the

    example yourself,

    consult the example

    index.

    3. Compare the two

    mortgage calculators

    side by side. You will

    see that the input

    verification demo

    specifies valid input

    values in the

    associated label for

    each editable text

    field. Try entering

    badly formatted values

    in both examples to

    observe behavior. Then

    try entering a

    properly formatted,

    but unacceptable

    value.

You can find the code for the Input Verification demo in

    InputVerificationDemo.java. Here is the code for the InputVerifier subclass, MyVerifier:

    class MyVerifier extends InputVerifier

     implements ActionListener {

     double MIN_AMOUNT = 10000.0;

     double MAX_AMOUNT = 10000000.0;

     double MIN_RATE = 0.0;

     int MIN_PERIOD = 1;

     int MAX_PERIOD = 40;

     public boolean shouldYieldFocus(JComponent input) {

     boolean inputOK = verify(input);

     makeItPretty(input);

     updatePayment();

     if (inputOK) {

     return true;

     } else {

     Toolkit.getDefaultToolkit().beep();

     return false;

     }

     }

     protected void updatePayment() {

     double amount = DEFAULT_AMOUNT;

     double rate = DEFAULT_RATE;

     int numPeriods = DEFAULT_PERIOD;

     double payment = 0.0;

     //Parse the values.

     try {

     amount = moneyFormat.parse(amountField.getText()).

     doubleValue();

     } catch (ParseException pe) {pe.printStackTrace();}

     try {

     rate = percentFormat.parse(rateField.getText()).

     doubleValue();

     } catch (ParseException pe) {pe.printStackTrace();}

     try {

     numPeriods =

    decimalFormat.parse(numPeriodsField.getText()).

     intValue();

     } catch (ParseException pe) {pe.printStackTrace();}

     //Calculate the result and update the GUI.

     payment = computePayment(amount, rate, numPeriods);

     paymentField.setText(paymentFormat.format(payment));

     }

     //This method checks input, but should cause no side effects.

     public boolean verify(JComponent input) {

     return checkField(input, false);

     }

     protected void makeItPretty(JComponent input) {

     checkField(input, true);

     }

     protected boolean checkField(JComponent input, boolean changeIt) {

     if (input == amountField) {

     return checkAmountField(changeIt);

     } else if (input == rateField) {

     return checkRateField(changeIt);

     } else if (input == numPeriodsField) {

     return checkNumPeriodsField(changeIt);

     } else {

     return true; //should not happen

     }

     }

     //Checks that the amount field is valid. If it is valid,

     //it returns true; otherwise, returns false. If the

     //change argument is true, this method sets the

     //value to the minimum or maximum value if necessary and (even if not)

    sets it to the

     //parsed number so that it looks good -- no letters,

     //for example.

     protected boolean checkAmountField(boolean change) {

     boolean wasValid = true;

     double amount = DEFAULT_AMOUNT;

     //Parse the value.

     try {

     amount = moneyFormat.parse(amountField.getText()).

     doubleValue();

     } catch (ParseException pe) {

     pe.printStackTrace();

     wasValid = false;

     }

     //Value was invalid.

     if ((amount < MIN_AMOUNT) || (amount > MAX_AMOUNT)) {

     wasValid = false;

     if (change) {

     if (amount < MIN_AMOUNT) {

     amount = MIN_AMOUNT;

     } else { // amount is greater than MAX_AMOUNT

     amount = MAX_AMOUNT;

     }

     }

     }

Report this document

For any questions or suggestions please email
cust-service@docsford.com