Important: Please read the Qt Code of Conduct -

Recursion trick in ShaderEffectSource fails when I destroy the source object in onStateChanged

  • I want a ShaderEffectSource called snapshotter that updates on every change of a source item, but when the source item is destroyed, I want snapshotter to retain the last state of the source item.

    In my code I use a workaround for a Qt deficiency - setting snapshotter.sourceItem = snapshotter when the previous source item gets destroyed. This works fine when I destroy the old source item e.g. on key press. But when I do it in an onStateChanged handler, I get this error:

    ShaderEffectSource: 'recursive' must be set to true when rendering recursively.

    But I don't want to set recursive: true, because then snapshotter would start repainting as fast as possible, wasting a lot of processing power.

    Any idea why that problem happens considering it works fine when using key press, and/or a workaround?

    I realize I'm asking why a hacky solution fails in some cases, but since it works in some cases, I'd like to use the solution anyway as it's very useful.

    My code: (main.qml)

    import QtQuick 2.6
    import QtQuick.Window 2.2
    Window {
        visible: true
        width: 640
        height: 480
        Loader {
            active: true
            id: loader
                Rectangle {
                    color: "red"
                    border.color: "white"
                    width: 100
                    height: 100
                    parent: row
                    states: [
                        State {
                            // the condition is always true, in this example code
                            name: "theOnlyState"; when: width === 100
                    onStateChanged: {
                        if(state === "theOnlyState") {
                   = false;
        Row {
            id: row
            ShaderEffectSource {
                id: snapshotItem
                sourceItem: {
                    if(loader.status === Loader.Ready) {
                        return loader.item;
                    } else {
                        return snapshotItem;
                live: loader.status === Loader.Ready
                width: 100
                height: 100

    Note: I just had an idea: maybe setting recursive: true will not create the problem I mentioned, considering I'd only set it when live == false. Maybe Qt is smart enough not constantly redraw in that case. But I'm not sure how to check if that's true.

  • Found a solution and posted it at StackOverflow.

  • Thank you for sharing your solution :-)

Log in to reply