Overlaying QWidgets
-
They could be siblings or further relatives but they do need to have a common ancestor to be placed in the same window.
You have control over the stacking order of such widgets with raise(), lower() and stackUnder().The other option is that they don't have a common ancestor i.e. they become separate windows, but then it becomes a little trickier to handle the various moves, resizes and stacking order.
-
@Chris-Kawa thanks for your reply. There is a common parent for both
QWidgetsand, ideally, I'd be using aQGridLayoutso that both of theQWidgetsfill the entire layout (one underneath each other). I'm pretty sure this won't be possible though. -
No, two widgets in the same layout can't overlay each other. It's the actual job of the layout that they don't. One of them (usually the top one) needs to be "free floating" i.e. not in a layout. Resizing needs to be done manually.
-
That depends on what you want. In a stacked layout only one widget is visible at a time. The others are not drawn. Stack layout is useful to implement something like QTabWidget.
What are you trying to do exactly?
-
I'll give you a cut-down version of what I'm wanting to achieve...
I've posted on this forum previously about my target application and I'm still trying to figure out a nice solution. So basically, I have a 3rd party COM object which draws a "nautical chart" using a Windows GDI DC. I'm also trying to integrate the QML
Mapinto this application for added flexibility for the end user.The only way I've managed to figure out how to get both the QML and COM/DC to play nicely so far is to put a
QWidgeton top of aQQuickWidgetand to allow the child to fill theQQuickWidgetentirely. The problem with doing this is that firstly, I need to use thewinIdof the top-mostQWidgetin order to draw the COM object but with doing this, I then get thousands of QML warnings which I am unable to stop - however, I cangrabthe rendered QML and draw it as aQImageonto myQWidgetas a layer beneath the COM object (I really hope this makes sense so far).Ultimately, this isn't really a nice solution and the QML warnings make further debugging of the application impossible. I have tried other solutions - custom
QQuickItemwhich would draw the 3rd party COM object but this doesn't work. As soon as I go anywhere near awinId, this breaks the QML stuff.My thinking thus far is that if I am able to stack the
QQuickWidgetand theQWidgetbut without setting the any parents then I won't get any of the annoying QML warnings and I'll also be able to quickly swap between the two views.If there is the possibility of off-screen rendering both the QML and the COM then bringing them both together in another single
QWidget, that'd be perfect but my tinkering so far hasn't come up with a workable solution for this.Sorry for the waffle...
-
Maybe instead of trying to marry QML with GDI you could draw with GDI to a bitmap and then paint that in a regular widget's paint event. For example something like this:
class GDIWrapper : public QWidget { public: void paintEvent(QPaintEvent*) override { HDC hDC = CreateCompatibleDC(NULL); DWORD* pSrcData = nullptr; BITMAPINFO bmi = { sizeof( BITMAPINFOHEADER ), width(), height(), 1, 32, BI_RGB, 0, 0, 0, 0, 0}; HBITMAP bitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pSrcData, 0, 0); HGDIOBJ prev_bitmap = SelectObject(hDC, bitmap); DrawSomething(hDC); //this would be the 3rd party draw SelectObject(hDC, prev_bitmap); GdiFlush(); { //scoped so that QImage does not outlive bitmap QImage img ((uchar*)pSrcData, width(), height(), QImage::Format_RGB32); QPainter p(this); p.drawImage(0,0,img); } DeleteObject(bitmap); DeleteDC(hDC); } };Of course you'd need to add the necessary error checking.
You could then easily overlay that over QQuickWidget without the need for native handle (winId):auto gdi_wrapper = new GDIWrapper(); auto quick_widget = new QQuickWidget(QUrl::fromLocalFile(":/some.qml")); quick_widget->setLayout(new QVBoxLayout); quick_widget->layout()->addWidget(gdi_wrapper); -
Maybe instead of trying to marry QML with GDI you could draw with GDI to a bitmap and then paint that in a regular widget's paint event. For example something like this:
class GDIWrapper : public QWidget { public: void paintEvent(QPaintEvent*) override { HDC hDC = CreateCompatibleDC(NULL); DWORD* pSrcData = nullptr; BITMAPINFO bmi = { sizeof( BITMAPINFOHEADER ), width(), height(), 1, 32, BI_RGB, 0, 0, 0, 0, 0}; HBITMAP bitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pSrcData, 0, 0); HGDIOBJ prev_bitmap = SelectObject(hDC, bitmap); DrawSomething(hDC); //this would be the 3rd party draw SelectObject(hDC, prev_bitmap); GdiFlush(); { //scoped so that QImage does not outlive bitmap QImage img ((uchar*)pSrcData, width(), height(), QImage::Format_RGB32); QPainter p(this); p.drawImage(0,0,img); } DeleteObject(bitmap); DeleteDC(hDC); } };Of course you'd need to add the necessary error checking.
You could then easily overlay that over QQuickWidget without the need for native handle (winId):auto gdi_wrapper = new GDIWrapper(); auto quick_widget = new QQuickWidget(QUrl::fromLocalFile(":/some.qml")); quick_widget->setLayout(new QVBoxLayout); quick_widget->layout()->addWidget(gdi_wrapper);@Chris-Kawa Thanks for your suggestion. Looks like a very good one to me - will try this later.
The ultimate solution, I guess, would be using your code in a custom 'QQuickItem' so that I could add it to the QML - then I could make use of additional QML features.
Or maybe I'm trying to push the QML integration too far. I dunno.
-
@Chris-Kawa I've just implemented your suggestion and the resulting
QImageappears to be rotated and flipped. Bizarre! -
Coordinate systems and related data storage often differ between frameworks. If you can't control how the 3rd party organizes its output just set the right flip/rotation using setTransform() on your painter before drawing.