Russian Qt Forum

Qt => Общие вопросы => Тема начата: neosapient от Май 13, 2016, 02:06



Название: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: neosapient от Май 13, 2016, 02:06
Здравствуйте.

Есть сторонняя программа, которая ничего не знает об Qt. Но программа умеет загружать dll. Хочу воткнуть GUI, которое базируется на фреемворке Qt.

Собственно, сделал класс-наследник от QThread. В методе run() создается QApplication и QMainWindow. Далее показываю show() окна и смотрю на него.

1) Но вот не могу нажать на кнопки.
2) При уменьшении размера окна (мышкой сужаю окно, зацепившись за его край), его содержимое не перерисовывается. А вот при увеличении размера окна (мышкой растягиваю окно), его содержимое перерисовывается.


Как автоматически переподключить все сигналы-слоты на новый поток?
Пробовал moveToThread для QApplication и QMainWindow, но не помогает.

Может надо event'ы переподключить на новый поток?

[Qt5.4, VC9, Win7]


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: Igors от Май 13, 2016, 05:07
Наверняка слышали
Цитировать
UI только в главном потоке
Каких-то внятных/убедительных пояснений "почему так" я не слышал. Но, пытаясь делать не главном, приключений найдете массу - это точно.

Есть сторонняя программа, которая ничего не знает об QT. Но программа умеет загружать dll. Хочу воткнуть GUI, которое базируется на фреемворке QT.
Ну так может портировать это приложение на Qt? Если у него есть свой событийный цикл - его можно перенаправить на Qt. В любом случае нужно активно модифицировать приложение. 


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: kuzulis от Май 13, 2016, 08:28
А что, гугл теперь не в моде?
http://stackoverflow.com/questions/25025168/event-loop-in-qt-based-dll-in-a-non-qt-application


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: Bepec от Май 13, 2016, 12:01
Там главная проблема в том, что цикл событий окна зависит от получаемых системных сообщений. По сути запустив окошко, мы должны перенаправить в него оконные сообщения. Или же имитировать их. Но более тонко я в этом не разбирался, мне хватило (как и многим) coreApplication :D
 
to kuzulis: Там QCoreApplication. Собственно и проблема у ТСса в том, что он ГУИ хочет запустить :)
А GUI при таком подходе должно отплёвываться сообщениями - dont use in other thread. :D



Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: neosapient от Май 13, 2016, 13:24
По сути запустив окошко, мы должны перенаправить в него оконные сообщения. Или же имитировать их.
Да, нехватку этой части я и наблюдаю в своей тестовой программе. Но не пойму, как реализовать.


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: neosapient от Май 13, 2016, 13:53
Вот пример программы, которая создает кнопку:
Код:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
TARGET = app_in_thread
TEMPLATE = app
SOURCES += main.cpp

Код:
#include <QApplication>
#include <QThread>
#include <QPushButton>

class QxAppShell: public QThread
{
public:
    QxAppShell()
    { QThread::start(); }

    void run() Q_DECL_OVERRIDE
    {
        int argc=0;
        char *argv=0;

        QApplication app(argc, &argv);
        QPushButton button;
        button.setText("Hello, World");
        button.show();
        app.exec();
    }
} *g_app;

int main(int argc, char *argv[])
{
    g_app = new QxAppShell;
    while(true)
        QThread::msleep(1);
    return 0;
}

Программа отображает кнопку.
При попытке растянуть окно кнопки - всё получается и окно перерисовывается. А вот при попытке сузить окно кнопки, зона окна сужается без перерисовки.
Так же при попытке кликнуть на кнопку не видно отрисовки нажатия.


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: Igors от Май 13, 2016, 17:32
А что, гугл теперь не в моде?
http://stackoverflow.com/questions/25025168/event-loop-in-qt-based-dll-in-a-non-qt-application
И что, сразу все становится ясно?  :)

При попытке растянуть окно кнопки - всё получается и окно перерисовывается.
Да тоже калечно рисуется. Вы как-то "уперлись в кнопку" поставив задачу "пусть UI работает в другой (не главной) нитке". А стоит ли? Это может оказаться непростым, а то и недостижимым. но что Вы с этого будете иметь?  Как планируете организовать общение с "не Qt" частью?


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: Bepec от Май 13, 2016, 17:40
Ну на деле то всё происходит в главной нитке, угу.
Т.е. в принципе окно нарисовать там вполне реально. И даже работать оно будет, тут главное имитировать сообщения винды, которые собой являют катализатор оконных процессов :D


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: neosapient от Май 13, 2016, 20:10
Да тоже калечно рисуется. Вы как-то "уперлись" поставив задачу "пусть UI работает в другой (не главной) нитке". А стоит ли?

Как я писал в начале: есть приложение, которое создано не мной. Давайте вообразим что-нибудь большое и неповоротливое, сложно проектируемое и требующее огромного количества человекочасов для переписывания на Qt. Пусть это будет 1С Бухгалтерия (чур без обид  ;) 1С хороша по своему)  - я не могу такую огромную программу переписать на Qt в адекватные сроки.

Мне надо всего лишь пропатчить чужую программу согласно предоставленному ей АПИ. Программа имеет свой собственный цикл обработки сообщений. Я не вижу способа как то вклиниться в этот цикл и заставить ядро Qt функционировать в главном потоке основной программы.

Всё что я могу: заставить программу вызвать из моей dll какую то функцию. Соответственно, я хочу сделать так, чтобы при вызове моей функции запускался поток, который запускал ядро Qt, которое запускало свой собственный цикл обработки сообщений.


В итоге я хочу показывать окно с настройками для своего патча/подпрограммы.
Собственно, я уже сделал этот патч на MFC. Но код выходит неповоротлив и некрасив. А когда меня попросили отображать данные не таблицей, а деревом - я вообще взвыл и решил перейти на Qt, благо тут используется паттерн MVC.

тут главное имитировать сообщения винды, которые собой являют катализатор оконных процессов :D
Да, задача перехватить сообщения от винды и направить в Qt'шный поток в QEventLoop. Вопрос как это всё сделать?


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: Igors от Май 13, 2016, 22:55
Да, задача перехватить сообщения от винды и направить в QT'шный поток в QEventLoop. Вопрос как это всё сделать?
Тут немного поизучал

1) Создать QApplication в др потоке можно, но тогда устанавливается другой EventDispatcher, который сделан как-то коряво, во всяком случае в Qt 5.4.2. Он получает сообщения Вындоуз но не выполняет их как "нормальный" EventDispatcher, а большинство держит в очереди. Короче - на нормальную работу с UI он явно не рассчитан. Не видно как подменить его на нормальный, а даже если и удастся - надо ждать новых сюрпризов.

2) Совершенно непонятно зачем крутить QApplication в др нитке, как тогда Вы представляете получение события OC? В похожей ситуации я действовал так:

- на старте приложения создал QApplication, просто в главной нитке, Когда пришла пора "показать Qt окно" просто крутил processEvents. Для модального Qt окна проблем вообще нет. Для немодального появляется возня с переключением обработчика событий на Qt и обратно - но она победима. Вот собсно и все

[off]QT = QuickTime[/off]


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: Igors от Май 14, 2016, 10:27
Все-таки оживить пример можно, оставили лючок. Нужно добавить в проект путь к qwindowsysteminterface.h и тогда
Код
C++ (Qt)
#include <QtWidgets>
#include <QThread>
#include <qwindowsysteminterface.h>
 
class QxAppShell: public QThread
{
public:
   QxAppShell()
   {
moveToThread(this);
QThread::start();
   }
 
   void run() Q_DECL_OVERRIDE
   {
int argc = 0;
char * argv = 0;
 
QApplication app(argc, &argv);
QWindowSystemInterface::setSynchronousWindowsSystemEvents(true);
 
QPushButton button;
       button.setText("Hello, World");
       button.show();
       app.exec();
   }
 
} *g_app;
 
int main(int argc, char *argv[])
{
   g_app = new QxAppShell;
 
   while (true)
       QThread::msleep(1);
 
   return 0;
}
Но это явно то чего делать не следует  :)


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: neosapient от Май 14, 2016, 12:31
Все-таки оживить пример можно, оставили лючок. Нужно добавить в проект путь к qwindowsysteminterface.h и тогда...
Но это явно то чего делать не следует  :)

Спасибо! Заработало.
Скажите, а как вы дошли до этой функции setSynchronousWindowsSystemEvents()? Я в своих многодневных поисках близко к ней не подошел ))

P.S.
Вероятно QML подгружается из dll и способен работать в дочернем потоке загрузившей его программы.

P.P.S.
Сейчас тестирую - ищу грабли ))


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: Igors от Май 14, 2016, 13:10
а как вы дошли до этой функции setSynchronousWindowsSystemEvents()?
Навесил фильтр, посмотрел откуда приходит MouseButtonPress если все в главной нитке. Сравнивая этот вариант с Вашим (а там не приходит) нашел почему.

Сейчас тестирую - ищу грабли ))
Еще раз обращаю Ваше внимание что обработка UI событий "не из главной нитке" у них порезана совершенно сознательно, умышленно. Значит резоны (они же грабли) есть. И нет никаких гарантий что их удастся обойти.

В Вындоуз окно может получать месяги в той (и только в той) нитке где оно было создано. Поэтому запустив QApplication в "не главной" Вы никак не сможете ловить события приходящие др окнам. Др словами получаете "2 обработчика событий параллельно" - вот уж не знаю что Вы с ними будете делать. Ну ладно, "я предупреждал"  :)


Название: Re: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы
Отправлено: lit-uriy от Май 15, 2016, 18:07
я так и не понял почему в отдельный поток усиленно пихалось приложение на Qt.

Здесь, на форуме, были темы о том, как сделать dll-ку с QAplication и GUI и вызывать её из стороннего приложения.