GUI зависает при использовании Windows::SetParent на QApplication

Речь идет о связи двух программ Qt под Windows. Одна программа, назовем его Client, другая программа, называемая Server. Ситуация: я хочу разместить Клиента внутри QWidget сервера. Windows уже предоставляет несколько хороших методов для удаления оформления (границы, строки заголовка и т. Д.) И изменения родительского элемента окна, поэтому перерисовка, изменение размера, активация окна все заботятся Windows. Когда я запускаю свой клиент с помощью QProcess, я жду его запуска, чтобы появилось окно, с которым я могу поговорить. Затем я удаляю украшение и устанавливаю QWidget Сервера как родительский. Все сделано с этим кодом:

winHandle = ::FindWindowA(NULL, "My Client");//get clients window id
if(winHandle != NULL)
{
   ::ShowWindow(winHandle, SW_HIDE);

    // Remove the window border
    LONG lStyle = GetWindowLong(winHandle, GWL_STYLE);
    lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); 
    ::SetWindowLong(winHandle, GWL_STYLE, lStyle);

    ::SetParent(winHandle, (HWND)(ui->widget->effectiveWinId()));//set the server's widget to be the parent of the client win
    ::SetWindowPos(winHandle, HWND_TOP, ui->widget->pos().x(), ui->widget->pos().y(), 0, 0 , SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_ASYNCWINDOWPOS);

     ::UpdateWindow(winHandle);
     ::ShowWindow(winHandle, SW_SHOW);
 }

Все это прекрасно работает, мой клиент хорошо расположен на моей вкладке, и все перерисовки и т. Д. Работают отлично. НО, проблема, с которой я сталкиваюсь, заключается в том, что иногда (не всегда!) Кнопки серверов не реагируют. Я заметил, что когда происходит такой случай, кнопки не реагируют, пока они расположены в середине экрана. но самое странное то, что если я переместлю все окно, чтобы кнопки были расположены близко к краю экрана - они работают! если я перенесу его обратно в центр - они снова перестанут работать. любая идея?? кто то?

Я пробовал также следующий код:

        QWindow * window = QWindow::fromWinId((WId) winHandle);
        QWidget * widget = QWidget::createWindowContainer(window);
        widget->setParent( ui->widget);
        QVBoxLayout *layout = new QVBoxLayout();
        layout->addWidget(widget);     
        ui->widget->setLayout(layout);

с этим решением графический интерфейс не зависал, но клавиатура теперь не работает в окне клиента - во внутреннем окне. например - если внутреннее окно - блокнот - я не могу напечатать в нем, но я могу использовать мышь. есть идеи что можно сделать?

2 ответа

Решение

Вы можете попытаться сделать это, получив QWindow для родного окна, а затем создать QWidget обертка для него. Для этого требуется как минимум Qt 5.2.

Например:

HWND winHandle = ::FindWindowA(NULL, "My Client");
if (! winHandle) return;
QWindow * window = QWindow::fromWinId((WId)winHandle);
if (! window) return;
QWidget * widget = QWidget::createWindowContainer(window);
if (! widget) return;
// At this point you can use Qt to change window flags, reparent/embed, etc.

Вы должны спросить winHandle о его минимальном и максимальном размере и передать их на widget, Вы также должны разрешить widget быть сосредоточенным, если вы собираетесь взаимодействовать с ним.

Очистите стиль WS_POPUP для окна, которое нужно восстановить, и установите вместо него бит WS_CHILD. В противном случае, я думаю, что SetParent фактически устанавливает отношения владелец / владелец, а не отношения родитель / потомок.

Когда вы перемещаете дочерний объект, он должен быть в клиентских координатах родителя. Тот факт, что вы используете экранные координаты, является хорошим признаком того, что у вас нет правильных отношений между родителями и детьми. (Это также согласуется с пользовательским интерфейсом, работающим в верхнем левом углу экрана, где экранные координаты будут очень близки к координатам клиента.)

Несмотря на негативные комментарии, можно заставить все работать с кросс-процессными родительскими / дочерними окнами. Тем не менее, это может быть сложным, чтобы понять это правильно.

Другие вопросы по тегам