现象
通过Qt提供的QWidget::createWindowContainer()方法得到外部exe的QWidget容器,添加到自己程序的主窗口中,成功实现exe的嵌入,鼠标交互与页面都没有问题,但是在改变主窗口大小后,外部嵌入的窗口绘制出现了残留,现象代码如下:
WId Id = (WId)FindWindowA("外部exe类名","外部exe名");
ui.wWindow = QWindow::fromWinId(Id);
if(wWindow)
{
wContainer = QWidget::createWindowContainer(wWindow,this);
}
if(wContainer)
{
ui.dockwidget->setWidget(wContainer);
}
解决方案
1.Qt提供方案(未能解决本人问题,大家可自行尝试)
// 使用Qt的窗口容器API
QWindow *externalWindow = QWindow::fromWinId((WId)hwndChild);
QWidget *container = QWidget::createWindowContainer(externalWindow, this);
// 关键设置
container->setAttribute(Qt::WA_TranslucentBackground);
container->setAttribute(Qt::WA_OpaquePaintEvent, false);
container->setAttribute(Qt::WA_NoSystemBackground, true);
container->setContentsMargins(0, 0, 0, 0);
// 重要:启用持续更新
container->setUpdatesEnabled(true);
2.仅适用于Windows平台,使用Windows提供的API设置窗口属性后,再利用Qt做嵌入(成功解决窗口重绘的问题,但是影响了鼠标缩放功能,鼠标点击事件的响应也变得卡顿)
WId Id = (WId)FindWindowA("外部exe类名","外部exe名");
ui.wWindow = QWindow::fromWinId(Id);
if(wWindow)
{
HWND hwndAdView = (HWND) Id;
SetWindowLongPtr((HWND)Id,
GWL_STYLE,GetWindowLongPtr((HWND)Id,GWL_STYLE) | WS_CLIPCHILDREN);
LONG_PTR exStyle = GetWindowLongPtr(hwndAdView, GWL_EXSTYLE);
SetWindowLongPtr(hwndAdView,GWL_EXSTYLE, exStyle | WS_EX_COMPOSITED);
LONG style = GetWindowLong(hwndAdView, GWL_STYLE);
SetWindowLong(hwndAdView, GWL_STYLE, style & ~(WS_CAPTION | WS_THICKFRAME));
wContainer = QWidget::createWindowContainer(wWindow,this);
}
if(wContainer)
{
ui.dockwidget->setWidget(wContainer);
}
3.鼠标缩放事件不响应排查后确定为窗口样式导致,在2所示的代码中,去掉窗样式WS_EX_COMPOSITED,改为SetWindowLongPtr(hwndAdView,GWL_EXSTYLE, exStyle);鼠标的缩放功能可以用了,完美解决。
但目前博主并未找到更好的跨平台方法,如有其他更好的方法请各位大神指教。