gpt4 book ai didi

java - 为什么我的 JTable 在 OS X 上使用 VoiceOver 时总是报告为空?

转载 作者:搜寻专家 更新时间:2023-11-01 03:02:41 25 4
gpt4 key购买 nike

VoiceOver在 OSX 10.10.4 (Yosemite) 上,使用 JRE 1.7.0_75 和 JRE 1.8.0_45,将下表报告为“空”。

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();
}
});
}
}

除了 VoiceOver 说 table 是空的,其他一切似乎都正常:

我错过了什么?

更多信息:

  • 我试过使用 JRE 1.6.0_65,这是 Apple 提供的 JRE,但我遇到了同样的问题。我试过这个,以防在迁移到 Oracle 提供的 JRE 时它发生了变化。

最佳答案

VoiceOver 说“空”的原因是 accessibility hierarchy未正确曝光。您可以使用辅助功能检查器工具(Xcode 开发人员工具之一)来检查辅助功能层次结构。在这种情况下,在辅助功能检查器工具运行的情况下,将鼠标指针悬停在 JTable 上会显示有一个 AXTable 元素和 10 个 AXStaticText 子元素(每个单元格一个)。表应公开为 AXTable > AXRow > AXCell > …。此外,根据 Roles reference , AXTable 元素应具有 Rows 属性以及其他必需属性,但 JRE 尚未将这些属性公开给可访问性层次结构。

我已经使用 Java 1.8.0_51 在 Windows 8.1 Pro 上试用了您的程序,我看到了类似的问题。与辅助功能检查器工具类似,Windows SDK 附带一个 Inspect tool可用于检查可访问性数据。运行测试用例时,JTable 似乎根本没有公开。启用 Windows 讲述人后,我无法导航到表格或其单元格。

因此,JRE 似乎并不完全支持表可访问性。

source of javax.accessibility.AccessibleRole ,您可以看到定义 ROW 常量的代码与其他常量一起被注释掉,这些常量被记录为“正在考虑 future 的潜在用途”。

source of JTable ,您可以看到定义了 AccessibleJTableAccessibleTableHeaderAccessibleJTableCellAccessibleJTableHeaderCell 辅助类,但是没有t 表格行的 Accessible 实现。

理论上,您可以编写一个自定义的 AccessibleContext 实现,该实现将用于向操作系统公开 JTable 的更完整的可访问性层次结构。但是,我不确定是否有可能完全解决 Java 明显缺乏对表可访问性的支持。

这是否可能取决于平台。例如,检查 source code of src/macosx/native/sun/awt/JavaAccessibilityUtilities.m ,您可以看到 Java 的可访问性角色是如何映射到 NSAccessibility*Role 常量的。你可以看到 ROW_HEADER accessible role映射到 AXRow。因此,您可以使用 ROW_HEADER 可访问角色公开 AXTable 的 AXRow 子级。下面是一些成功执行此操作的代码:

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 is used because it maps to 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 the number of columns in this row
}
@Override
public Accessible getAccessibleChild(int i) {
return null; // TODO return a 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
}
}
}

从这个截图可以看出:

Screenshot showing the sample code with Accessibility Inspector running

.. AXTable 上现在有两个 AXRow 子项。但是,VoiceOver 仍然宣布该表为“空”。我不确定这是因为这些行没有 AXCell 子行,还是因为 AXTable 缺少其必需的属性,还是其他一些原因。

如果您要采用自定义 AccessibleContext 路线,最好完全避免尝试公开表层次结构。相反,您可以将表格建模为列表,其中每一行对应一个列表项,并且每个列表项都包含每个单元格的一个组。这类似于 Firefox(已测试版本 39.0)使用的方法。目前在 Mac 上,Firefox 在公开 HTML 表格时不使用表格角色。不过,这应该在 Firefox 41 中得到修复。参见 Bug 744790 - [Mac] HTML table semantics are not communicated to VoiceOver at all .

我还在使用 Mac OS 10.10.4 和 Java 1.8.0_51。

编辑:“空”表问题已报告为 OpenJDK Bug JDK-7124284 [macosx] Nothing heard from VoiceOver when navigating in a table .从评论中可以看出,Mac Swing 可访问性存在几个已知问题,目前已推迟到 JDK 9。

另一种可能的解决方法是使用 JavaFX TableView 类。试用 http://docs.oracle.com/javafx/2/ui_controls/table-view.htm 中的 TableView 示例我看到 VoiceOver 正确地宣布了表格。 JavaFX 可访问性是作为 JEP 204 的一部分实现的这是在 Java 8u40 中实现的。

关于java - 为什么我的 JTable 在 OS X 上使用 VoiceOver 时总是报告为空?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31656339/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com