Russian Qt Forum
Ноябрь 22, 2024, 22:52 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Запустил QApplication и GUI из дочернего потока, но не отрабатывают сигналы  (Прочитано 8767 раз)
neosapient
Гость
« : Май 13, 2016, 02:06 »

Здравствуйте.

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

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

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


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

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

[Qt5.4, VC9, Win7]
« Последнее редактирование: Май 14, 2016, 11:18 от neosapient » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Май 13, 2016, 05:07 »

Наверняка слышали
Цитировать
UI только в главном потоке
Каких-то внятных/убедительных пояснений "почему так" я не слышал. Но, пытаясь делать не главном, приключений найдете массу - это точно.

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

Сообщений: 2812


Просмотр профиля
« Ответ #2 : Май 13, 2016, 08:28 »

А что, гугл теперь не в моде?
http://stackoverflow.com/questions/25025168/event-loop-in-qt-based-dll-in-a-non-qt-application
Записан

ArchLinux x86_64 / Win10 64 bit
Bepec
Гость
« Ответ #3 : Май 13, 2016, 12:01 »

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

Записан
neosapient
Гость
« Ответ #4 : Май 13, 2016, 13:24 »

По сути запустив окошко, мы должны перенаправить в него оконные сообщения. Или же имитировать их.
Да, нехватку этой части я и наблюдаю в своей тестовой программе. Но не пойму, как реализовать.
Записан
neosapient
Гость
« Ответ #5 : Май 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;
}

Программа отображает кнопку.
При попытке растянуть окно кнопки - всё получается и окно перерисовывается. А вот при попытке сузить окно кнопки, зона окна сужается без перерисовки.
Так же при попытке кликнуть на кнопку не видно отрисовки нажатия.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Май 13, 2016, 17:32 »

И что, сразу все становится ясно?  Улыбающийся

При попытке растянуть окно кнопки - всё получается и окно перерисовывается.
Да тоже калечно рисуется. Вы как-то "уперлись в кнопку" поставив задачу "пусть UI работает в другой (не главной) нитке". А стоит ли? Это может оказаться непростым, а то и недостижимым. но что Вы с этого будете иметь?  Как планируете организовать общение с "не Qt" частью?
Записан
Bepec
Гость
« Ответ #7 : Май 13, 2016, 17:40 »

Ну на деле то всё происходит в главной нитке, угу.
Т.е. в принципе окно нарисовать там вполне реально. И даже работать оно будет, тут главное имитировать сообщения винды, которые собой являют катализатор оконных процессов Веселый
Записан
neosapient
Гость
« Ответ #8 : Май 13, 2016, 20:10 »

Да тоже калечно рисуется. Вы как-то "уперлись" поставив задачу "пусть UI работает в другой (не главной) нитке". А стоит ли?

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

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

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


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

тут главное имитировать сообщения винды, которые собой являют катализатор оконных процессов Веселый
Да, задача перехватить сообщения от винды и направить в Qt'шный поток в QEventLoop. Вопрос как это всё сделать?
« Последнее редактирование: Май 14, 2016, 11:19 от neosapient » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Май 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]
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Май 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;
}
Но это явно то чего делать не следует  Улыбающийся
« Последнее редактирование: Май 14, 2016, 10:29 от Igors » Записан
neosapient
Гость
« Ответ #11 : Май 14, 2016, 12:31 »

Все-таки оживить пример можно, оставили лючок. Нужно добавить в проект путь к qwindowsysteminterface.h и тогда...
Но это явно то чего делать не следует  Улыбающийся

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

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

P.P.S.
Сейчас тестирую - ищу грабли ))
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Май 14, 2016, 13:10 »

а как вы дошли до этой функции setSynchronousWindowsSystemEvents()?
Навесил фильтр, посмотрел откуда приходит MouseButtonPress если все в главной нитке. Сравнивая этот вариант с Вашим (а там не приходит) нашел почему.

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

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

Сообщений: 3880


Просмотр профиля WWW
« Ответ #13 : Май 15, 2016, 18:07 »

я так и не понял почему в отдельный поток усиленно пихалось приложение на Qt.

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

Юра.
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.089 секунд. Запросов: 23.