gpt4 book ai didi

java - JavaFX "console"输出的可访问屏幕阅读

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:25:32 24 4
gpt4 key购买 nike

我正在尝试创建一个可供屏幕阅读器访问的简单 UI。我基本上是成功的,但我无法以让屏幕阅读器读取新文本输出的方式设计 UI。

目前,我有一个 TextArea 显示由 System.setOut 创建和设置的匿名 PrintStream 的输出。有时我会打开一个 TextField 用于字符串输入,但我一直只使用 TextArea 来测试文本的阅读(目前它只是监听要显示的击键更多文本用于测试目的)。

问题是这样的:当新文本通过 System.out 添加到 TextArea 时,屏幕阅读器不会读取它。我仍然可以使用箭头键向上导航以阅读添加的内容,但在首次添加时不会阅读。有什么方法可以让屏幕阅读器更像一个标准控制台(它会自动读取所有新文本)来处理我的 TextArea 吗?我正在使用 NVDA。

我尝试过的事情:
- 使用 TextArea.notifyAccessibleAttributeChanged(AccessibleAttribute.TEXT)
- 使用 TextArea.requestFocus()TextArea.notifyAccessibleAttributeChanged(AccessibleAttribute.FOCUS_NODE)
- 在刷新期间使用 TextArea.setAccessibleText(theNewText) 时禁用 PrintStream 上的自动刷新
- 使用隐藏的 Label 设置为新文本并专注于它(我还在摆弄这个;屏幕阅读器无法阅读实际的“隐藏”文本,所以我正在尝试找到一种方法绘制它但也是“不可见的”,也许在 TextArea 后面)
- 将焦点切换到另一个 Node 并返回,这并不像我喜欢的那样工作,因为它读取其他 Node 的可访问内容,然后读取 的整个主体>文本区域
- 这些的各种组合

我似乎无法让它工作。我觉得我在这里遗漏了一些简单而明显的东西,但 JavaFX Accessibility API 仍然相对较新,我找不到针对此类特定问题的解决方案。

这是我的应用程序的相关代码,如果有帮助的话:

@Override
public void start(Stage primaryStage) {
try {
primaryStage.setTitle("Test");
root = new BorderPane();
root.setFocusTraversable(false);
Scene scene = new Scene(root,800,600);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
//Create middle
output = new TextArea();
output.setEditable(false);
output.setFocusTraversable(false); //I've tried true also, just to test
output.setAccessibleRole(AccessibleRole.TEXT_AREA);
root.setCenter(output);
...
//Begin
primaryStage.show();
Thread th = new Thread(new AppMain());
th.start();
} catch(Exception e) {
e.printStackTrace();
}
}

@Override
public void init() {
//Set output to TextArea
System.setOut(new PrintStream(new OutputStream() {
@Override
public void write(int b) throws IOException {
appendTextArea(String.valueOf((char) b));
}
}, true)); //I've also overriden flush while this is false, see above
}

public void appendTextArea(String str) {
Platform.runLater(() -> {
output.appendText(str);
});
}

非常感谢您提供的任何帮助或建议。这个小问题困扰我太久了,我对 JavaFX 还是个新手。谢谢!

最佳答案

这是一个基于您的代码的完整工作示例。

披露:对于屏幕阅读器,我在我的 Mac 上使用“Voice Over Utility”,但希望这与您的环境没有太大差异。

关键是利用 Control#executeAccessibleAction方法。

示例:

TextArea.executeAccessibleAction(AccessibleAction.SET_TEXT_SELECTION, start, finish);

应用类

package application;

import java.io.PrintStream;
import java.io.IOException;
import java.io.OutputStream;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Stage;
import javafx.scene.AccessibleAction;
import javafx.scene.AccessibleRole;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;

public class Main extends Application
{
private TextArea output;
private BorderPane root;

private final StringBuilder STR_BUFFER = new StringBuilder();
private static final String NEW_LINE = System.lineSeparator();

@Override
public void start(Stage primaryStage)
{
try
{
primaryStage.setTitle("Test");
root = new BorderPane();
root.setFocusTraversable(false);
Scene scene = new Scene(root, 800, 600);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);

// Create middle
output = new TextArea();
output.setEditable(false);
output.setFocusTraversable(true); // I've tried true also, just to test

// ----------------------------------------------
// Tell the Screen Reader what it needs to access
// ----------------------------------------------
output.setAccessibleRole(AccessibleRole.TEXT_AREA);

root.setCenter(output);
// ...

// Begin
primaryStage.show();

// start the thread
Thread th = new Thread(new AppMain());
th.start();
}
catch (Exception e)
{
e.printStackTrace();
}
}

@Override
public void init()
{
// Set output to TextArea when we have a full string
System.setOut(new PrintStream(new OutputStream()
{
@Override
public void write(int b) throws IOException
{
if (b == '\r')
{
return;
}
if (b == '\n')
{
final String text = STR_BUFFER.toString() + NEW_LINE;
appendTextArea(text);
STR_BUFFER.setLength(0);
}
else
{
STR_BUFFER.append((char) b);
}
}
}, true));
}

public void appendTextArea(String str)
{
Platform.runLater(() ->
{
int anchor = output.getText().length();

output.appendText(str);

// just to clear it
output.positionCaret(0);

// ----------------------------------------------
// Tell the Screen Reader what it needs to do
// ----------------------------------------------
output.executeAccessibleAction(AccessibleAction.SET_TEXT_SELECTION, anchor, anchor + str.length());
});
}

public static void main(String[] args)
{
launch(args);
}
}

线程类

/*
* Just to simulate a feed to the console (textArea).
* This will die after 1 minute.
*/
package application;

public class AppMain implements Runnable
{
@Override
public void run()
{
int i = 0;
long start = System.currentTimeMillis();

while (System.currentTimeMillis() - start < 60000)
{
try
{
Thread.sleep(3000);
}
catch (InterruptedException e)
{}
System.out.println("This is line number " + ++i);
}
}
}

关于java - JavaFX "console"输出的可访问屏幕阅读,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36575952/

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