Обработка событий в потоке, QT
Есть DLL, в которой запускаю поток QThread, в котором запускаю цикл QApplication. Так же в потоке создаётся диалог и таймер. Диалог скрывается по таймеру.
У диалога переопределены обработчики событий мыши.
Почему-то обработка сигналов от таймера происходит вовремя, без задержек. А вот сигналы от мыши обрабатываются только в том случае, если вызвать ресайз формы.
То есть, если я кликнул правой кнопкой мыши на диалоге и не изменил его размеров, то форма может скрыться по таймеру так и не обработав событие мышки. Почему так?
Немного кода:
Код:
void MThread::run()
{
MThread::_app = new QApplication(_argc, _argv);
_main_window = new SongTitle();
_main_window->SetTitle(QString::fromLocal8Bit("lalala"));
_main_window->ShowTitle();
//this->exec();
MThread::_app->exec();
}
{
MThread::_app = new QApplication(_argc, _argv);
_main_window = new SongTitle();
_main_window->SetTitle(QString::fromLocal8Bit("lalala"));
_main_window->ShowTitle();
//this->exec();
MThread::_app->exec();
}
Код:
void SongTitle::mouseReleaseEvent(QMouseEvent *event)
{
MessageBoxW(0, L"in mouse event",L"",0);
switch (event->button()){
case Qt::LeftButton:
MessageBoxW(0, L"left",L"",0);
break;
case Qt::RightButton:
MessageBoxW(0, L"right",L"",0);
break;
default:
QDialog::mousePressEvent(event);
break;
}
}
{
MessageBoxW(0, L"in mouse event",L"",0);
switch (event->button()){
case Qt::LeftButton:
MessageBoxW(0, L"left",L"",0);
break;
case Qt::RightButton:
MessageBoxW(0, L"right",L"",0);
break;
default:
QDialog::mousePressEvent(event);
break;
}
}
Весь GUI обязан быть в главном потоке приложения.
Похоже Qt gui весь должен быть в главном потоке и видимо это не обойти. Реализация событийной системы там своя, не нативная (хотя нативные события встроить можно), логикой виндовых окон там не обойтись. Сильно сомневаюсь, что в дочернем потоке хотя бы api-шный gui можно в Qt-программах использовать (по той-же причине). Хотелось бы, чтобы я заблуждался, может кто опровергнет?
Ну хорошо. Кто объяснит мне, чем главный поток принципиально отличается от того, что создаётся через QThread?
Тем, что он главный и его логика жёстко прописана в ядре. Может, из остальных потоков события не так обрабатываются, или ещё что. Вариантов масса, и без копания в исходниках вряд ли можно многое узнать.
Так же там есть намёк на главный поток, в контексте которого запускается второстепенный и сам GUI.
К тому же, если бы я накосячил с потоками, мне бы в debug console вывалилась надпись о том, что виджеты можно создавать только в главном потоке, ничего бы не стало работать, а форма отображается.
Создаться и отображаться она может, а вот остальная логика может рандомно поехать — например, как в твоём случае. А что отладка показывает?
Вот что странно: сообщения от таймера обрабатываются как надо, а сообщения от мыши лагают. И пинок для обработки сообщений мыши даёт именно событие перерисовки окна. Я даже представить не могу, какой механизм мог бы работать и с какой логикой.
Возможно, это баг. За троллями такое частенько наблюдается. А работа с потоками в DLL — вообще больная тема.
Раз на SO никто не подсказал ничего, видимо, лучше оставить эту тему и как-то выкручиваться иначе.
Никакой ни баг, в доках об этом пишут. Сообщения, не направленные конкретно к gui-шным элементам, может и нормально обрабатываются, а всякие ресайзы связаны с гуи и могут глючить. Думаю, что подобное с таймером.
А можно ссылку на доки?
Кстати, я уже пробовал и свою очередь делать, через QEventLoop, но всё равно никаких изменений.
И если это баг, то что я делаю неправильно? Могу залить полностью код проекта.
C++ GUI Programming with Qt 4 (First Edition) (ISBN 0131872494)
by Jasmin Blanchette & Mark Summerfield. Это книга разрабов Qt, можно ей верить. А в офдоках подтверждение точно находил, возможно даже просто в хелпе Qt.
Сигнал таймера не спецефичен для формы, поэтому благодаря поддержке со стороны кьют и передается нормально. А ресайзы "чисто гуишные" и кьют их в неглавном потоке не обязана обработать верно. Я почти уверен что так происходит.
Неправильным может быть только сама затея - гуи (часть гуи) в дочернем потоке.
Я все-таки надеюсь, что я не прав в своем мнении о полной невозможности обойти эти запреты. Может хоть в ограниченной области задачь можно безболезненно гуи разбрасывать по потокам? Как-то синхронизовать, обратный вызов или еще какие примудрости? Не может быть, чтобы такой изъян народ не подвиг накопать решение.
Это не док, но то, что под рукой нашлось --
by Jasmin Blanchette & Mark Summerfield. Это книга разрабов Qt, можно ей верить. А в офдоках подтверждение точно находил, возможно даже просто в хелпе Qt.
Сигнал таймера не спецефичен для формы, поэтому благодаря поддержке со стороны кьют и передается нормально. А ресайзы "чисто гуишные" и кьют их в неглавном потоке не обязана обработать верно. Я почти уверен что так происходит.
Неправильным может быть только сама затея - гуи (часть гуи) в дочернем потоке.
Я все-таки надеюсь, что я не прав в своем мнении о полной невозможности обойти эти запреты. Может хоть в ограниченной области задачь можно безболезненно гуи разбрасывать по потокам? Как-то синхронизовать, обратный вызов или еще какие примудрости? Не может быть, чтобы такой изъян народ не подвиг накопать решение.
Если попытаться создать GUI вне главного потока, программа падает.
Безразлично, в каком именно потоке будет создан GUI, лишь бы в этом потоке был создан экземпляр QApplication, он и будет считать главным.
Алсо, не стал бы доверять книге, где рассматривается QT 4-й версии. С тех пор уже столько воды утекло.
Насчет достаточно гуи и QApplication в один поток и он становится главным -- боюсь тоже боком выйдет когда-то.
А про то, что в любом потоке можно создать GUI, лишь бы был инстанс QApplication — это уже либо из документации прочёл, либо из coock book'а, которые собрали комьюнити. Но эта информация тоже не первой свежести, официальный док по потокам ещё не обновился для пятой ветки. А может, там просто и обновлять нечего...
Может не инстанс а ссылку на main-ский qApp? Иначе это сильно смахивает на создание целого процесса, а не потока.. Если что узнаете, отпишитесь плиз.
Код:
if( QTimer->isActive() )
{
"что-то делаем";
}
else
{
"форма может скрыться по таймеру";
}
{
"что-то делаем";
}
else
{
"форма может скрыться по таймеру";
}
Я даже пробовал не запускать цикл qApp, а вместо этого запустить цикл потока, но инстанс всё равно создавал. В коде этот момент закомментирован. И всё работало. Ну, как работало...Так же ситуация, но программа не падала. А когда попытался запустить только поток, не создавая инстанса qApp, то сразу же вылетала ошибка.
Поэкспериментирую ещё, но что-то уже и идей даже нет. Можно попробовать посоздавать все инстансы внутри потока приложения, а цикл обработки событий запустить в новом потоке QThread, Надеюсь, это не подвесит приложение. Но что-то не верится, что такая штука сработает. Там была какая-то особенность для пересылки сигналов между потоками, для них использовался специальный вид подключений.
Отпишусь, если найду решение.