Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Help making an app accessible (windows QAccessible)



  • Hello,
    I have a custom QLabel derivative where I do a lot of custom display and that I need to make accessible...

    Here is the code that I used:

            class MyWidgetAccessible: public QAccessibleWidget {
            public:
              MyWidgetAccessible(QWidget *w): QAccessibleWidget(w) { }
              int childCount() const Q_DECL_OVERRIDE { return 0; }
              QAccessibleInterface* child(int index) const Q_DECL_OVERRIDE { return nullptr; }
              QRect rect() const Q_DECL_OVERRIDE 
              { 
                QRect rect= widget()->rect(); 
                QPoint tp = widget()->mapToGlobal(QPoint(0,0));
                rect= QRect(tp.x() + rect.x(), tp.y() + rect.y(), rect.width(), rect.height());
                qDebug() << "request rect2" << rect; 
                return rect;
              }
              QAccessible::Role role() const Q_DECL_OVERRIDE { return QAccessible::PushButton; }
              QString text(QAccessible::Text t) const Q_DECL_OVERRIDE
              { 
                switch (t) 
                {
                case QAccessible::Name: return "my widget";
                case QAccessible::Value:
                  return "my widget on keyboard"; // return the current text for the screen
                case QAccessible::Description:
                  return "This is my widget";
                default:
                  return QString();
                }
                return QAccessibleWidget::text(t);
              }
            };
    
    

    and I created and registered a QAccessibleInterface *accessibilityFactory(const QString &classname, QObject *object) function. I verified that this function was called and that my class was instanciated. Which is the case...

    Now, here is what the symptoms are.
    If I have my mouse hovering above my control and that I start the narator, the control "accessibility" data is correctly found. The control is "circled" and the PC will read the text that I created ("my widget"...)...
    If I move the mouse to the window menus, the narrated focus will change to the menus. But if I move the mouse back over my control, nothing will happen, the narrator focus will not change/move.

    Any clue what is going wrong?

    Thanks,
    Cyrille


  • Lifetime Qt Champion

    Hi,

    Are you just hovering on your widget or are you clicking on it again ?



  • Hello,

    I have tried both hover and click.
    None of them seem to do anything.
    My widget inherits from QLabel.

    Cyrille



  • Hello,

    Well, I have continued the work and made some progresses.

    My app structure is:
    centralWidget=QWidget with centered layout
    |__centralWidget_child = CustomControl1, inherits QLabel, a "virtual keyboard". presents 51 "buttons" to in addition to the CustomControl2 control
    ___|__CustomControl1_child= CustomControl2, inherits QLabel

    The code bellow seems to work. But has 2 issues...

    First problem/question:
    I can navigate through them using the narator key command.
    BUT, when I hover the mouse above my widgets, the narator "focus" does not move as it does for the application menu items.
    Any clue why this is the case? Could it be because QLabels can not have focus or something like that? What control should I inherit from if not QLabel?

    Second question:
    I the "value" for the CustomControl1 can change when the user does things. So I need to tell the system that it has changed.
    How do I do that?

    class CEmuButtonAccessible : public QObject, public QAccessibleInterface { Q_OBJECT Q_INTERFACES(QAccessibleInterface)
      int id; QAccessibleWidget *papa; QtEmulatorWidget *emu;
    public:
      CEmuButtonAccessible(QWidget* c, int id, QAccessibleWidget *parent): QAccessibleInterface(), id(id), papa(parent), emu((QtEmulatorWidget*)c); { }
      QRect rect() const Q_DECL_OVERRIDE  { return appropriate recangle;  }
      QAccessible::Role role() const Q_DECL_OVERRIDE { return QAccessible::PushButton; }
      QAccessible::State state() const Q_DECL_OVERRIDE { return QAccessible::State(); }
      QString text(QAccessible::Text t) const Q_DECL_OVERRIDE { return approptiate text; }
      QAccessibleInterface *parent() const Q_DECL_OVERRIDE { return papa; }
      QObject *object() const Q_DECL_OVERRIDE { return (QObject*)this; }
      bool isValid() const Q_DECL_OVERRIDE { return true; }
      void setText(QAccessible::Text,const QString &) Q_DECL_OVERRIDE {}
      // No sub childs
      int indexOfChild(const QAccessibleInterface *) const Q_DECL_OVERRIDE { return -1; }
      int childCount() const Q_DECL_OVERRIDE { return 0; }
      QAccessibleInterface* child(int index) const Q_DECL_OVERRIDE { return nullptr; }
      QAccessibleInterface *childAt(int,int) const Q_DECL_OVERRIDE { return nullptr; }
    };
    
    
    class QtEmulatorWidgetAccessible: public QAccessibleWidget {
      CEmuButtonAccessible *buttons[51]; // 51 "virtual" sub items
    public:
      QtEmulatorWidgetAccessible(QWidget *w): QAccessibleWidget(w) { for (int i=0; i<51; i++) buttons[i]= new CEmuButtonAccessible(w, i, this); }
      int childCount() const Q_DECL_OVERRIDE { return QAccessibleWidget::childCount()+51; }
      QAccessibleInterface* child(int index) const Q_DECL_OVERRIDE { if (index==0) return QAccessibleWidget::child(index); return buttons[index-1]; }
      QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE // Without this, the child scanning does not work
      { 
        for (int i=0; i<emu->mySkin->Keyboard.count(); i++)
          if (emu->mySkin->Keyboard.at(i).rect.contains(x, y))
            return buttons[i];
        return QAccessibleWidget::childAt(x, y);
      }
      int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE  // Without this, the child scanning does not work
      { 
        for (int i=0; i<51; i++) if (child==buttons[i]) return i+1;
        return QAccessibleWidget::indexOfChild(child);
      }
      QRect rect() const Q_DECL_OVERRIDE  { return rectnagle;  }
      QAccessible::Role role() const Q_DECL_OVERRIDE { return QAccessible::PushButton; }
      QString text(QAccessible::Text t) const Q_DECL_OVERRIDE { return text; }
    };
    
    

    Thanks,
    Cyrille


  • Lifetime Qt Champion

    Based on this example, did you call addControllingSignal ?



  • Hello,

    Yes, I did in the constructor...
    However, in my case, the value is not an int, but a string...
    However, even when changing the signal signature to QString, it still does not work..

    Cyrille


  • Lifetime Qt Champion

    Would it be possible to provide a minimal compilable example to test that widget ?


Log in to reply