在QApplication上使用Windows :: SetParent时,GUI冻结

时间:2014-06-09 08:24:25

标签: qt winapi qwidget setparent

它是关于Windows下的两个Qt程序的通信。  一个程序,让我们称他为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);

使用此解决方案, GUI未冻结但键盘现在无法在客户端窗口中工作 - 在内部窗口中。 例如 - 如果内部窗口是记事本 - 我不能在里面键入,但我可以使用鼠标。 知道可以做什么吗?

2 个答案:

答案 0 :(得分:0)

您可以尝试通过为本机窗口获取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.

您需要询问关于its minimum and maximum sizewinHandle并将其传递到widget。如果您打算与widget进行交互,还需要允许{{1}}成为焦点。

答案 1 :(得分:0)

清除要重新分配的窗口的WS_POPUP样式,并改为设置WS_CHILD位。否则,我认为SetParent实际上建立了一个所有者/拥有的关系,而不是父/子关系。

当你重新定位孩子时,它应该在父母的客户坐标中。您使用屏幕坐标的事实是一个很好的暗示,您没有正确的父/子关系。 (这也与在屏幕左上角附近工作的UI一致,屏幕坐标非常靠近客户坐标。)

尽管有负面评论,但可以使所有内容与跨进程父/子窗口一起使用。也就是说, 可能难以做到正确。