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

Qt 在QApplication上使用Windows::SetParent时GUI冻结,qt,winapi,qwidget,setparent,Qt,Winapi,Qwidget,Setparent,它是关于两个Qt程序在Windows下的通信。 一个程序,我们叫他客户机,另一个程序,叫服务器。 情况: 我想把客户机放在服务器的QWidget中。Windows已经提供了一些删除装饰边框、标题栏等的好方法。。并更改窗口的父窗口,以便重新绘制、调整大小和窗口激活都由Windows负责。 当我使用QProcess启动我的客户机时,我会等待它启动,以便有一个窗口可以与我交谈。然后我移除装饰并将服务器的QWidget设置为父级。 所有操作都使用此代码完成: winHandle = ::FindWind

它是关于两个Qt程序在Windows下的通信。 一个程序,我们叫他客户机,另一个程序,叫服务器。 情况: 我想把客户机放在服务器的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不会冻结,但键盘现在在客户端窗口(内部窗口)中无法工作。 例如,如果内部窗口是记事本,我不能在里面打字,但我可以使用鼠标。
你知道能做什么吗

您可以尝试为本机窗口获取QWindow,然后为其创建QWidget包装器。这至少需要Qt5.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并将其传递到小部件。如果要与小部件交互,还需要允许小部件聚焦。

清除要重新租用的窗口的WS\u弹出样式,并改为设置WS\u子位。否则,我认为SetParent实际上建立了所有者/所有者关系,而不是父/子关系

重新定位子对象时,它应位于父对象的客户机坐标中。使用屏幕坐标的事实很好地暗示了您没有正确的父/子关系。它还与屏幕左上角附近的UI一致,屏幕坐标将非常接近客户端坐标


尽管有负面评论,但可以通过跨进程父/子窗口使一切工作正常。也就是说,要把它做好可能是一个挑战。

跨进程重新租用窗口永远不会有好结果。你不应该这样做。你几乎没有机会把这件事做好。您需要为您的问题找到一个不同的解决方案。您有什么建议吗?在单个进程中运行整个UI。使用Qt,您将没有机会实现这一点。曾经停止做你现在正在做的事情,不要落入“它几乎已经起作用”的陷阱。虽然@David已经提供了一个建议,但这还不够。如果GUI分布在多个线程中,那么您将在单个进程中遇到相同的问题。换句话说:使您的GUI成为单线程的。如果这不是一个选项,您可能希望评估将客户端实现为CLSCTX_LOCAL_SERVER ActiveX控件,这可能会耗尽上下文。@IInspectable not fully有点苛刻。大量未列出且无法在注释中列出的需求。你也没有把它们都列出来。我尝试使用Qt5.1,但没有成功。切换到Qt5.2,现在我没有得到那个错误,窗口嵌入到主窗口中,但你只能看到它的一个非常薄的部分在左手上side@one如何管理小部件的大小?您使用布局管理器吗?你试过设置最小尺寸吗?我添加了一个布局并设置了最小尺寸,现在看起来很漂亮。但现在的问题是,键盘在内部窗口中不工作。@您是否使小部件可聚焦?是的。我使用了widget->setFocusPolicyQt::StrongFocus;控件->设置焦点;小部件->抓取键盘;所以在第一秒钟我就有了keboard,但一旦失去了焦点,我就无法把它带回来