我需要在QML应用程序中显示Windows本机窗口。
一个有效的解决方案是利用QWindow::fromWinId和QWidget::createWindowContainer方法" throw"将窗口转换为QWidget。然后我们从QML中获取一个项目并强制将这个小部件移动到"镜像"物品的尺寸和位置。
以下代码段演示了可能的实现方式 (注意:这些代码段被解释并且没有错误检查)
main.qml 的
ID为" target"的矩形被传递到MyInterfaceObject的targetObject属性。
Rectangle {
id: app
.
.
Rectangle {
id: target
MyInterfaceObject {
targetObject: target
.
.
}
}
MyInterfaceObject.cpp
MyInterfaceObject是一个具有QVariant targetObject属性的QObject。它需要一个理想的窗口处理和"抛出"它到一个小部件上。然后,它启动一个计时器,将嵌入的窗口小部件映射到targetObject的位置。
可能会根据某些targetObject信号而不是计时器更新,但由于我最初在Flickable上进行了测试,因此无效。
// Find the window by it's title
HWND windowHandle = ::FindWindow(0, L"Your Window Title");
// "Throw" window into a widget
QWindow *embeddedWidgetWindow = QWindow::fromWinId((WId)windowHandle);
// the quickWidget is created in main.cpp
QWidget *embeddedWidget = QWidget::createWindowContainer(embeddedWidgetWindow, quickWidget);
embeddedWidget->show();
embeddedWidgetWindow->show();
quickWidget->show();
// Start a timer that will enforce the "mirroring" effect
QTimer* timer = new QTimer;
timer->setInterval(1);
timer->start();
timer->connect(timer, &QTimer::timeout, [this](){
// targetObject is the QVariant form of the target QML object from our main.qml
auto quickItem = this->targetObject().value<QQuickItem*>();
// Map our widgets position/dimensions to our target qml object
auto scenePos = quickItem->mapToItem(0, quickItem->position());
auto myX = scenePos.x() - quickItem->position().x();
auto myY = scenePos.x() - quickItem->position().y();
embeddedWidget->setGeometry(myX, myY, quickItem->width(), quickItem->height());
});
main.cpp
// The widget that will parent our native window widget
QQuickWidget* quickWidget= new QQuickWidget;
quickWidget->setSource(QUrl(QStringLiteral("qrc:/main.qml")));
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
// Give our InterfaceObject access to this quickWidget
InterfaceObject::setQuickWidget(quickWidget);
嵌入式小部件将成功跟踪我的QML对象。但是,当设置在Flickable时,小部件在滚动或拖动时会暂时落后一点。
我的第二个解决方案与上述类似,涉及QScreen::grabWindow方法和QuickQuickPaintedItem。
MyInterfacePaintedItem.cpp
// Do this for every paint event
// Find the window by it's title
HWND windowHandle = ::FindWindow(0, L"Your Window Title");
auto quickItem = this->targetObject().value<QQuickItem*>();
// can also "throw" the native window into a widget like above and
// use that widgets winId (widget->winId())
auto pixmap = QGuiApplication::primaryScreen()->grabWindow((WId)windowHandle)
painter->drawPixmap(QRect(0, 0, quickItem->width(), quickItem->height()),
pixmap,
pixmap.rect());
此解决方案适用于我传递的每个窗口,除了我想要的窗口。我留下了一张空的白色图像,而不是所需的图像。
我尝试将BitBlt与QtWin :: fromHBITMAP(usage)结合使用,但这对我的特定窗口也不起作用。我总是得到像上面的非工作解决方案一样的白色图像。 (Potential cause)。
答案 0 :(得分:0)
利用DwmRegisterThumbnail,您可以在QML应用程序内的任何位置显示本机OpenGL窗口。从我头顶上移下来的步骤是:
将DWM dll添加到QMake
win32:LIBS += -ldwmapi.dll
向QML应用程序注册本机应用程序的缩略图
DWM API允许您通过传递源(缩略图所有者)和目标窗口的窗口句柄(HWND,而不是WId)来向另一个应用程序注册应用程序缩略图。
注意:目标窗口必须是由调用此函数的进程创建的顶级窗口!
DwmRegisterThumbnail((HWND)window()->winId(), hNativeHandle, hThumbnail);
更新缩略图的大小和位置
现在我们已经在目标窗口中注册了缩略图,我们可以利用DwmUpdateThumbnailProperties函数来控制其在窗口中的大小和位置。阅读有关此功能的DWM API文档,并更新缩略图的大小和位置,以在应用程序中镜像所需的全局大小和位置。我使用放置在应用程序中的QQuickItem,并基于此创建缩略图属性。