1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
Анимация диалога состоит из таких классов:
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.
|