Проблема
Мне нужно собственное окно Windows, отображаемое в приложении QML.
Ограничения
- Приложение в собственном окне (NW) отрисовывается с помощью OpenGL
- NW предназначено только для отображения и не требует ввода данных пользователем
- No 3 rd разрешены сторонние библиотеки
- У вас есть доступ к исходному коду NW
- Примечание: перенос этого конкретного исходного кода в QOpenGLWidget хмурится на
Рабочий раствор
Рабочим решением является использование QWindow :: fromWinId и QWidget ::createWindowContainer методы для «выброса» окна в QWidget.Затем мы берем элемент из QML и заставляем этот виджет «отражать» размеры и положение элемента.
Следующие фрагменты кода демонстрируют возможную реализацию.
(Примечание: эти фрагменты перефразированы и лишены ошибкипроверка)
main.qml
Прямоугольник с идентификатором "target" передается в свойство targetObject объекта MyInterfaceObject.
Rectangle {
id: app
.
.
Rectangle {
id: target
MyInterfaceObject {
targetObject: target
.
.
}
}
MyInterfaceObject.cpp
MyInterfaceObject - это объект QObject, имеющий свойство QVariant targetObject.Он берет нужный дескриптор окна и «выбрасывает» его на виджет.Затем он запускает таймер, который отобразит встроенный виджет на позицию 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());
Это решение работает для каждого окна, которое я передаю, за исключением того, которое я хочу.У меня осталось пустое белое изображение вместо желаемого.
Extra
Я пытался использовать BitBlt в сочетании с QtWin :: fromHBITMAP ( использование ),но это не работает на моем конкретном окне либо.Я всегда получаю белое изображение, как нерабочее решение выше.( Потенциальная причина ).
Среда
- Qt: 5.10.0
- Платформа: Windows 7
- Компилятор:MSVC2015 32 бит