[SOLVED] How to draw a transparent hole inside a QQuickView / QQuickWindow based on a custom QQuickItem?
-
Hello,
I have the following problem, I do not manage to create a transparent hole inside a QQuickView, through a customed QQuitItem.Here is what I have:
- a C++ custom QQuickItem, CustomQQuickItem, which is registered in qml so I can access it from a QML file
- a C++ main application, creating a QQuickView.
- a main QML file as follows:
@import QtQuick 2.0
import LWQQuickItem 1.0Rectangle {
id:idScreenUIZ0_0
width: 800
height: 480
color: "blue"CustomQQuickItem { id: idCustomQuickItem x: 100 y: 100 width: 500 height: 100 }
}@
I would like my CustomQQuickItem instance to 'draw' transparency in the QQuickView with the given position and size (100,100,500,100).
So I overrode the QSGNode * updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) method of the QQuickItem to do this transparent hole.
@QSGNode * LWQQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{// retrieve window in which the QQuickItem is drawn // Returns the window in which this item is rendered. QQuickWindow *pQQuickWindow; pQQuickWindow = QQuickItem::window(); if (pQQuickWindow != NULL) { // Here I would like to draw a transparent area in the window itself pQQuickWindow->setColor(QColor(0,0,0,0)); ; } else { qDebug()<<"qquickwindow not found!"; } //Not sure what I should return here return oldNode;
}
@Anyone has any idea if this is possible at all? basically, is it possible to:
- either draw directly in the underlying window a transparent area ?
- or define a specific scene graph node that will draw a transparent area in the rendering window?
Thank you for providing me any hint to help me achieve this.
Regards,
Bill -
I don't think you're going to be able to take the approach you're presenting. An item on top of another item can't "erase" it's parent. If the overlayed item is transparent, it's just going to show its parent behind it.
If you want a rectangular "hole" in a solid background, you could always fake it using a container item and four solid panels to fill in around your transparent area...
@
Item {
id:idScreenUIZ0_0
width: 800
height: 480Rectangle { // The "Hole" id: hole color: "transparent" x: 100 y: 100 width: 500 height: 100 } Rectangle { id: leftpanel color: "blue" anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: hole.left } Rectangle { id: rightpanel color: "blue" anchors.left: hole.right anchors.right:parent.right anchors.top: parent.top anchors.bottom: parent.bottom } Rectangle { id: toppanel color: "blue" anchors.top: parent.top anchors.bottom: hole.top anchors.left: leftpanel.right anchors.right: rightpanel.left } Rectangle { id: bottompanel color: "blue" anchors.top: hole.bottom anchors.bottom: hole.bottom anchors.left: leftpanel.right anchors.right: rightpanel.left }
}
@
Brain to terminal, ymmv -
Thank you,
But I really need to draw a transparent area inside a QQuickView that may first render opaque elements under my hole and then even other opaque elements on top of my hole. I see my requirement as some kind of mask, that could be also overlapped by other opaque elements, depending on the rendering sequence. I hope my need is clearly expressed here.I am sure this must be possible, and I agree to say that my approach is not right to achieve this, that's why I am looking for the right approach!
Unfortunately I am not very familiar with this SG stuff, and really need to get some competence in this domain :=)Thank you for your proposal, but sadly it won't satisfy my use case.
Regards,
Bill -
You can use the same kind of thing as above, but utilize different Z properties for your items. By setting the Z depth you can draw things stacked however you want them rather than having to rely on the order that they're drawn.
-
I must not have been clear enough in my explanations, and I am sorry about it.
Let's imagine I have a full screen background image, and now i want to draw a transparent hole in this background image (to begin with, and any shape maybe later), of any dimension, at any location, at any moment, want to be able to actually activate or deactivate this hole at run time. And on top of that, I would lile to be able to draw other smaller opaque elements over the transparent created hole, event elements that could partially cover the transparent region and bit of the background image still visible.Is this explanation clearer now?
Regards,
Bill -
So, if you have a background image and you cut a hole in it arbitrarily, what is to be shown behind it?
Perhaps I'm still not understanding, but again, though, one item cannot "paint transparency" onto another item to erase part of the separate item.
-
I would like to see any other application window displayed underneath my Qt application.
But I don't think that the QQuickItem is a good approach, because I am not sure I can define a SGNode able to modify parent nodes to change basically their alpha values. Or maybe it is possible?Maybe I shall try with the Qt Graphical Effects, or a simple shader, but still not sure if my shader could apply to my background image though...
I am gonna make a visual illustration of what I would like to achieve so you can get the whole picture.
Regards,
Bill -
Here you go, is the use case clear now?
!http://i46.tinypic.com/10fb0g3.png()! -
Finally achieved my goal BUT WITHOUT CUSTOM QQUICKITEM, I rather used a QGraphicalEffect / Mask
main.cpp
@int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);QtQuick2ApplicationViewer viewer; viewer.setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format; format.setAlphaBufferSize(8); format.setRenderableType(QSurfaceFormat::OpenGL); qDebug() << format.hasAlpha(); viewer.setFormat(format); QColor color; color.setRedF(0.0); color.setGreenF(0.0); color.setBlueF(0.0); color.setAlphaF(0.0); viewer.setColor(color); viewer.setClearBeforeRendering(true); //viewer.setFlags(Qt::FramelessWindowHint); viewer.setMainQmlFile(QStringLiteral("qml/MaskTest/main.qml")); viewer.showExpanded(); return app.exec();
}
@main.qml
@
import QtQuick 2.0
import QtGraphicalEffects 1.0
import "."Item {
id: idRoot
width: 800
height: 480Image { id: idBackGround x: 0 y: 0 width: 800 height: 480 source: "../../resource/background.jpg" visible: false } RectangularMask { id: idRectangularMask transpX: idSliderX.value transpY: idSliderY.value transpWidth: idSliderW.value transpHeight: idSliderH.value visible: false } OpacityMask { anchors.fill: idRoot source: idBackGround maskSource: idRectangularMask } Image { id: idTop x: 200 y: 200 source: "../../resource/top.png" } Slider { id: idSliderX x:100 y: 440 width: 200 minimum: 0 maximum: 800 } Slider { id: idSliderY x:100 y: 460 width: 200 minimum: 0 maximum: 480 } Slider { id: idSliderW x:350 y: 440 width: 200 minimum: 0 maximum: 800 } Slider { id: idSliderH x:350 y: 460 width: 200 minimum: 0 maximum: 480 }
}
@RectangularMask.qml
@import QtQuick 2.0Item {
property int transpX: 0
property int transpY: 0
property int transpWidth: 0
property int transpHeight: 0width: 800 height: 480 Rectangle { color: "transparent" Rectangle{ x:0 y:0 width: 800 height: transpY color: "black" } Rectangle{ x:0 y:transpY+transpHeight width: 800 height: 480-y color: "black" } Rectangle{ x:0 y:0 width: transpX height: 480 color: "black" } Rectangle{ x:transpX+transpWidth y:0 width: 800 - x height: 480 color: "black" } }
}
@Slider.qml
@import QtQuick 2.0Item {
id: slider; width: 400; height: 16// value is read/write. property real value: 1 onValueChanged: updatePos(); property real maximum: 1 property real minimum: 1 property int xMax: width - handle.width - 4 onXMaxChanged: updatePos(); onMinimumChanged: updatePos(); function updatePos() { if (maximum > minimum) { var pos = 2 + (value - minimum) * slider.xMax / (maximum - minimum); pos = Math.min(pos, width - handle.width - 2); pos = Math.max(pos, 2); handle.x = pos; } else { handle.x = 2; } } Rectangle { anchors.fill: parent border.color: "white"; border.width: 0; radius: 8 gradient: Gradient { GradientStop { position: 0.0; color: "#66343434" } GradientStop { position: 1.0; color: "#66000000" } } } Rectangle { id: handle; smooth: true y: 2; width: 30; height: slider.height-4; radius: 6 gradient: Gradient { GradientStop { position: 0.0; color: "lightgray" } GradientStop { position: 1.0; color: "gray" } } MouseArea { id: mouse anchors.fill: parent; drag.target: parent drag.axis: Drag.XAxis; drag.minimumX: 2; drag.maximumX: slider.xMax+2 onPositionChanged: { value = (maximum - minimum) * (handle.x-2) / slider.xMax + minimum; } } }
}
@ -
I still have an issue related now to the Mask / QGraphicalEffect itself... Will look for it later...
The effect is working, here the result:
http://www.youtube.com/watch?v=aPPu--7IzuYRegards,
Bill