Skip to main content

5.0 Building Custom Accessible Components



5.0 Building Custom Accessible Components
This is a very extensive topic incorporating all of the accessibility features in this document. Therefore this section is meant as an introduction to building custom accessible components.

All JFC component classes which can be rendered in final form implement the Accessible interface and are accessible. An example of a final form JFC component class is JButton.

Important: extending JComponent to build a custom component does not allow you to automatically become an accessible component since JComponent does not implement Accessible. JComponent is considered a base class from which you would build a final form GUI component and implement the Accessible interface.

As you will see, extending a JComponent to build an accessible component does have time-saving benefits.


5.1 Start with a Base Component

5.1.1 Starting with JFC's JComponent as a Base
If you begin by extending the JFC JComponent class you pick up partial accessibility support by inheriting its internal protected abstract class AccessibleJComponent. AccessibleJComponent subclasses AccessibleAWTContainer which, through the class hierarchy, extends AccessibleContext and implements AccessibleComponent from java.awt.Component's protected internal class AccessibleAWTComponent in Java 1.3. This allows you to pick up basic accessible component features such as foreground and background color as well as the firing of basic component state change information such as for AccessibleState.VISIBLE.

Your next task will be to implement Accessible on your new component.

 class MyComponent extends JComponent, implements Accessible {
   AccessibleContext getAccessibleContext() {
      return new MyAccessible();
   }
      ...
   MyAccessible extends AccessibleJComponent {
      ...
   }
 }

Figure 1.3 JFC JComponent Base for Accessible

5.1.2 Starting with an AWT Component
If you would like to create a new GUI framework from AWT rather than JFC you will then need to create a new base class similar to JComponent and extend from that as shown in this example.

 class BaseComponent extends Component {
     //Note: AccessibleAWTComponent extends
     //AccessibleContext and implements AccessibleComponent
     protected AccessibleBaseComponent extends 
                              AccessibleAWTComponent {
      ...
     }
 }
 class CustomComponent1 extends BaseComponent {
   AccessibleContext getAccessibleContext() {
      return new MyAccessible();
   }
      ...
   MyAccessible extends AccessibleBaseComponent {
      ...
   }
 }

Figure 1.4 AWT Component Base for Accessible


5.2 Implement the Accessibility API based on Role
The Java Accessibility API provides a pre-defined set of AccessibleRoles. The role you select should determine the following:


5.3 Managing Children
There are two types of children you can have in any GUI application. One is a "live" child, created by adding a component to a container in the AWT framework. These live children operate as separate entities and respond to events propagated by the AWT component hierarchy.

The second type of child is drawn and managed by the parent in an effort to save system resources. Here, the parent is a "proxy" for its child. This lightweight, proxied child is usually a transient object. A typical proxied child would be a list box entry. A list box could have 100 items in it and you would not want to have the overhead of creating a live child for each item. So, proxied children are manufactured and drawn by their parent from the list boxes data as needed.

An example of this is JFC's implementation of cell renderers for list box. In a JFC list box, each list entry is created through the use of a single ListCellRenderer. The JList component tells the renderer where to draw, when to "appear" selected, and so on. The JList component does not care what the cell renderer draws in it as long as the renderer does what it is told. The cell render does not receive focus from the windowing system, even though JList may ask it to appear focused. If you are familiar with X Window System programming, you should recognize these lightweight objects as similar to "gadgets."

The JFC JTabbedPane component presents a different parent/child relationship that might best be described as a limited proxy. In the case of notebook page tabs, you know you will be dealing with a limited number of children. Here, the tabs are not actually components, but merely visual page tab elements with a reference to the component to be shown, based on the page tab selected. Because the list of elements is small, and generally persistent, it is easier to maintain a vector of accessible objects representing each page tab. When assistive technology requests an accessible child, JTabbedPane merely goes to the internal vector of accessible page tab objects and returns the corresponding object.

For each case the parent component should be a live component and the parent should report its accessible children. In JFC, live children support is provided by default. For all other cases, the parent component should implement getAccessibleChild and getAccessibleChildCount. For proxied children this information should be derived from the data used to create the children.

Here are some basic rules to follow when managing children:

5.3.1 Managing Events
Since live children need to be available to receive events, they are are also available to fire events, such as accessible state change events, needed by an assistive technology. However, unlike live children, proxied children are usually transient and therefore an assistive technology would not be able to receive any events from them. Therefore, all accessibility events pertaining to the proxied children (see section 6.2.4 Property Change Notification) should be generated from the proxying parent.

5.3.2 Managing Selection
Assistive technologies need to know what is selected in order to properly present information to the user. For text components the selected text is provided for by the accessible text interface. The following selection rules should be adhered to by a proxying parent:

5.3.3 List Box Proxy Example
This section provides an example of how the JFC JList component implements parts of the accessibility API by acting as a proxy for its child elements. This task for this example is to provide the JList AccessibleRole, number of accessible children, and the accessible name for a given child.

Picture of a JList D

Figure 1.5: JList characteristics:

The code fragment in figure 1.6 AccessibleJList shows how JList extends from JComponent and implements the Accessible interface. Since JList uses JComponent as it base it can create its own internal class, AccessibleJList, which extends from JComponent's AccessibleJComponent. As discussed in section 5.1 Start with a Base Component, AccessibleJlist now picks up the AccessibleContext and AccessibleComponent support provided by JComponent. The Accessible method, getAccessibleContext, returns a new instance of AccessibleJList.

The next tasks to be formed are to return the role and number of children information. The method getAccessibleRole() will return AccessibleRole.LIST and getAccessibleChildCount() will return the size of the list model which is the number of elements in the list. See Figure 1.6 AccessibleJList.

 public class JList extends JComponent  implements Accessible
  {
   public AccessibleContext getAccessibleContext() {
       return new AccessibleJList;
   }
   protected class AccessibleJList extends 
       AccessibleJComponent implements AccessibleSelection,
       PropertyChangeListener, ListSelectionListener, 
       ListDataListener {
       AccessibleSelection  {
       public AccessibleRole getAccessibleRole() {
           return AccessibleRole.LIST;
       }
       public int getAccessibleChildrenCount() {
           return getModel().getSize(); // Get From Data Model
       }
       public Accessible getAccessibleChild(int i) {
               return new AccessibleJListChild(JList.this, i);
       }
       public AccessibleSelection() {
               return this;
       }
       .
       .
       .
  }
  // Internal Class Configures an Accessible Child from 
  // a JList index
  protected class AccessibleJListChild {
     See next code sample.
  }
 }

FIGURE 1.6 AccessibleJList

The next step will be to determine the AccessibleName of the zeroth child. To do this we need to get the Accessible child for this element and acquire the AccessibleName from it. To do this we will provide another internal class AccessibleJListChild whose responsibility will be to configure the listCellRender for a given list model element and return an Accessible object. See figure 1.7 JLIst key elements used to implement Accessible.

Image showing JList key elements used to implement Accessible D

Figure 1.7 JList key elements used to implement Accessible

Figure 1.7 shows the key elements used to support the accessible interface. The diagram shows the JList selection model which is used to create AccessibleSelection. It shows the list model whose size determines the number of elements in the list and whose elements that are used to configure the list cell renderer to produce an accessible component which will be the accessible child created by the JList proxy. The diagram also indicates that JList impements Accessible.

To get the accessible name of a child we must first, as a proxy, create an AccessibleChild which will be based on internal class AccessibleJList. Its constructor is passed a reference to the JList and an element index used to determine which element in the list model must be passed to the cell renderer to acquire the accessible child component. From this information the constructor stores the JList parent list model, its cell renderer, and the child index called indexInParent. AccessibleJListChild implements Accessible and can be returned to the caller for a given child, in our case the zeroth child. See Figure 1.8 AccessibleJListChild.

An assistive technology, such as a screen reader program, would then query AccessibleJListChild for its accessible name. To get the AccessibleName the AccessibleContext for the child must be determined by accquiring the zeroth element from the list model which will return an object. This object must then be passed to the ListCellRenderer for configuration.

The ListCellRenderer provides a method, getListCellRenderComponent, which will return a component based on the object and other configuration data. By accessible design of JFC components, see section 4.4 Changing Data Models and Cell Renderers, the component returned must be an Accessible object. By default, JList uses JLabels for child elements that implement Accessible. From the Accessible object we can get the AccessibleContext for the child.

From the AccessibleContext we can get the AccessibleName. For the zeroth element this would be "Burger $1.99."

 protected class AccessibleJListChild
              extends AccessibleContext
              implements Accessible, AccessibleComponent {
         ...
     public AccessibleJListChild(JList parent, 
                            int indexInParent) {
         listModel = parent.getModel();
         cellRenderer = parent.getCellRenderer();
         this.indexInParent = indexInParent;
     }
     private AccessibleContext getCurrentAccessibleContext() {
         Component c = getComponentAtIndex(indexInParent);
         return ((Accessible) c).getAccessibleContext();
     }
     public String getAccessibleName() {
         AccessibleContext ac = getCurrentAccessibleContext();
         return ac.getAccessibleName();
     }
     // Configure the Cell Renderer for a given List
     // Item Index and return the Component
     private Component getComponentAtIndex(int index) {
         Object value = listModel.getElementAt(index);
         //The cellRenderer should return an Accessible
         //Component
     return 
        cellRenderer.getListCellRendererComponent(Object,...);
     }
     private AccessibleContext getCurrentAccessibleContext() {
         Component c = getComponentAtIndex(indexInParent);
         return ((Accessible) c).getAccessibleContext();
     }
 }

FIGURE 1.8 AccessibleJListChild


5.4 Peered Objects
Peered objects translate to GUI objects in the underlying operating system. For example, most AWT components fall into this category; an AWT button translates to a button on the underlying Windows operating system. It will be very difficult, perhaps impossible, without help from both the Java side and the underlying operating system to make peered objects accessible on the Java side.

In most instances, the data does not reside on the Java side of the wall. In the case of Windowstm or OS/2tm, it means that you need to provide numerous methods to get the data back to the Java side of the wall from the native DLL. This may be simple for small items like labels and buttons, but for more complex items like file dialogs and WYSIWIG documents, it is a difficult task.

The most expedient solution is to use JFC and not peered objects.


5.5 Menus
Menus are usually the most specialized part of a GUI application due to performance issues and constant access by the user. They are often the most distinguishing features of a GUI environment. This means they are usually treated as a special case item by assistive technologies. If you decide to use a new menuing system, you probably will no longer work with assistive technology.

Important: Use JFC's menu components. Assistive technologies are familiar with them.


5.6 Text Components
Using JFC's JTextComponent is ideal, but implementing AccessibleText on components like these is a minimum. This is especially important for editable text areas.


5.7 Tips
When determining how to implement code, it is always good to see how someone else accomplished the task. The JFC comes complete with source. Because the JFC has implemented the Accessibility API, in most cases, this is an excellent place to start. Furthermore, the JFC also includes the Accessibility API source.

JFC
JFC Component Type of Example
JList Example of a Proxying component for a list of Accessible Children.
JTextComponent, JEditorPane Examples of AccessibleText and AccessibleText implementation for presenting HTML text.
JLabel Simple implemenation of the Accessibility API.
JProgressBar Implementation of AccessibleValue.
JComponent AccessibleJComponent internal class implementation of the AccessibleContext abstract class.
AbstractButton Implementation of AccessibleAction for activating a JFC button.

Table 20: Example Accessibility API Implementations



5.0 Building Custom Accessible Components
This is a very extensive topic incorporating all of the accessibility features in this document. Therefore this section is meant as an introduction to building custom accessible components.

All JFC component classes which can be rendered in final form implement the Accessible interface and are accessible. An example of a final form JFC component class is JButton.

Important: extending JComponent to build a custom component does not allow you to automatically become an accessible component since JComponent does not implement Accessible. JComponent is considered a base class from which you would build a final form GUI component and implement the Accessible interface.

As you will see, extending a JComponent to build an accessible component does have time-saving benefits.


5.1 Start with a Base Component

5.1.1 Starting with JFC's JComponent as a Base
If you begin by extending the JFC JComponent class you pick up partial accessibility support by inheriting its internal protected abstract class AccessibleJComponent. AccessibleJComponent subclasses AccessibleAWTContainer which, through the class hierarchy, extends AccessibleContext and implements AccessibleComponent from java.awt.Component's protected internal class AccessibleAWTComponent in Java 1.3. This allows you to pick up basic accessible component features such as foreground and background color as well as the firing of basic component state change information such as for AccessibleState.VISIBLE.

Your next task will be to implement Accessible on your new component.

 class MyComponent extends JComponent, implements Accessible {
   AccessibleContext getAccessibleContext() {
      return new MyAccessible();
   }
      ...
   MyAccessible extends AccessibleJComponent {
      ...
   }
 }

Figure 1.3 JFC JComponent Base for Accessible

5.1.2 Starting with an AWT Component
If you would like to create a new GUI framework from AWT rather than JFC you will then need to create a new base class similar to JComponent and extend from that as shown in this example.

 class BaseComponent extends Component {
     //Note: AccessibleAWTComponent extends
     //AccessibleContext and implements AccessibleComponent
     protected AccessibleBaseComponent extends 
                              AccessibleAWTComponent {
      ...
     }
 }
 class CustomComponent1 extends BaseComponent {
   AccessibleContext getAccessibleContext() {
      return new MyAccessible();
   }
      ...
   MyAccessible extends AccessibleBaseComponent {
      ...
   }
 }

Figure 1.4 AWT Component Base for Accessible


5.2 Implement the Accessibility API based on Role
The Java Accessibility API provides a pre-defined set of AccessibleRoles. The role you select should determine the following:


5.3 Managing Children
There are two types of children you can have in any GUI application. One is a "live" child, created by adding a component to a container in the AWT framework. These live children operate as separate entities and respond to events propagated by the AWT component hierarchy.

The second type of child is drawn and managed by the parent in an effort to save system resources. Here, the parent is a "proxy" for its child. This lightweight, proxied child is usually a transient object. A typical proxied child would be a list box entry. A list box could have 100 items in it and you would not want to have the overhead of creating a live child for each item. So, proxied children are manufactured and drawn by their parent from the list boxes data as needed.

An example of this is JFC's implementation of cell renderers for list box. In a JFC list box, each list entry is created through the use of a single ListCellRenderer. The JList component tells the renderer where to draw, when to "appear" selected, and so on. The JList component does not care what the cell renderer draws in it as long as the renderer does what it is told. The cell render does not receive focus from the windowing system, even though JList may ask it to appear focused. If you are familiar with X Window System programming, you should recognize these lightweight objects as similar to "gadgets."

The JFC JTabbedPane component presents a different parent/child relationship that might best be described as a limited proxy. In the case of notebook page tabs, you know you will be dealing with a limited number of children. Here, the tabs are not actually components, but merely visual page tab elements with a reference to the component to be shown, based on the page tab selected. Because the list of elements is small, and generally persistent, it is easier to maintain a vector of accessible objects representing each page tab. When assistive technology requests an accessible child, JTabbedPane merely goes to the internal vector of accessible page tab objects and returns the corresponding object.

For each case the parent component should be a live component and the parent should report its accessible children. In JFC, live children support is provided by default. For all other cases, the parent component should implement getAccessibleChild and getAccessibleChildCount. For proxied children this information should be derived from the data used to create the children.

Here are some basic rules to follow when managing children:

5.3.1 Managing Events
Since live children need to be available to receive events, they are are also available to fire events, such as accessible state change events, needed by an assistive technology. However, unlike live children, proxied children are usually transient and therefore an assistive technology would not be able to receive any events from them. Therefore, all accessibility events pertaining to the proxied children (see section 6.2.4 Property Change Notification) should be generated from the proxying parent.

5.3.2 Managing Selection
Assistive technologies need to know what is selected in order to properly present information to the user. For text components the selected text is provided for by the accessible text interface. The following selection rules should be adhered to by a proxying parent:

5.3.3 List Box Proxy Example
This section provides an example of how the JFC JList component implements parts of the accessibility API by acting as a proxy for its child elements. This task for this example is to provide the JList AccessibleRole, number of accessible children, and the accessible name for a given child.

Picture of a JList D

Figure 1.5: JList characteristics:

The code fragment in figure 1.6 AccessibleJList shows how JList extends from JComponent and implements the Accessible interface. Since JList uses JComponent as it base it can create its own internal class, AccessibleJList, which extends from JComponent's AccessibleJComponent. As discussed in section 5.1 Start with a Base Component, AccessibleJlist now picks up the AccessibleContext and AccessibleComponent support provided by JComponent. The Accessible method, getAccessibleContext, returns a new instance of AccessibleJList.

The next tasks to be formed are to return the role and number of children information. The method getAccessibleRole() will return AccessibleRole.LIST and getAccessibleChildCount() will return the size of the list model which is the number of elements in the list. See Figure 1.6 AccessibleJList.

 public class JList extends JComponent  implements Accessible
  {
   public AccessibleContext getAccessibleContext() {
       return new AccessibleJList;
   }
   protected class AccessibleJList extends 
       AccessibleJComponent implements AccessibleSelection,
       PropertyChangeListener, ListSelectionListener, 
       ListDataListener {
       AccessibleSelection  {
       public AccessibleRole getAccessibleRole() {
           return AccessibleRole.LIST;
       }
       public int getAccessibleChildrenCount() {
           return getModel().getSize(); // Get From Data Model
       }
       public Accessible getAccessibleChild(int i) {
               return new AccessibleJListChild(JList.this, i);
       }
       public AccessibleSelection() {
               return this;
       }
       .
       .
       .
  }
  // Internal Class Configures an Accessible Child from 
  // a JList index
  protected class AccessibleJListChild {
     See next code sample.
  }
 }

FIGURE 1.6 AccessibleJList

The next step will be to determine the AccessibleName of the zeroth child. To do this we need to get the Accessible child for this element and acquire the AccessibleName from it. To do this we will provide another internal class AccessibleJListChild whose responsibility will be to configure the listCellRender for a given list model element and return an Accessible object. See figure 1.7 JLIst key elements used to implement Accessible.

Image showing JList key elements used to implement Accessible D

Figure 1.7 JList key elements used to implement Accessible

Figure 1.7 shows the key elements used to support the accessible interface. The diagram shows the JList selection model which is used to create AccessibleSelection. It shows the list model whose size determines the number of elements in the list and whose elements that are used to configure the list cell renderer to produce an accessible component which will be the accessible child created by the JList proxy. The diagram also indicates that JList impements Accessible.

To get the accessible name of a child we must first, as a proxy, create an AccessibleChild which will be based on internal class AccessibleJList. Its constructor is passed a reference to the JList and an element index used to determine which element in the list model must be passed to the cell renderer to acquire the accessible child component. From this information the constructor stores the JList parent list model, its cell renderer, and the child index called indexInParent. AccessibleJListChild implements Accessible and can be returned to the caller for a given child, in our case the zeroth child. See Figure 1.8 AccessibleJListChild.

An assistive technology, such as a screen reader program, would then query AccessibleJListChild for its accessible name. To get the AccessibleName the AccessibleContext for the child must be determined by accquiring the zeroth element from the list model which will return an object. This object must then be passed to the ListCellRenderer for configuration.

The ListCellRenderer provides a method, getListCellRenderComponent, which will return a component based on the object and other configuration data. By accessible design of JFC components, see section 4.4 Changing Data Models and Cell Renderers, the component returned must be an Accessible object. By default, JList uses JLabels for child elements that implement Accessible. From the Accessible object we can get the AccessibleContext for the child.

From the AccessibleContext we can get the AccessibleName. For the zeroth element this would be "Burger $1.99."

 protected class AccessibleJListChild
              extends AccessibleContext
              implements Accessible, AccessibleComponent {
         ...
     public AccessibleJListChild(JList parent, 
                            int indexInParent) {
         listModel = parent.getModel();
         cellRenderer = parent.getCellRenderer();
         this.indexInParent = indexInParent;
     }
     private AccessibleContext getCurrentAccessibleContext() {
         Component c = getComponentAtIndex(indexInParent);
         return ((Accessible) c).getAccessibleContext();
     }
     public String getAccessibleName() {
         AccessibleContext ac = getCurrentAccessibleContext();
         return ac.getAccessibleName();
     }
     // Configure the Cell Renderer for a given List
     // Item Index and return the Component
     private Component getComponentAtIndex(int index) {
         Object value = listModel.getElementAt(index);
         //The cellRenderer should return an Accessible
         //Component
     return 
        cellRenderer.getListCellRendererComponent(Object,...);
     }
     private AccessibleContext getCurrentAccessibleContext() {
         Component c = getComponentAtIndex(indexInParent);
         return ((Accessible) c).getAccessibleContext();
     }
 }

FIGURE 1.8 AccessibleJListChild


5.4 Peered Objects
Peered objects translate to GUI objects in the underlying operating system. For example, most AWT components fall into this category; an AWT button translates to a button on the underlying Windows operating system. It will be very difficult, perhaps impossible, without help from both the Java side and the underlying operating system to make peered objects accessible on the Java side.

In most instances, the data does not reside on the Java side of the wall. In the case of Windowstm or OS/2tm, it means that you need to provide numerous methods to get the data back to the Java side of the wall from the native DLL. This may be simple for small items like labels and buttons, but for more complex items like file dialogs and WYSIWIG documents, it is a difficult task.

The most expedient solution is to use JFC and not peered objects.


5.5 Menus
Menus are usually the most specialized part of a GUI application due to performance issues and constant access by the user. They are often the most distinguishing features of a GUI environment. This means they are usually treated as a special case item by assistive technologies. If you decide to use a new menuing system, you probably will no longer work with assistive technology.

Important: Use JFC's menu components. Assistive technologies are familiar with them.


5.6 Text Components
Using JFC's JTextComponent is ideal, but implementing AccessibleText on components like these is a minimum. This is especially important for editable text areas.


5.7 Tips
When determining how to implement code, it is always good to see how someone else accomplished the task. The JFC comes complete with source. Because the JFC has implemented the Accessibility API, in most cases, this is an excellent place to start. Furthermore, the JFC also includes the Accessibility API source.

JFC
JFC Component Type of Example
JList Example of a Proxying component for a list of Accessible Children.
JTextComponent, JEditorPane Examples of AccessibleText and AccessibleText implementation for presenting HTML text.
JLabel Simple implemenation of the Accessibility API.
JProgressBar Implementation of AccessibleValue.
JComponent AccessibleJComponent internal class implementation of the AccessibleContext abstract class.
AbstractButton Implementation of AccessibleAction for activating a JFC button.

Table 20: Example Accessibility API Implementations