Анимация диалога состоит из таких классов: TutorialDialog TutorialAnimator TutorialHelper MouseBlocker Каждый из них представлен .cpp и .h файлом, а к TutorialDialog есть еще .ui файл с интерфейсом. Что и как делает каждый класс: TutorialDialog Это сам интерфейс, в котором демонстрируется html файл с инструкциями. Он также содержит слайдер для регулировки скорости демонстрации и кнопку Demonstrate, нажатие на которую запускает анимацию. Содержимое инструкций заружается из файла :/Tutorial/html/pageN.html ресурсов программы. Кнопки next и previous активны в зависимости от наличия файла для следующей/прошлой страницы. Скорость регулируется от 20 до 70. Это базовое и минимальное значение скорости в милисекундах, быстрее которого не будет происходить ниодно действите анимации. Например, симуляция ввода с клавиатуры будет происходить с паузой в это значение между нажатиями на кнопки. По нажатию кнопки Demonstrate считывается файл :/Tutorial/commands/pageN.txt из ресурсов программы, в котором должны находиться инструкции по анимации действий описаных в html файле, который отображается в данный момент. Для анимации создается инстанс класс TutorialAnimator с аргументами: ссылкой на TutorialDialog и текстом файла комманд. Далее запускает его, после чего управление передается этому классу. TutorialAnimator Является наследником QThread, чтобы не блокироваться при открытии модальных диалогов и меню. При инициализации первым делом прячет TutorialDialog и разбивает полученый текст файла команд на строки, каждая из которых является отдельной командой. Создает инстанс класса TutorialHelper в GUI потоке, через который будет позже манипулировать интерфейсом. При запуске блокирует ввод и движения мышки при помощи методов blockInput и blockMouse из класса TutorialHelper. После чего начинает последовательно выполнять комманды полученые при инициализации. В данный момент поддерживаются следующие комманды: moveMouse X Y moveMouse objectName1 [objectName2 [... objectNameN]] clickWidget objectName1 [objectName2 [... objectNameN]] typeWidget objectName1 [objectName2 [... objectNameN]] text hoverMenuItem menuName itemName|itemIndex clickMenuItem menuName itemName|itemIndex selectComboItem objectName1 [objectName2 [... objectNameN]] itemIndex selectListItem objectName1 [objectName2 [... objectNameN]] itemIndex selectTab objectName1 [objectName2 [... objectNameN]] itemIndex wait SECONDS moveMouse - переместить указатель мыши в указаную точку или в центр виджета. clickWidget - переместить указатель мыши в центр виджета и кликнуть. typeWidget - напечатать текст на клавиатуре когда указаный обьект в фокусе. hoveMenuItem - переместить указатель мыши на пункт меню. clickMenuItem - кликнуть пункт меню мышью. selectComboItem - открыть combo box и выбрать в нем элемент. selectListItem - выбрать элемент в списке при помощи мыши. selectTab - выбрать вкладку QTabWidget при помощи мыши wait - ожидать указаное кол-во секунд. Для каждой из них есть отдельный метод, который ее обрабатывает. Все манипуляции с интерфейсом происходят через класс TutorialHelper, который был создан раньше и выполняется в GUI потоке. Но так как из треда, в котором TutorialAnimator, вызов метода TutorialHelper приведет к его выполнению не в GUI-потоке, для вызова этих методов используется QMetaObject::invokeMethod с аргументом Qt::BlockedQueuedConnection. Это позволяет выполнить метод когда выполнение программы вернется в основной поток и блокировать выполнение потока TutorialAnimator пока вызваный метод не выполнится. Этот класс также содержит такие полезные методы как findChild, findWidget и getWidget, который наверняка пригодятся также для написания unit-тестов. Они позволяют рекурсивно искать обьекты по дереву обьектов программы. Для этого используется поиск в ширину. В отличии от стандартной функции findChild, эти методы умеют искать не просто первый обьект с указаным именем, а последний обьект в цепочке наследования. Например, комманда clickWidget MainWindow SomeWidget TargetButton означает: найти виджет MainWindow, в нем SomeWidget, в нем TargetButton и кликнуть ее. Также поддерживается поиск по имени класса: w#className. Например6 moveMouse w#FWWindow objectTreeView - найти обьект класса FWWindow, в котором найти objectTreeView и переместить курсор мыши в его центр. TutorialHelper Этот класс содержит все методы по манипулированию интерфейсом. Его методы вызываются из TutorialAnimator, но должны выполняться в GUI потоке. Он также содержит методы blockInput для блокировки ввода и blockMouse для блокировки движения мыши, которые могут выполняться с любого потока. MouseBlocker Наследник QThread, который когда запущен каждые 10 милисекунд перемещает указатель мыши в его текущее положение. Это полностью блокирует перемещение мыши пользователем. Используется через TutorialHelper::blockMouse.