How to Support Assistive Technologies

 < Day Day Up > 

You might be wondering what assistive technologies are and why you should care. Primarily, assistive technologies enable people with disabilities to use the computer. Say you get carpal tunnel syndrome. You can use assistive technologies to accomplish your work without using your hands.

Assistive technologiesvoice interfaces, screen readers, alternate input devices, and so onare useful not only for people with disabilities but also for people using computers in non-office environments. For example, you might use assistive technology to check your email when you're stuck in a traffic jam, using only voice input and output. The information that enables assistive technologies can be used for other tools as well, such as automated GUI testers and input devices like touchscreens. Assistive technologies get information from components using the Accessibility API, which is defined in the javax.accessibility package. [5]

[5] javax.accessibility API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/accessibility/package-summary.html.

Because support for the Accessibility API is built into the Swing components, your Swing program will probably work just fine with assistive technologies, even if you do nothing special. For example, assistive technologies can automatically get the text information that's set by the following lines of code:

 JButton button = new JButton("I'm a Swing button!"); label = new JLabel(labelPrefix + "0    "); label.setText(labelPrefix + numClicks); JFrame frame = new JFrame("SwingApplication"); 

They can also grab the tool-tip text (if any) associated with a component and use it to describe the component to the user .

Making your program function smoothly with assistive technologies is easy and in the United States may be required by federal law. For more information, see Global Legal Resources for IT Related Accessibility Issues at: http://www.sun.com/access/background/laws.html.

Rules for Supporting Accessibility

Here are a few things you can do to make your program work as well as possible with assistive technologies:

  • If a component doesn't display a short string (which serves as its default name), specify a name with the setAccessibleName method. You might want to do this for image-only buttons , panels that provide logical groupings, text areas, and so on.

  • Set tool-tip text for components whenever it makes sense to do so. For example:

     aJComponent.setToolTipText(      "Clicking this component causes XYZ to happen."); 
  • If you don't want to provide a tool tip for a component, use the setAccessible-Description method to provide a description that assistive technologies can show the user. For example:

     aJComponent.getAccessibleContext().     setAccessibleDescription(     "Clicking this component causes XYZ to happen."); 
  • Specify keyboard alternatives wherever possible. Make sure you can use your program with the keyboard only. Try hiding your mouse! If the focus is in an editable text component, you can use Shift-Tab to move it to the next component. Support for keyboard alternatives varies by component. Buttons support them with the setMnemonic method. Menus inherit the button mnemonics support and also support accelerators, as described in Enabling Keyboard Operation (page 282). Other components can use key bindings [6] to associate user typing with program actions.

    [6] See also How to Use Key Bindings (page 623).

  • Assign a textual description to all ImageIcon objects in your program. You can set this property by either the setDescription method or one of the String forms of the ImageIcon constructors.

  • If some components form a logical group , try to put them into one container. For example, use a JPanel to contain all of the radio buttons in a radio button group.

  • Whenever you have a label that describes another component, use the setLabelFor method so that assistive technologies can find the component associated with that label. This is especially important when the label displays a mnemonic for another component (such as a text field).

  • If you create a custom component, make sure it supports accessibility. In particular, be aware that subclasses of JComponent are not automatically accessible. Custom components that are descendants of other Swing components should override inherited accessibility information as necessary. For more information, see How Accessibility Works (page 528) and Making Custom Components Accessible (page 529).

  • Use the examples provided with the accessibility utilities to test your program. Although the primary purpose of these examples is to show programmers how to use the Accessibility API when implementing assistive technologies, they are also quite useful for testing application programs for accessibility. The following section, Testing for Accessibility, shows ScrollDemo running with Monkeyone of the accessibility utilities examples. Monkey shows the tree of accessible components in a program and lets you interact with those components.

  • Finally, don't break what you get for free! If your GUI has an inaccessible containerfor example, your own subclass of Container or JComponent or any other container that doesn't implement the Accessible interfaceany components inside that container become inaccessible.

Testing for Accessibility

The examples that come with the accessibility utilities can give you an idea of how accessible your program is. For instructions on getting these utilities, see the JFC Assistive Technologies home page at http://java.sun.com/products/jfc/accessibility/. Follow the instructions in the documentation for setting up the Java Virtual Machine (VM) to run one or more of the utilities automatically.

Let's use an accessibility utility to compare the original version of one of our demos to a version in which the rules for supporting accessibility have been applied. Figure 3 is a picture of a program called ScrollDemo .

Figure 3. A screenshot of the ScrollDemo example.

graphics/09fig03.jpg

Try This:

  1. graphics/cd_icon.gif

    Run ScrollDemo using Java Web Start or compile and run the example yourself. [7]

    [7] To run ScrollDemo using Java Web Start, click the ScrollDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#ScrollDemo .

  2. graphics/cd_icon.gif

    Run AccessibleScrollDemo using Java Web Start or compile and run the example yourself. [8]

    [8] To run AccessibleScrollDemo using Java Web Start, click the AccessibleScrollDemo link on the RunExamples/misc.html page on the CD. You can find the source files here: JavaTutorial/uiswing/misc/example-1dot4/index.html#AccessibleScrollDemo .

  3. Compare the two versions side by side. The only noticeable difference is that the cm toggle button and the photograph have tool tips in the accessible version.

  4. Run the two versions under the accessibility utility called Monkey. Note when the accessibility tools have been downloaded and configured in the accessibility. properties file, that the Monkey window automatically comes up when you click on the "Run ScrollDemo " and "Run AccessibleScrollDemo " links (in steps 1 and 2).

    If the Monkey window doesn't appear on startup, the problem may be that the accessibility.properties file isn't present in the version of the VM being used by Java Web Start. You can change the VM by running the Java Web Start Application Manager and selecting File > Preferences > Java.

  5. When the Monkey window comes up, you need to select File > Refresh Trees to see information appear under Accessible Tree . You can then expand the tree by successively clicking on the horizontal icons displayed by each folder icon. When the tree has been expanded, you can see detailed information for the various components. The custom components (rules and corners) that weren't accessible in the original version are accessible in the modified version. This can make quite a difference to assistive technologies.

Figure 4 shows Monkey running on ScrollDemo . The left side of the split pane shows the actual component hierarchy for the program. The right side shows the accessible components in the hierarchy, which is what interests us.

Figure 4. Monkey running on an inaccessible version of ScrollDemo

graphics/09fig04.jpg

The first thing to notice is that, even with no explicit support in ScrollDemo , Monkey is able to discover a lot of information about the various components in the example. Most of the components and their children appear in the tree. However, the names for most of them are empty (null), which is rather unhelpful. The descriptions are also empty.

Further trouble comes with the program's custom components. The two rulers are inaccessible, so they aren't included in the accessible tree. The viewports that contain the rulers are displayed as leaf nodes because they have no accessible children. The custom corners are also missing from the accessible tree.

Figure 5 shows the Monkey window for AccessibleScrollDemo .

Figure 5. Monkey running on an accessible version of ScrollDemo .

graphics/09fig05.jpg

The rules are now listed as children of the viewports, and the corners are listed as children of the scroll pane. Furthermore, many of the components now have non-null names.

In Figure 5, the Column Header item is selected. Monkey highlights the corresponding component in the ScrollDemo program.

When an item is selected, you can use Monkey's Panels menu to bring up one of four different panels that let you interact with the selected component. Choosing Panels > Accessibility API panel brings up a panel like the one that is shown in Figure 6. This panel displays information available through methods defined in the AccessibleContext base class and the AccessibleComponent interface.

Figure 6. An Accessibility API panel.

graphics/09fig06.gif

Monkey has three other panels:

  • AccessibleAction shows the actions supported by an accessible component and lets you invoke the action. It works only with an accessible component whose context implements the AccessibleAction interface.

  • AccessibleSelection shows the current selection of an accessible component and lets you manipulate the selection. It works only with an accessible component whose context implements the AccessibleSelection interface.

  • AccessibleHypertext shows any hyperlinks contained within an accessible component and lets you traverse them. It works only with an accessible component whose context implements the AccessibleHypertext interface.

The accessibility utilities examples are handy as testing tools and can give you an idea of how accessible the components in your program are. However, even if your components behave well in Monkey or the other examples, they still might not be completely accessible because Monkey and the other examples exercise only certain portions of the Accessibility API. The only true test of accessibility is to run your programs with real-world assistive technologies.

Setting Accessible Names and Descriptions on Components

Giving your program's components accessible names and descriptions is one of the easiest and most important steps in making your program itself accessible. Following is a complete listing of the AccessibleScrollDemo constructor that creates the scroll pane and the custom components it uses. The boldface statements give component names and descriptions that assistive technologies can use.

 public AccessibleScrollDemo() {     // Get the image to use.  ImageIcon david = createImageIcon("images/youngdad.jpeg",   "Photograph of David McNabb in his youth.");  // Create the row and column headers.     columnView = new Rule(Rule.HORIZONTAL, true);     if (david != null) {         columnView.setPreferredWidth(david.getIconWidth());     } else {         columnView.setPreferredWidth(320);     }  columnView.getAccessibleContext().   setAccessibleName("Column Header");   columnView.getAccessibleContext().   setAccessibleDescription("Displays horizontal ruler for " +   "measuring scroll pane client.");  rowView = new Rule(Rule.VERTICAL, true);     if (david != null) {         rowView.setPreferredHeight(david.getIconHeight());     } else {         rowView.setPreferredHeight(480);     }  rowView.getAccessibleContext().setAccessibleName("Row Header");   rowView.getAccessibleContext().   setAccessibleDescription("Displays vertical ruler for " +   "measuring scroll pane client.");  // Create the corners.     JPanel buttonCorner = new JPanel();     isMetric = new JToggleButton("cm", true);     isMetric.setFont(new Font("SansSerif", Font.PLAIN, 11));     isMetric.setMargin(new Insets(2,2,2,2));     isMetric.addItemListener(this);  isMetric.setToolTipText("Toggles rulers' unit of measure " +   "between inches and centimeters.");  buttonCorner.add(isMetric); //Use the default FlowLayout  buttonCorner.getAccessibleContext().   setAccessibleName("Upper Left Corner");   String desc = "Fills the corner of a scroll pane " +   "with color for aesthetic reasons.";  Corner lowerLeft = new Corner();  lowerLeft.getAccessibleContext().   setAccessibleName("Lower Left Corner");   lowerLeft.getAccessibleContext().setAccessibleDescription(desc);  Corner upperRight = new Corner();  upperRight.getAccessibleContext().   setAccessibleName("Upper Right Corner");   upperRight.getAccessibleContext().setAccessibleDescription(desc);  // Set up the scroll pane.     picture = new ScrollablePicture(david,                                     columnView.getIncrement());  picture.setToolTipText(david.getDescription());   picture.getAccessibleContext().setAccessibleName(   "Scroll pane client");  JScrollPane pictureScrollPane = new JScrollPane(picture);     pictureScrollPane.setPreferredSize(new Dimension(300, 250));     pictureScrollPane.setViewportBorder(             BorderFactory.createLineBorder(Color.black));     pictureScrollPane.setColumnHeaderView(columnView);     pictureScrollPane.setRowHeaderView(rowView);     // In theory, to support internationalization you would change     // UPPER_LEFT_CORNER to UPPER_LEADING_CORNER,     // LOWER_LEFT_CORNER to LOWER_LEADING_CORNER, and     // UPPER_RIGHT_CORNER to UPPER_TRAILING_CORNER.  In practice,     // bug #4467063 makes that impossible (at least in 1.4.0).     pictureScrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,                                 buttonCorner);     pictureScrollPane.setCorner(JScrollPane.LOWER_LEFT_CORNER,                                 lowerLeft);     pictureScrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER,                                 upperRight);     // Put it in this panel.     setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));     add(pictureScrollPane);     setBorder(BorderFactory.createEmptyBorder(20,20,20,20)); } 

Often the program sets a component's name and description directly through the component's accessible context. Other times, it sets an accessible description indirectly with tool tips. In the case of the cm toggle button, the description is set automatically to the text on the button.

How Accessibility Works

An object is accessible if it implements the Accessible [9] interface. The Accessible interface defines just one method, getAccessibleContext , which returns an Accessible-Context [10] object (see Figure 7). This object is an intermediary that contains the accessible information for an accessible object.

[9] Accessible API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/accessibility/Accessible.html.

[10] AccessibleContext API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/accessibility/AccessibleContext.html.

Figure 7. This figure shows how assistive technologies get the accessible context from an accessible object and query it for information.

graphics/09fig07.jpg

AccessibleContext is an abstract class that defines the minimum information an accessible object must provide about itself. That minimum includes name, description, role, state set, and so on. To identify its accessible object as having particular capabilities, an accessible context can implement one or more of the interfaces as shown in Table 6, "Accessible Interfaces," on page 533. For example, JButton implements AccessibleAction , Accessible-Value , AccessibleText , and AccessibleExtendedComponent . It isn't necessary for JButton to implement AccessibleIcon , which is implemented by the ImageIcon attached to the button.

Because the JComponent class itself doesn't implement the Accessible interface, instances of its direct subclasses aren't accessible. If you write a custom component that inherits directly from JComponent , you need to explicitly make it implement the Accessible interface. JComponent does have an accessible context, called AccessibleJComponent , that implements the AccessibleComponent interface and provides a minimal amount of accessible information. You can provide an accessible context for your custom components by creating a subclass of AccessibleJComponent and overriding important methods. The next section, Making Custom Components Accessible, shows two examples of doing this.

All of the other standard Swing components implement the Accessible interface and have an accessible context that implements one or more of the preceding interfaces as appropriate. The accessible contexts for Swing components are implemented as inner classes and have names of this style:

  Component  .Accessible  Component  

If you create a subclass of a standard Swing component and your subclass is substantially different from its superclass, you should provide a custom accessible context for it. The easiest way is to create a subclass of the superclass's accessible context class and override methods as necessary. For example, if you create a JLabel subclass substantially different from JLabel , your subclass should contain an inner class that extends AccessibleJLabel . The next section shows how to do this using examples in which JComponent subclasses extend AccessibleJComponent .

Making Custom Components Accessible

The ScrollDemo program uses three custom component classes. ScrollablePicture is a subclass of JLabel , and Corner and Rule are both subclasses of JComponent .

The ScrollablePicture class relies completely on accessibility inherited from JLabel through JLabel.AccessibleJLabel . [11] The code that creates an instance of Scrollable-Picture sets the tool-tip text for the scrollable picture. The tool-tip text is used by the context as the component's accessible description. This behavior is provided by AccessibleJLabel .

[11] JLabel.AccessibleJLabel API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JLabel.AccessibleJLabel.html.

The accessible version of the Corner class contains just enough code to make its instances accessible. We implemented accessibility support by adding the code shown in bold to the original version of Corner in the following.

 public class Corner extends JComponent  implements Accessible {  public void paintComponent(Graphics g) {         //Fill me with dirty brown/orange.         g.setColor(new Color(230, 163, 4));         g.fillRect(0, 0, getWidth(), getHeight());     }  public AccessibleContext getAccessibleContext() {   if (accessibleContext == null) {   accessibleContext = new AccessibleCorner();   }   return accessibleContext;   }   protected class AccessibleCorner extends AccessibleJComponent {   //Inherit everything, override nothing.   }  } 

All of the accessibility provided by this class is inherited from AccessibleJComponent , [12] which is fine for Corner because AccessibleJComponent provides a reasonable amount of default accessibility information and because corners are uninterestingthey exist only to take up a little bit of space onscreen. Other classes, such as Rule , need to provide customized information.

[12] AccessibleJComponent API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JComponent.AccessibleJComponent.html.

Rule provides an accessible context for itself in the same manner as Corner , but the context overrides two methods to provide details about the component's role and state:

 protected class AccessibleRuler extends AccessibleJComponent {     public AccessibleRole getAccessibleRole() {         return AccessibleRuleRole.RULER;     }     public AccessibleStateSet getAccessibleStateSet() {         AccessibleStateSet states = super.getAccessibleStateSet();         if (orientation == VERTICAL) {             states.add(AccessibleState.VERTICAL);         } else {             states.add(AccessibleState.HORIZONTAL);         }         if (isMetric) {             states.add(AccessibleRulerState.CENTIMETERS);         } else {             states.add(AccessibleRulerState.INCHES);         }         return states;     } } 

AccessibleRole [13] is an enumeration of objects that identify the roles that Swing components can play. It contains predefined roles such as label and button. The rulers in our example don't fit well into any of the predefined roles, so the program invents a new ruler in a subclass of AccessibleRole :

[13] AccessibleRole API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/accessibility/AccessibleRole.html.

 class AccessibleRuleRole extends AccessibleRole {     public static final AccessibleRuleRole RULER         = new AccessibleRuleRole("ruler");     protected AccessibleRuleRole(String key) {         super(key);     }     //Should really provide localizable versions of these names.     public String toDisplayString(String resourceBundleName,                                   Locale locale) {         return key;     } } 

Any component that has state can provide state information to assistive technologies by overriding the getAccessibleStateSet method. A rule has two sets of states: Its orientation can be either vertical or horizontal, and its units of measure can be either centimeters or inches. AccessibleState [14] is an enumeration of predefined states. This program uses its predefined states for vertical and horizontal orientation. Because AccessibleState contains nothing for centimeters and inches, the program makes a subclass to provide appropriate states:

[14] AccessibleState API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/accessibility/AccessibleState.html.

 class AccessibleRulerState extends AccessibleState {     public static final AccessibleRulerState INCHES                   = new AccessibleRulerState("inches");     public static final AccessibleRulerState CENTIMETERS                   = new AccessibleRulerState("centimeters");     protected AccessibleRulerState(String key) {         super(key);     }     //Should really provide localizable versions of these names.     public String toDisplayString(String resourceBundleName,                                   Locale locale) {         return key;     } } 

You've seen how to implement accessibility for two simple components, which exist only to paint themselves onscreen. Components that do more, such as respond to mouse or keyboard events, need to provide more elaborate accessible contexts. You can find examples of implementing accessible contexts by delving into the source code for the Swing components.

The Accessibility API

Tables 4 through 6 cover just part of the accessibility API. For more information, see the API documentation for the classes and packages in the accessibility package. Also, refer to the API documentation for the accessible contexts for individual Swing components. You can find the javax.accessibility API documentation online at: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/accessibility/package-summary.html.

Table 4. Naming and Linking Components

Method

Purpose

 getAccessibleContext().   setAccessibleName(String) getAccessibleContext().   setAccessibleDescription(String) (  on a  JComponent  or  Accessible  object  ) 

Provide a name or description for an accessible object.

 void setToolTipText(String) (  in  JComponent) 

Set a component's tool tip. If you don't set the description, many accessible contexts use the tool-tip text as the accessible description.

 void setLabelFor(Component) (  in  JLabel) 

Associate a label with a component. This tells assistive technologies that a label describes another component.

 void setDescription(String) (  in  ImageIcon) 

Provide a description for an image icon.

Table 5. Making a Custom Component Accessible

Interface or Class

Purpose

 Accessible (  an interface  ) 

Components that implement this interface are accessible. Subclasses of JComponent must implement it explicitly.

 AccessibleContext JComponent.AccessibleJComponent (  an abstract class and its subclasses  ) 

AccessibleContext defines the minimal set of information required of accessible objects. The accessible context for each Swing component is a subclass of this and named as shown. For example, the accessible context for JTree is JTree.AccessibleJTree . To provide custom accessible contexts, custom components should contain an inner class that is a subclass of AccessibleContext . For more information, see Making Custom Components Accessible (page 529).

 AccessibleRole AccessibleStateSet (  classes  ) 

Define the objects returned by an AccessibleContext object's getAccessibleRole and getAccessibleStateSet methods, respectively.

 AccessibleRelation AccessibleRelationSet (  classes introduced in 1.3  ) 

Define the relations between components that implement this interface and one or more other objects.

Table 6. Accessible Interfaces

Interface

Purpose

AccessibleAction

Indicate that the object can perform actions. By implementing this interface, the accessible context can give information about what actions the accessible object can perform and can tell the accessible object to perform them.

AccessibleComponent

Indicate that the accessible object has an onscreen presence. Through this interface, an accessible object can provide information about its size , position, visibility, and so on. The accessible contexts for all standard Swing components implement this interface, directly or indirectly. The accessible contexts for your custom components should do the same. As of v1.4, AccessibleExtendedComponent is preferred.

 AccessibleEditableText  (introduced in 1.4)  

Indicate that the accessible object displays editable text. In addition to the information available from its superinterface, AccessibleText , methods are provided for cutting, pasting, deleting, selecting, and inserting text.

 AccessibleExtendedComponent  (introduced in 1.4)  

In addition to the information available from its superinterface, AccessibleComponent , methods are provided for obtaining key bindings, border text, and tool-tip text.

 AccessibleExtendedTable  (introduced in 1.4)  

In addition to the information available from its superinterface, AccessibleTable , methods are provided to convert between an index and its row or column.

AccessibleHypertext

Indicate that the accessible object contains hyperlinks. Through this interface, an accessible object can provide information about its links and allow them to be traversed.

 AccessibleIcon  (introduced in 1.3)  

Indicate that the accessible object has an associated icon. Methods are provided that return information about the icon, such as size and description.

 AccessibleKeyBinding  (introduced in 1.4)  

Indicate that the accessible object supports one or more keyboard shortcuts that can be used to select the object. Methods are provided that return the key bindings for a given object.

AccessibleSelection

Indicate that the accessible object can contain a selection. Accessible contexts that implement this interface can report information about the current selection and can modify the selection.

 AccessibleTable  (introduced in 1.3)  

Indicate that the accessible object presents data in a two-dimensional data object. Through this interface information about the table, such as table caption, row and column size, description, and name, are provided. As of v1.4, AccessibleExtendedTable is preferred.

AccessibleText

Indicate that the accessible object displays text. This interface provides methods for returning all or part of the text, attributes applied to it, and other information about the text such as its length.

AccessibleValue

Indicate that the object has a numeric value. Through this interface an accessible object provides information about its current value and its minimum and maximum values.

Examples That Use the Accessibility API

The following table lists some examples that have good support for assistive technologies.

Example

Where Described

Notes

AccessibleScrollDemo

This section

Contains two custom components that implement the Accessible interface. To see a less accessible version of this program refer to How to Use Scroll Panes (page 325).

ButtonDemo

How to Use the Common Button API (page 157)

Uses three buttons. Supports accessibility through button text, mnemonics, and tool tips.

 < Day Day Up > 


JFC Swing Tutorial, The. A Guide to Constructing GUIs
The JFC Swing Tutorial: A Guide to Constructing GUIs (2nd Edition)
ISBN: 0201914670
EAN: 2147483647
Year: 2004
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net