Qt for HarmonyOS/user development guide/a11y zh: Difference between revisions
No edit summary |
|||
| Line 1: | Line 1: | ||
'''中文''' [[Qt_for_HarmonyOS/user_development_guide/a11y|English]] | |||
= 开启 Qt 无障碍功能 = | = 开启 Qt 无障碍功能 = | ||
Latest revision as of 09:47, 26 August 2026
中文 English
开启 Qt 无障碍功能
目前 Qt 提供的 SDK 版本,默认是关闭鸿蒙平台下的无障碍功能的。如果需要使用或测试无障碍功能,需要开启相关选项。
需要注意的是,目前在HarmonyOS平台,只有Qt5支持无障碍。
修改工程模板,让 hap 携带无障碍开关
其中 launchWant 是 Ability 的启动参数,io.qt.experimental.enableA11ySupport 是 Qt OHOS 插件识别的无障碍开关。
在 QAbility.ets 中加入:
private enableQtAccessibilitySupport(): void {
this.launchWant.parameters = this.launchWant.parameters ?? {};
this.launchWant.parameters['io.qt.experimental.enableA11ySupport'] = true;
}
然后确保在 Qt 创建窗口之前调用它:
onWindowStageCreate(windowStage: Window.WindowStage) {
this.enableQtAccessibilitySupport();
qpa.handleAbilityOnWindowStageCreate(this, windowStage);
}
恢复窗口时也需要保留:
onWindowStageRestore(windowStage: Window.WindowStage): void {
this.enableQtAccessibilitySupport();
qpa.handleAbilityOnWindowStageRestore(this, windowStage);
}
命令行携带无障碍参数启动 hap 包
代码版本
| 分支 | 日期 |
|---|---|
tqtc/harmonyos-5.12.12 |
2025/7/7 |
tqtc/harmonyos-5.15.16 |
2025/7/16 |
启动方式
在 want 中添加启动参数 io.qt.experimental.enableA11ySupport。
- 命令行启动:
aa start -a QAbility -b com.ohos.ohosqttemplate --pb io.qt.experimental.enableA11ySupport true
- DevEco 启动:在 launch 配置中添加
--pb io.qt.experimental.enableA11ySupport true
官方适配文档
https://doc.qt.io/archives/qt-5.15/accessible-qwidget.html
SwitchButton 继承自 QAbstractButton
这种继承自 QAbstractButton 的自定义控件,无需做特殊处理。
class SwitchButton : public QAbstractButton {
Q_OBJECT
Q_PROPERTY(double offset READ offset WRITE setOffset)
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
public:
explicit SwitchButton(QWidget* parent = nullptr);
~SwitchButton() override;
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
void setCheckedColor(const QColor& color);
void setUncheckedColor(const QColor& color);
void setDisabledColor(const QColor& color);
void setHandleColor(const QColor& color);
void setAnimationDuration(int duration);
protected:
void paintEvent(QPaintEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
private:
double offset() const;
void setOffset(double value);
QColor backgroundColor() const;
void setBackgroundColor(const QColor& color);
double m_offset;
QColor m_checkedColor;
QColor m_uncheckedColor;
QColor m_disabledColor;
QColor m_handleColor;
QColor m_backgroundColor;
QPropertyAnimation* m_animation;
int m_handleRadius;
int m_margin;
};
SwitchButton2 继承自 QWidget
这种继承自 QWidget 的自定义控件,只能得到通用的无障碍描述(没有选中状态、也没有可执行动作),需要从 QAccessibleWidget 派生,或重新实现 QAccessibleActionInterface,并调用 QAccessible::installFactory 注册工厂方法。
鸿蒙的读屏服务主要依据以下三项来识别开关类控件,请确保都实现:
state().checkable—— 控件可勾选state().checked—— 当前是否选中actionNames()中包含toggleAction(),并在doAction()中响应
SwitchButton2 头文件如下:
class SwitchButton2 : public QWidget {
Q_OBJECT
Q_PROPERTY(double offset READ offset WRITE setOffset)
Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable)
public:
explicit SwitchButton2(QWidget* parent = nullptr);
~SwitchButton2() override = default;
void setCheckable(bool);
bool isCheckable() const;
// 设置颜色
void setCheckedColor(const QColor& color);
void setUncheckedColor(const QColor& color);
void setDisabledCheckedColor(const QColor& color);
void setDisabledUncheckedColor(const QColor& color);
void setHandleColor(const QColor& color);
void setDisabledHandleColor(const QColor& color);
// 获取状态
bool isChecked() const;
// 设置动画时间
void setAnimationDuration(int duration);
signals:
void toggled(bool checked);
public slots:
void setChecked(bool checked);
void toggle();
protected:
void paintEvent(QPaintEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
double offset() const;
void setOffset(double value);
private:
bool m_checkable { true };
bool m_checked { false };
double m_offset { 0 };
double m_radius { 0 };
QColor m_checkedColor { Qt::green };
QColor m_uncheckedColor { Qt::gray };
QColor m_disabledCheckedColor { Qt::darkGreen };
QColor m_disabledUncheckedColor { Qt::lightGray };
QColor m_handleColor { Qt::white };
QColor m_disabledHandleColor { Qt::gray };
QPropertyAnimation* m_animation { nullptr };
bool m_pressed { false };
};
main.cpp:
#include <QAccessible>
#include <QApplication>
#include <QtWidgets/qaccessiblewidget.h>
#include "mainwindow.h"
#include "switchbutton2.h"
class AccessibleSwitchButton : public QAccessibleWidget {
public:
AccessibleSwitchButton(QWidget* w)
: QAccessibleWidget(w)
{
Q_ASSERT(button());
if (button()->isCheckable())
addControllingSignal(QLatin1String("toggled(bool)"));
else
addControllingSignal(QLatin1String("clicked()"));
}
QAccessible::State state() const override
{
QAccessible::State state = QAccessibleWidget::state();
SwitchButton2* b = button();
if (b->isCheckable())
state.checkable = true;
if (b->isChecked())
state.checked = true;
return state;
}
QAccessible::Role role() const override
{
return QAccessible::Role::CheckBox;
}
QStringList actionNames() const override
{
QStringList names;
if (widget()->isEnabled()) {
names << toggleAction();
}
names << QAccessibleWidget::actionNames();
return names;
}
void doAction(const QString& actionName) override
{
if (actionName == toggleAction()) {
button()->toggle();
} else {
QAccessibleWidget::doAction(actionName);
}
}
protected:
SwitchButton2* button() const
{
return qobject_cast<SwitchButton2*>(object());
}
};
QAccessibleInterface* customWidgetFactory(const QString& classname, QObject* object)
{
QAccessibleInterface* interface = 0;
if (classname == QLatin1String("SwitchButton2") && object && object->isWidgetType())
interface = new AccessibleSwitchButton(static_cast<QWidget*>(object));
return interface;
}
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
QAccessible::installFactory(customWidgetFactory);
MainWindow w;
w.show();
return a.exec();
}
复用 simplewidgets_p.h
Qt 默认对基础控件做了无障碍支持。如果自行实现的控件虽然继承自 QWidget,但实际行为和 Button、Label 等基础控件类似,也可以直接复用 Qt 实现的无障碍控件。
但是由于 Qt 未导出这些控件,如果要复用,需要自行修改 simplewidgets_p.h 代码,将要复用的控件导出(在头文件里添加 Q_WIDGETS_EXPORT 或 Q_DECL_EXPORT 并重新编译)。
例如 QAccessibleButton(注意它位于 #if QT_CONFIG(abstractbutton) 条件编译块内,导出时不要破坏该结构):
class Q_WIDGETS_EXPORT QAccessibleButton : public QAccessibleWidget
{
Q_DECLARE_TR_FUNCTIONS(QAccessibleButton)
public:
QAccessibleButton(QWidget *w);
QString text(QAccessible::Text t) const override;
QAccessible::State state() const override;
QRect rect() const override;
QAccessible::Role role() const override;
QStringList actionNames() const override;
void doAction(const QString &actionName) override;
QStringList keyBindingsForAction(const QString &actionName) const override;
protected:
QAbstractButton *button() const;
};
默认支持的无障碍控件
Qt 默认实现的支持无障碍的常用控件,可以自行查看 src\widgets\accessible\qaccessiblewidgetfactory.cpp。
| Qt 控件 | 对应无障碍控件 |
|---|---|
| QLineEdit | QAccessibleLineEdit(QSpinBox 内部的行编辑器除外) |
| QTextEdit | QAccessibleTextEdit |
| QPlainTextEdit | QAccessiblePlainTextEdit |
| QComboBox | QAccessibleComboBox |
| QAbstractSpinBox | QAccessibleAbstractSpinBox |
| QSpinBox | QAccessibleSpinBox |
| QDoubleSpinBox | QAccessibleDoubleSpinBox |
| QScrollBar | QAccessibleScrollBar |
| QAbstractSlider | QAccessibleAbstractSlider |
| QSlider | QAccessibleSlider |
| QToolButton | QAccessibleToolButton |
| QCheckBox / QRadioButton / QPushButton / QAbstractButton | QAccessibleButton |
| QDialog / QMessageBox / QToolBar / QFrame | QAccessibleWidget |
| QMainWindow | QAccessibleMainWindow |
| QLabel / QLCDNumber / QStatusBar / QTipLabel | QAccessibleDisplay |
| QProgressBar | QAccessibleProgressBar |
| QMenuBar | QAccessibleMenuBar |
| QMenu | QAccessibleMenu |
| QTreeView | QAccessibleTree |
| QTableView / QListView | QAccessibleTable |
| QTabBar | QAccessibleTabBar |
| QStackedWidget | QAccessibleStackedWidget |
| QGroupBox | QAccessibleGroupBox |
| QToolBox | QAccessibleToolBox |
| QDialogButtonBox | QAccessibleDialogButtonBox |
| QDial | QAccessibleDial |
| QTextBrowser | QAccessibleTextBrowser |
| QAbstractScrollArea | QAccessibleAbstractScrollArea |
| QScrollArea | QAccessibleScrollArea |
| QCalendarWidget | QAccessibleCalendarWidget |
| QDockWidget | QAccessibleDockWidget |
| QMdiArea | QAccessibleMdiArea |
| QMdiSubWindow | QAccessibleMdiSubWindow |
| QSplitter / QSizeGrip / QSplitterHandle / QRubberBand | QAccessibleWidget |
| QWidget | QAccessibleWidget |
注:如果自定义控件继承自上表中的某个 Qt 控件,会自动沿基类链匹配到对应的无障碍实现,无需额外处理。
第三方 Qt 控件库
需要查阅三方控件库的相关文档。