java - Why is my JTable always reported as empty using VoiceOver on OS X? -


voiceover on osx 10.10.4 (yosemite), using jre 1.7.0_75 , jre 1.8.0_45, reports following table "empty".

package stackoverflow.examples.jtable;  import javax.swing.jframe; import javax.swing.jtable; import javax.swing.swingutilities;  public class tabledemo extends jframe {     private static final long serialversionuid = 1l;      public tabledemo()     {         super("accessible jtable?");          final string[] columnnames =              {                 "first name",                 "last name",                 "sport",                 "# of years",                 "vegetarian"             };         final object[][] data =              {                 {"kathy", "smith", "snowboarding", new integer(5), new boolean(false)},                 {"john", "doe", "rowing", new integer(3), new boolean(true)},             };          final jtable jtable = new jtable(data, columnnames);         jtable.getaccessiblecontext().setaccessiblename("data table");         system.out.println("rows: " + jtable.getaccessiblecontext().getaccessibletable().getaccessiblerowcount());         system.out.println("cols: " + jtable.getaccessiblecontext().getaccessibletable().getaccessiblecolumncount());         system.out.println("java: " + system.getproperty("java.version"));         jtable.setopaque(true);         setcontentpane(jtable);     }      private static void createandshowgui()      {         final tabledemo frame = new tabledemo();         frame.pack();         frame.setvisible(true);     }      public static void main(string[] args)     {         swingutilities.invokelater(new runnable()         {             @override             public void run()             {                 createandshowgui();             }         });     } } 

apart voiceover saying table empty, else seems ok:

what missing?

further info:

  • i've tried using jre 1.6.0_65 apple supplied jre , same issue. tried in case changed when moving oracle supplied jre.

the reason why voiceover says "empty" because accessibility hierarchy not being exposed correctly. can use accessibility inspector tool (one of xcode developer tools) examine accessibility hierarchy. in case, accessibility inspector tool running, hovering mouse pointer on jtable shows there axtable element 10 axstatictext children (one each of cells). tables should exposed axtable > axrow > axcell > … . also, according roles reference, axtable element should have rows attribute among other required attributes, these have not been exposed accessibility hierarchy jre.

i have tried out program on windows 8.1 pro using java 1.8.0_51 , see similar problem. similar accessibility inspector tool, windows sdk comes inspect tool can used inspect accessibility data. when running test case, appears jtable has not been exposed @ all. enabling windows narrator, unable navigate table or cells.

so, appears jre not support table accessibility.

in source of javax.accessibility.accessiblerole, can see code define row constant commented out along other constants documented "under consideration potential future use".

in source of jtable, can see accessiblejtable, accessibletableheader, accessiblejtablecell, , accessiblejtableheadercell helper classes defined, there isn't accessible implementation rows of table.

in theory write custom accessiblecontext implementation operate expose more complete accessibility hierarchy jtable os. however, not sure whether possible work around java's apparent lack of support table accessibility.

whether possible might depend on platform. example, examining source code of src/macosx/native/sun/awt/javaaccessibilityutilities.m, can see how java's accessibility roles mapped nsaccessibility*role constants. can see row_header accessible role mapped axrow. thus, expose axrow children of axtable using row_header accessible role. here code succeeds in doing this:

public static class myjtable extends jtable {     public myjtable(tablemodel tm) {         super(tm);     }      @override     public myaccessiblejtable getaccessiblecontext() {         if (accessiblecontext == null) {             accessiblecontext = new myaccessiblejtable();         }         return (myaccessiblejtable)accessiblecontext;     }      protected class myaccessiblejtable extends accessiblejtable {          @override         public int getaccessiblechildrencount() {             if (myjtable.this.getcolumncount() <= 0) {                 return 0;             }             return myjtable.this.getrowcount();         }          @override         public accessible getaccessiblechild(int i) {             if (i < 0 || getaccessiblechildrencount() <= i) {                 return null;             }             tablecolumn firstcolumn = getcolumnmodel().getcolumn(0);             tablecellrenderer renderer = firstcolumn.getcellrenderer();             if (renderer == null) {                 class<?> columnclass = getcolumnclass(0);                 renderer = getdefaultrenderer(columnclass);             }             component component = renderer.gettablecellrenderercomponent(myjtable.this, null, false, false, i, 0);             return new myaccessiblerow(myjtable.this, i, component);         }     }      protected static class myaccessiblerow extends accessiblecontext implements accessible {         private myjtable table;         private int row;         private component renderercomponent;          protected myaccessiblerow(myjtable table, int row, component rendercomponent) {             this.table = table;             this.row = row;             this.renderercomponent = renderercomponent;         }          @override         public accessiblerole getaccessiblerole() {             // row_header used because maps nsaccessibilityrowrole             // on mac.             return accessiblerole.row_header;         }          @override         public locale getlocale() {             accessiblecontext ac = renderercomponent.getaccessiblecontext();             if (ac != null) {                 return ac.getlocale();             } else {                 return null;             }         }          @override         public int getaccessiblechildrencount() {             return 0; // todo return number of columns in row         }         @override         public accessible getaccessiblechild(int i) {             return null; // todo return myaccessiblejtablecell         }         @override         public int getaccessibleindexinparent() {             return row;         }         @override         public accessiblestateset getaccessiblestateset() {             return null; // todo         }         @override         public accessiblecontext getaccessiblecontext() {             return this; // todo         }         @override         public accessiblecomponent getaccessiblecomponent() {             return table.getaccessiblecontext(); // todo         }     } } 

as can see screenshot:

screenshot showing sample code accessibility inspector running

.. there 2 axrow children on axtable. however, voiceover still announces table "empty". not sure whether because rows not have axcell children, or because axtable missing required attributes, or other reason.

if go custom accessiblecontext route, better avoid trying expose table hierarchy. instead, model table list, each row corresponds list item, , each list item contains group each of cells. similar approach used firefox (tested version 39.0). on mac, firefox not use table role when exposing html table. should fixed in firefox 41, though. see bug 744790 - [mac] html table semantics not communicated voiceover @ all.

i using mac os 10.10.4 , java 1.8.0_51.

edit: "empty" table issue has been reported openjdk bug jdk-7124284 [macosx] nothing heard voiceover when navigating in table. comments, there several known issues mac swing accessibility deferred jdk 9.

another possible work around use javafx tableview class. trying out tableview sample http://docs.oracle.com/javafx/2/ui_controls/table-view.htm seeing voiceover announcing table. javafx accessibility implemented part of jep 204 implemented in java 8u40.


Comments

Popular posts from this blog

yii2 - Yii 2 Running a Cron in the basic template -

asp.net - 'System.Web.HttpContext' does not contain a definition for 'GetOwinContext' Mystery -

mercurial graft feature, can it copy? -