JEditorPane, JScrollPane и специальные возможности - PullRequest
2 голосов
/ 13 июля 2011

У меня есть простое приложение Swing с JEditorPane, обернутым в JScrollPane.

К сожалению, программа для чтения с экрана, такая как JAWS или NVDA , не работает правильно.

Когда фокус входит в JEditorPane, он только читает доступное имя, за которым следует «текст», а затем останавливается, когда ожидаемое поведение должно продолжить чтение содержимого JEditorPane.

Если я не оборачиваю JEditorPane в JScrollPane, он работает как положено.

Я попытался осмотреть доступное дерево с помощью Monkey, но не вижу какой-либо существенной разницы между JEditorPane, обернутым в JScrollPane, и тем, который не обернут.

Есть идеи?

Вот краткий пример, демонстрирующий проблему. Если фокус попадает в первую JEditorPane, JAWS читает «первая панель редактора - редактировать». Если фокус попадает во вторую панель JEditor, JAWS читает «вторая панель редактора - панель редактирования».

public final class SmallExample {
  public static void main(String... aArgs){
    JFrame frame = new JFrame("Test Frame"); 

    JPanel panel = new JPanel();

    JEditorPane editorPane1 = new JEditorPane();
    editorPane1.setText("Foo");
    editorPane1.getAccessibleContext().setAccessibleName("first editorpane");
    editorPane1.getAccessibleContext().setAccessibleDescription("");

    JScrollPane scrollPane = new JScrollPane( editorPane1, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
    panel.add(scrollPane);

    JEditorPane editorPane2 = new JEditorPane();
    panel.add(editorPane2);
    editorPane2.setText("Bar");
    editorPane2.getAccessibleContext().setAccessibleName("second editorpane");
    editorPane2.getAccessibleContext().setAccessibleDescription("");    

    frame.getContentPane().add(panel);      

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}

1 Ответ

2 голосов
/ 14 июля 2011

Я сам нашел обходной путь:

Если я

  1. изменил доступное дерево, чтобы пропустить JScrollPane и JViewPort
  2. , чтобы избежать отправки доступных событий, измененных свойством, изJEditorPane

, затем он работает.

Я все равно буду очень признателен за понимание , почему это работает (я нашел обходной путь, заменив AccessibleContext для editorPane2с одним для editorPane1 и постепенным переключением методов обратно, пока я не нашел те, которые мне нужно было переопределить).

Вот рабочий пример (он уже не так краток):

public final class Example {

  public static void main(String... aArgs){
    JFrame frame = new JFrame("Test Frame"); 

    final JPanel panel = new JPanel(){
        public AccessibleContext getAccessibleContext() {
            if(accessibleContext==null){
                accessibleContext = new AccessibleContextWrapper(super.getAccessibleContext()){
                    public Accessible getAccessibleChild(int i) {
                        Accessible accessibleChild = super.getAccessibleChild(i);
                        while(accessibleChild!=null && (accessibleChild instanceof JScrollPane || accessibleChild instanceof JViewport)){
                            accessibleChild = accessibleChild.getAccessibleContext().getAccessibleChild(0);
                        }
                        return accessibleChild;
                    }
                };
            }
            return accessibleContext;
        }
    };

    final JEditorPane editorPane = new JEditorPane(){
        public AccessibleContext getSuperAccessibleContext() {
            return super.getAccessibleContext();
        }
        @Override
        public AccessibleContext getAccessibleContext() {
            return new AccessibleContextWrapper(super.getAccessibleContext()){
                public Accessible getAccessibleParent() {
                    Accessible parent = super.getAccessibleParent();
                    while(parent!=null && (parent instanceof JScrollPane || parent instanceof JViewport)){
                        parent = parent.getAccessibleContext().getAccessibleParent();
                    }
                    return parent;
                }

                public int getAccessibleIndexInParent() {
                    int res = super.getAccessibleIndexInParent();                           
                    Accessible parent = super.getAccessibleParent();
                    while(parent!=null && (parent instanceof JScrollPane || parent instanceof JViewport)){
                        res = parent.getAccessibleContext().getAccessibleIndexInParent();
                        parent = parent.getAccessibleContext().getAccessibleParent();
                    }
                    return res;
                }

                public void addPropertyChangeListener(
                        PropertyChangeListener listener) {                  
                }

                public void removePropertyChangeListener(
                        PropertyChangeListener listener) {                  
                }           
            };
        }       
    };
    editorPane.setText("Foo");
    editorPane.getAccessibleContext().setAccessibleName("first editorpane");
    editorPane.getAccessibleContext().setAccessibleDescription("");
    editorPane.getAccessibleContext();
    JScrollPane scrollPane = new JScrollPane( editorPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );  

    panel.add(scrollPane);

    frame.getContentPane().add(panel);      

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }

  public static class AccessibleContextWrapper extends AccessibleContext {
    private final AccessibleContext inner;

    public AccessibleContextWrapper(AccessibleContext inner) {
        this.inner = inner;
    }

    public String getAccessibleName() {
        return inner.getAccessibleName();
    }

    public void setAccessibleName(String s) {
        inner.setAccessibleName(s);
    }

    public String getAccessibleDescription() {
        return inner.getAccessibleDescription();
    }

    public void setAccessibleDescription(String s) {
        inner.setAccessibleDescription(s);
    }

    public AccessibleRole getAccessibleRole() {
        return inner.getAccessibleRole();
    }

    public AccessibleStateSet getAccessibleStateSet() {
        return inner.getAccessibleStateSet();
    }

    public Accessible getAccessibleParent() {
        return inner.getAccessibleParent();
    }

    public void setAccessibleParent(Accessible a) {
        inner.setAccessibleParent(a);
    }

    public int getAccessibleIndexInParent() {
        return inner.getAccessibleIndexInParent();
    }

    public int getAccessibleChildrenCount() {
        return inner.getAccessibleChildrenCount();
    }

    public Accessible getAccessibleChild(int i) {
        return inner.getAccessibleChild(i);
    }

    public Locale getLocale() throws IllegalComponentStateException {
        return inner.getLocale();
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        inner.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        inner.removePropertyChangeListener(listener);
    }

    public AccessibleAction getAccessibleAction() {
        return inner.getAccessibleAction();
    }

    public AccessibleComponent getAccessibleComponent() {
        return inner.getAccessibleComponent();
    }

    public AccessibleSelection getAccessibleSelection() {
        return inner.getAccessibleSelection();
    }

    public AccessibleText getAccessibleText() {
        return inner.getAccessibleText();
    }

    public AccessibleEditableText getAccessibleEditableText() {
        return inner.getAccessibleEditableText();
    }

    public AccessibleValue getAccessibleValue() {
        return inner.getAccessibleValue();
    }

    public AccessibleIcon[] getAccessibleIcon() {
        return inner.getAccessibleIcon();
    }

    public AccessibleRelationSet getAccessibleRelationSet() {
        return inner.getAccessibleRelationSet();
    }

    public AccessibleTable getAccessibleTable() {
        return inner.getAccessibleTable();
    }

    public void firePropertyChange(String propertyName, Object oldValue,
            Object newValue) {
        inner.firePropertyChange(propertyName, oldValue, newValue);
    }
  }

}
...