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
QWidgets
and, ideally, I'd be using aQGridLayout
so that both of theQWidgets
fill 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
Map
into 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
QWidget
on top of aQQuickWidget
and to allow the child to fill theQQuickWidget
entirely. The problem with doing this is that firstly, I need to use thewinId
of the top-mostQWidget
in 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 cangrab
the rendered QML and draw it as aQImage
onto myQWidget
as 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
QQuickItem
which 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
QQuickWidget
and theQWidget
but 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
QImage
appears 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.