You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Java Swing集成JavaFX后屏幕阅读器无法读取组件内容的解决方案咨询

Java Swing集成JavaFX后屏幕阅读器无法读取组件内容的解决方案咨询

大家好,我们团队维护着一个Java Swing桌面应用,最近为了提升UI质感,把部分页面重构为JavaFX实现,并且通过JFXPanel完成了Swing与JavaFX的桥接集成。集成过程很顺利,但现在遇到了一个棘手的无障碍访问问题:屏幕阅读器(比如NVDA)完全无法读取JavaFX组件的文本和描述信息。

我们已经按照要求给所有JavaFX组件都配置了无障碍相关的文本和描述,但问题依然存在。想请教一下有没有遇到过类似问题的朋友,或者了解相关技术的大佬,能给我们一些解决思路或者具体的方案?

下面是我们用来测试的示例代码:

package org.example.javafx.hellojavafx;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.AccessibleRole;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import org.controlsfx.control.PopOver;

import javax.swing.*;
import java.awt.*;

public class AccessiblePaneExample {

  public static void main(String[] args) {
    System.setProperty("javafx.accessible.force", "true");
    SwingUtilities.invokeLater(() -> {
      JFrame frame = new JFrame("Accessible Pane Example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(800, 600);
      frame.setLayout(new BorderLayout());

      JFXPanel fxPanel = new JFXPanel();
      frame.add(fxPanel, BorderLayout.CENTER);

      Platform.runLater(() -> initFX(fxPanel));

      frame.setVisible(true);
    });
  }

  private static void initFX(JFXPanel fxPanel) {
    // Button
    Button button = new Button("Click Me");
    button.setAccessibleRole(AccessibleRole.BUTTON);
    button.setAccessibleRoleDescription("A button that can be clicked");
    button.setAccessibleHelp("Clickable Button");

    // ComboBox
    ComboBox<String> comboBox = new ComboBox<>();
    comboBox.getItems().addAll("Item 1", "Item 2", "Item 3", "Item 4");
    comboBox.setAccessibleRole(AccessibleRole.COMBO_BOX);
    comboBox.setAccessibleRoleDescription("A combo box for selecting items");
    comboBox.setAccessibleHelp("Item Selection ComboBox");

    // BarChart
    final CategoryAxis xAxis = new CategoryAxis();
    final NumberAxis yAxis = new NumberAxis();
    final BarChart<String, Number> barChart = new BarChart<>(xAxis, yAxis);
    barChart.setTitle("Item Summary");
    xAxis.setLabel("Item");
    yAxis.setLabel("Value");

    XYChart.Series<String, Number> series = new XYChart.Series<>();
    series.setName("2023");
    series.getData().add(new XYChart.Data<>("Item 1", 50));
    series.getData().add(new XYChart.Data<>("Item 2", 80));
    series.getData().add(new XYChart.Data<>("Item 3", 30));
    series.getData().add(new XYChart.Data<>("Item 4", 60));

    barChart.getData().add(series);
    barChart.setAccessibleRoleDescription("Bar chart showing item summary");
    barChart.setAccessibleHelp("Bar chart showing item summary");

    for (XYChart.Data<String, Number> data : series.getData()) {
      PopOver popOver = new PopOver();
      popOver.setContentNode(new javafx.scene.control.Label(data.getXValue() + ": " + data.getYValue()));
      data.getNode().setOnMouseEntered(event -> popOver.show(data.getNode()));
      data.getNode().setOnMouseExited(event -> popOver.hide());
      data.getNode().setAccessibleRole(AccessibleRole.TEXT);
      data.getNode().setAccessibleRoleDescription(data.getXValue() + ": " + data.getYValue());
      data.getNode().setAccessibleHelp(data.getXValue() + ": " + data.getYValue());
    }

    // Layout
    BorderPane root = new BorderPane();
    root.setTop(button);
    root.setCenter(comboBox);
    root.setBottom(barChart);
    root.setFocusTraversable(true);

    Scene scene = new Scene(root, 800, 600);
    fxPanel.setScene(scene);
  }
}

备注:内容来源于stack exchange,提问作者chetan gangurde

火山引擎 最新活动