Qt for HarmonyOS/user development guide/a11y
English 中文
Enabling Qt Accessibility on HarmonyOS
In the Qt SDK releases currently provided, accessibility support on the HarmonyOS platform is disabled by default. To use or test accessibility, you have to enable it explicitly.
Enabling accessibility from the project template
launchWant holds the launch parameters of the Ability, and io.qt.experimental.enableA11ySupport is the accessibility switch recognized by the Qt OHOS plugin.
Add the following to QAbility.ets:
private enableQtAccessibilitySupport(): void {
this.launchWant.parameters = this.launchWant.parameters ?? {};
this.launchWant.parameters['io.qt.experimental.enableA11ySupport'] = true;
}
Make sure it is called before Qt creates its window:
onWindowStageCreate(windowStage: Window.WindowStage) {
this.enableQtAccessibilitySupport();
qpa.handleAbilityOnWindowStageCreate(this, windowStage);
}
Keep it in place when the window stage is restored as well:
onWindowStageRestore(windowStage: Window.WindowStage): void {
this.enableQtAccessibilitySupport();
qpa.handleAbilityOnWindowStageRestore(this, windowStage);
}
Enabling accessibility when launching the HAP from the command line
Supported code versions
| Branch | Date |
|---|---|
tqtc/harmonyos-5.12.12 |
2025/7/7 |
tqtc/harmonyos-5.15.16 |
2025/7/16 |
Launching
Add the launch parameter io.qt.experimental.enableA11ySupport to the want.
- From the command line:
aa start -a QAbility -b com.ohos.ohosqttemplate --pb io.qt.experimental.enableA11ySupport true
- From DevEco Studio: add
--pb io.qt.experimental.enableA11ySupport trueto the launch configuration.
Official Qt documentation
https://doc.qt.io/archives/qt-5.15/accessible-qwidget.html
SwitchButton derived from QAbstractButton
Custom widgets derived from QAbstractButton need no special handling.
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 derived from QWidget
A custom widget derived directly from QWidget only gets a generic accessible description — no checked state and no actions. You have to derive from QAccessibleWidget, or reimplement QAccessibleActionInterface, and register a factory method with QAccessible::installFactory.
The HarmonyOS screen reader identifies switch-like widgets mainly through the following three items, so make sure all of them are implemented:
state().checkable— the widget can be checkedstate().checked— whether it is currently checkedactionNames()containstoggleAction(), anddoAction()handles it
The SwitchButton2 header:
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;
// Colors
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);
// State
bool isChecked() const;
// Animation duration
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();
}
Reusing simplewidgets_p.h
Qt already provides accessibility support for its basic widgets. If your own widget derives from QWidget but behaves like a basic widget such as a button or a label, you can reuse the accessible class Qt already implements.
However, these classes are not exported, so to reuse them you have to edit simplewidgets_p.h yourself and export the class you need (add Q_WIDGETS_EXPORT or Q_DECL_EXPORT to the header and rebuild).
For example QAccessibleButton (note that it sits inside a #if QT_CONFIG(abstractbutton) block — do not break that structure when exporting it):
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;
};
Widgets with built-in accessibility support
The full list of Qt widgets that come with an accessible implementation can be found in src/widgets/accessible/qaccessiblewidgetfactory.cpp.
| Qt widget | Accessible class |
|---|---|
| QLineEdit | QAccessibleLineEdit (except the internal line edit of a 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 |
Note: if your custom widget derives from any of the Qt widgets above, the matching accessible implementation is picked up automatically along the base class chain — no extra work is needed.
Third-party Qt widget libraries
Refer to the documentation of the respective widget library.