Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Caduceus от Сентябрь 02, 2009, 21:39



Название: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 02, 2009, 21:39
Все дело под Windows.
Есть формочка с кучей кнопок, контролов. И есть один виджет, который явлется просто указателем места, над которым я создаю свое окно. Причем окно это создается в другом потоке. Родитель этого окна - то что возвращает этот виджет через winId. Окно создает, все нормально работает. Но: все конролы на форме недоступны, то есть видны, но не нажимаются. И сразу после того, как я пытаюсь запустить Spy++, вываливается ошибка, что QAppication шлет евент объекту, созданному в другом потоке.

Вот такая штука. Запустался уже.  Что это может быть?


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Па
Отправлено: Авварон от Сентябрь 02, 2009, 22:09
нельзя создавать окна в потоке, отличном от главного


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 02, 2009, 22:12
если я создаю окно в главном потоке, то весь цикл обработки его сообщений гасит вообще все - весь главный ГУИ просто умирает и не отрисовывается, не то что отвечать на нажатия


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Па
Отправлено: ufna от Сентябрь 02, 2009, 22:25
значит, нужно что то модифицировать. Опиши поподробней, что делает это окно.


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 02, 2009, 22:28
Это второе окно - прикрученный к Qt-шной проге игровой движок.
В нем все хорошо там крутиться. На события мыши и клавы реагирет. А вот Qt-шный GUI не нажимается.
Более того, если внутрь второго окна не нажмать, то Qt-шное таскается и ресазиться, а если по второму окну кликнуть (там анимация проигрывается), то qt-ное окно перестает отвечать на сдивги за заголовок и ресайзы за уголки. Надо щелкнуть вообе на другуое приложние, потом щелкуть на qt-шное окно — и вот огда оно реагирует на перемещения и ресайзы, хотя контролы все равно не нажимаются


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: BlackTass от Сентябрь 03, 2009, 00:57
Почему бы не пробрасывать обработку в отдельный тред, откуда она тоже соответственно будет пробрасываться обратно на отрисовку?


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 03, 2009, 08:43
Все что касается этого нативного окна и так в отдельном потоке. Вопрос немного перефразирую - не отслеживает ли Qt все дочерние окна (даже если они не qt шные а наивные) и не рулит ли как-то их циклом обработки сообщений сам?


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Tonal от Сентябрь 03, 2009, 10:23
Я уже на rsdn-е ответил: во втором потоке нужен свой цикл выборки сообщений.


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 03, 2009, 10:44
Так там он, там. Во втором потоке


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: BlackTass от Сентябрь 03, 2009, 11:11
если в главном потоке обработка событий сводится к эмитам и при этом умирает гуй, то сколько же там валится событий?


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 03, 2009, 11:16
Игровой движок, можно представить что там куча всего.
НО! есть одно НО. Я делал те же самые действия, то только через ActiveX - то есть я создавал ATLный ActiveX - в нем над окном Конрола создавал во втором потоке окно движка и ВСЕ суперско работало. Я кидал этот контрол на C#-ную форму и все зашибись

Сейчас я это дело перевел на Qt - то есть создаю окно движка надQt виджетом - и все кроме движка засыпает...

Продебажил конкретно вглубь Qt - при нажатии на конролы он даже в QtWndProc не заходит. Кто-то конкретно перехватывает это все дело.


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: BlackTass от Сентябрь 03, 2009, 13:40
там ваших собственных событий куча или каких? если ваших собственных смело кидайте их в другой поток да и все. У вас точно во втором потоке eventLoop работает в этом самом втором потоке, а не в гуевом?


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 03, 2009, 13:43
моих сообщений там вобще никаких нету. Цикл нативного окна 100% во втором потке.
Всё, уже не знаю куда копать. Все перепробовал


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: BlackTass от Сентябрь 03, 2009, 13:45
ну так как libastral и телепатия пока еще только развиваются, я думаю стоит выложить исходники (желательно обрезанные до самого минимума).


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 03, 2009, 14:01
О, получилось воспроизвести без игрового движка. Короче, есть наиримитвнейшая формочка с двумя кнопками и кастомным виджетом. При нажатии на кнопку кастомному виджету шлтеся сигнал. Вот функция слота:

Код:
void   EngineWidget::StartEngine()
{
if (m_hThread)
return;
DWORD    dwThreadId      = -1;
if ((m_hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadFunc,
(LPVOID)this, 0, &dwThreadId)) != NULL)
{
;
}
}

Примитивно? Примитивно. А сейчас вот самое интересное - потоковая функция threadFunc:
Код:
static DWORD WINAPI threadFunc(LPVOID pWidg)
{  
     QWidget* wdt = (QWidget*)pWidg;

WNDCLASSEX windowClass;
HINSTANCE engineInstance;
HWND engineWindow;

HINSTANCE h = ::GetModuleHandle(QApplication::applicationFilePath().toAscii());

windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_NOCLOSE | CS_OWNDC;
windowClass.lpfnWndProc = &DefWindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = engineInstance;
windowClass.hIcon = nullptr;
windowClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
windowClass.hbrBackground = nullptr;
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = APPLICATION_NAME;
windowClass.hIconSm = nullptr;
RegisterClassEx(&windowClass);

// RA changes
engineWindow = CreateWindow(APPLICATION_NAME, APPLICATION_NAME, WS_CHILD|WS_VISIBLE, 0, 0, 1280, 1024, (HWND)wdt->winId(),
nullptr, h, nullptr);

// RA changes
SetFocus(engineWindow);
SetCursor(windowClass.hCursor);

do
{

MSG message;

while (PeekMessage(&message, engineWindow, 0, 0, PM_REMOVE))
{
DispatchMessage(&message);
}
}while(true);
return FALSE;
}

Во. Вот если так сделать - то все кнопки на qt-шной форме перестают нажиматься. Это я в очень приближенной форме написал как работает окно игрового движка. Разумеется там не DefWindowProc оконная функция, но и так уже виснет.

Кто что думает?

PS Предвижу сразу фразы типа "Ага, у тебя нативное окно прям поверх всего делается из угла окна - кординаты 0 -0". Отвечу - опускал я это окно, было оно точно под кнопками, то есть кнопки не перекрывало - но они все равно не нажимались


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 03, 2009, 14:11
А вот как это выглядит с движком:


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 03, 2009, 21:48
Тот минимальныйпример что я привел никого на мысль не натолкнул?


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Tonal от Сентябрь 04, 2009, 08:28
Я как-то наткнулся на то, что если для окна не реализовать обработку WM_GETTEXT + WM_GETTEXTLEN, то любой кто попросит его имя - зависнит. :)
Например зависала функция FindWindow если не указан класс. Причём в любом приложении. :)

Посмотри в исходники Qt/MFC Migration Framework (http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Windows/qtwinmigrate/)
Может поможет.

Кстати, гугель, по запросу "winapi child window in other thread" выдал интересную ссылку:
http://www.eggheadcafe.com/software/aspnet/33723942/childrenparent-window-in.aspx


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 04, 2009, 08:56
Спасибо большое.
ОБработка WM_GETTEXT + WM_GETTEXTLEN ситуацию не изменило. А вот Ваша сссылка с Гугла оченно меня огорчила. Дело значит совсем не в Qt.

Не понтяно тогда, почему если я это окно вешаю над ActiveX -ом, то все нормально...


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Tonal от Сентябрь 04, 2009, 09:57
Про WM_GETTEXT я привёл просто для примера, не ожидая что они на что-нибудь повлияют.
По ссылке, вроде упоминали о каких-то обходных путях?

Про ActiveX - точно не уверен, но, возможно там не настоящее дочернее окно - не даром протокол встраивания дублирует функции и события WinApi.
В любом случае, MS туда очень много наворочили...


Название: Re: Создаю свое окно, дочернее к qt-шному через CreateWindow в другом потоке. Падает
Отправлено: Caduceus от Сентябрь 04, 2009, 10:08
Ураа, проблема решена. Видимо, если выносить окно в отделный поток, то гасится только цикл сообщений родителя этого кона в другом потоке. У меня сначала гасились все сообщения моего диалога, так как оно было родителем окна из второго потока. Выход из ситуации - сделать окно-заглушку в первом потоке и уже оно будет родителем окна во втором потке. То есть его цикл может и гасится - но пофигу становится. Именно поэтому у меня и работало с ActiveX-ом - там же ActiveX сам был этим окном-заглушкой.
И сейчас у меня полнофункциональная красота: