Я пытаюсь создать тест для своего приложения Qt. Цель состоит в том, чтобы протестировать графический интерфейс приложения, перемещая указатель мыши и щелкая QGraphicsItems или QWidgets с помощью библиотеки X11.

Тест написан как плагин для моего приложения Qt. Он запускает отдельный QThread, а в функции run () я перемещаю мышь. Назовем это «тестовым запущенным потоком».

Однако мне также нужно получить структуру графического интерфейса, т.е. расположение различных виджетов, поэтому в «потоке выполнения теста» я просматриваю QApplication :: topLevelWidgets () и нахожу тот, который мне интересен. Затем я вызываю mapToGlobal ( ) на этом виджете, чтобы получить свою глобальную позицию. Эта позиция затем может быть передана функциям мыши X11, чтобы навести указатель мыши на виджет.

Обычно это работает, но время от времени я получаю эту ошибку «Xlib: неожиданный асинхронный ответ». Некоторые поисковые запросы показали, что это может быть связано с настройкой позиций QWidget или попыткой обновить их из другого потока.

Но я просто получаю информацию о виджетах в другом потоке. Почему это может вызвать проблемы? :(

Если ничего не помогает, я готов настроить какую-то очередь связи обратно в основной (GUI) поток. «Тестовый запущенный поток» будет размещать запросы информации о виджетах в очереди, и поток графического интерфейса пользователя может на них отвечать.

Причина, по которой плагин запускает отдельный поток для перемещения мыши, заключается в том, что графический интерфейс должен продолжать реагировать на события, иначе вся суть упражнения будет потеряна. Я знаю, что могу также не использовать поток, а просто перемещать указатель мыши в основном потоке , регулярно вызывая processEvents (). Думаю, это другой вариант.

Любые идеи от кого-то, кто уже проходил этот путь раньше, были бы очень полезны. Спасибо !

0
safe_malloc 3 Апр 2013 в 09:03

1 ответ

Лучший ответ

Но я просто получаю информацию о виджетах в другом потоке. Почему это может вызвать проблемы? :(

Потому что вы все еще отправляете сообщения протокола X туда и обратно. toGlobal () обязательно запросит X-сервер о фактическом положении виджета (поскольку он мог быть перемещен каким-либо другим способом). Так что, к сожалению, «просто получить некоторую информацию» для X не является константной операцией. На самом деле, перемещение курсора мыши из тестового потока также является большим запретом по той же причине.

В вашем случае я бы просто использовал QTimer / processEvents с нулевым таймаутом и забыл о потоке; не стоит беспокоиться о настройке очередей для перемещения событий вперед и назад, не говоря уже о том, что вам нужно добавить мьютексы (!) в свой код.

0
JvO 4 Апр 2013 в 06:11
Итак, я понимаю вызов processEvents (), чтобы убедиться, что события мыши продолжают обрабатываться, поскольку они перемещаются из того же основного (GUI) потока. Но по какой причине вы также предлагали использовать QTimer?
 – 
safe_malloc
5 Апр 2013 в 14:48
Я имею в виду, что даже если QTimer отключается, а я все еще перемещаю мышь по экрану, код, запускаемый из QTimer, не запускается. Так как сейчас мы все делаем в 1 потоке. Допустим, я вызвал processEvents () из обратного вызова QTimer, он не будет вызван. Таким образом, реакция графического интерфейса пользователя при перемещении мыши по экрану будет потеряна. Вот почему я подумал, что, возможно, нужно освободить поток графического интерфейса и переместить мышь в отдельный поток. Вызов processEvents () из функции перемещения мыши возможен, но это означает смешивание кода Qt и X11 в одной функции.
 – 
safe_malloc
5 Апр 2013 в 15:06
Я думаю, вы неправильно понимаете использование processEvents (); эту функцию следует вызывать периодически, если вы выполняете какие-либо тяжелые вычисления, такие как кодирование фильма или вычисление фрактала Мандельброта, то есть вы загружаете процессор в течение значительного времени. Вызывая processEvents () из цикла , вы гарантируете, что графический интерфейс остается отзывчивым. Ваш случай другой: вы просто хотите двигать мышью, имитировать щелчки и получать какие-то результаты. Это можно сделать в слоте, вызываемом из QTimer, который обрабатывается основным потоком графического интерфейса пользователя и, таким образом, автоматически обновляет графический интерфейс.
 – 
JvO
5 Апр 2013 в 16:38