[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.0

    Rectangle {
    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


  • Moderators

    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: 480

    Rectangle {  // 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


  • Moderators

    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


  • Moderators

    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() <&lt; 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&#40;QStringLiteral("qml/MaskTest/main.qml"&#41;);
    viewer.showExpanded();
    
    return app.exec();
    

    }
    @

    main.qml
    @
    import QtQuick 2.0
    import QtGraphicalEffects 1.0
    import "."

    Item {
    id: idRoot
    width: 800
    height: 480

    Image {
        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.0

    Item {
    property int transpX: 0
    property int transpY: 0
    property int transpWidth: 0
    property int transpHeight: 0

    width: 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.0

    Item {
    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 &gt; 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--7IzuY

    Regards,
    Bill


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.