QML popup with blurred background?



  • I'd like to display a popup and have the background be a blurred version of the window the popup is appearing on top of (i.e. my main window)

    I'm assuming this process will involve using a FastBlur, and that I'll have to grabToImage to get the main screen's image to use as a source, but I'm not sure if I have to create an item to do the screen grab, or if there's some element I can simply ask for an image.

    Are there any examples of something like this using QML? It would seem like a fairly common request, given the sort of translucent UI tricks Android and iOS are introducing.


  • Moderators

    @igor_stravinsky
    10s google search resulted in this



  • I've seen the solution for the blurred background using FastBlur.

    The difference is that that solution uses a png image that already exists as the blurred background. I could do the same thing, but I'd need a screenshot of the current UI to use for the FastBlur, and I haven't seen a QML solution for gathering a snapshot of the current window.



  • @igor_stravinsky The FastBlur example uses an image, but FastBlur is just blurring whatever item its source property is pointing at. If you point it at your "main screen" (assuming that is itself a QML Item too) it'll blur that.

    If your dialog just overlaps part of the main screen, things probably get a bit more complex but you ought to be able to use ShaderEffectSource's sourceRect property to capture just the pixels needed for the blur (and in fact I see looking at raven-worx's SO link that's exactly what that does).

    (Alternative approach: In the past for doing some effects I have resorted to a C++ plugin to capture the whole QQuickView content and serve it up again via QQuickImageProvider to a QML Image for subsequent QML effects processing. That approach is a bit clunky and not as fast as you'd hope on mobile devices with high DPI displays. It's good enough for page transition effects; not so much for "live" effects... for those you really want to keep all the pixels in the OpenGL domain. Since then the purely QML world has got its own grabToImage... but so far as I can tell you can't currently do anything with the result other than save it to a file. Presumably you can close the loop by referring to that image file with some QML Image's source, but I can't imagine it being a viable approach for anything but actual screenshots and galleries of those screenshots: compressing a high DPI to png is not fast, no way it's going to be useful for "live" effects; at least the QQuickImageProvider approach never had to compress anything).



  • @timday Thanks for the suggestions.

    Unfortunately, my popup covers my "main screen", and although that's a QML item, capturing that image in another QML items looks less than trivial.

    What I'd really like to be able to do is to create a translucent rectangle the size of the screen, and have it act like a blurry lens above the main window UI. That would eliminate the need to take a screenshot and then manipulate it's pixels. I haven't seen any indication that that's possible, however.


  • Moderators

    @igor_stravinsky
    why don't you simply try the posted example?! All it would take you is 5 minutes... and you would see that it does what you want...

    import QtQuick 2.3
    import QtQuick.Window 2.2
    import QtGraphicalEffects 1.0
    
    Window {
        id: window
        visible: true
        width: 600
        height:600
    
        Rectangle {
            id: container
            anchors.fill: parent
    
            Image {
                id: image
    
                anchors.fill: parent
                source: "url/to/image.png"
            }
    
            Rectangle {
                width: 50
                height: 50
                x: 50
                y: 50
                color: "red"
            }
        }
        ShaderEffectSource {
            id: effectSource
    
            sourceItem: container
            anchors.fill: container
            sourceRect: Qt.rect(x,y, width, height)
        }
    
        FastBlur{
            id: blur
            anchors.fill: effectSource
    
            source: effectSource
            radius: 100
        }
    }
    


  • @igor_stravinsky said in QML popup with blurred background?:

    Unfortunately, my popup covers my "main screen", and although that's a QML item, capturing that image in another QML items looks less than trivial.
    What I'd really like to be able to do is to create a translucent rectangle the size of the screen, and have it act like a blurry lens above the main window UI. That would eliminate the need to take a screenshot and then manipulate it's pixels. I haven't seen any indication that that's possible, however.

    Er, that's exactly what the example does. It'd be a different story if your "main screen" was the OS' desktop, but if it's a QML item just use ShaderEffectSource and FastBlur. Entirely possible!



  • @timday
    Thanks for the help, Tim!

    I got the background blur working from the main screen.

    I had to implement this by having the main view blur its contents, and then show the popup. I was trying to find a way to have the popup blur its parent, so I could encapsulate the popup behavior. Although I could get the popup to pull it's blur from the parent view, I couldn't get it to apply the blur to the parent. Is there a way to do that from within a separate popup qml file?

    In my case the qml file that spawns the dialog is several layers inside of the item at the top level. Although I can reach up and find the correct parent to name as the sourceItem, I can't anchor to that item. When I try that, I get an error "QML ShaderEffectSource: Cannot anchor to an item that isn't a parent or sibling."



  • @igor_stravinsky

    Hmmm you got me playing around with this a bit myself... my code produces this:

    blurry cat

    Note the dimming of the non-popup area is something built into Popup; see its 'dim' and 'modal' properties.

    Code (runs in qmlscene in Qt 5.9.1):

    import QtQuick 2.3
    import QtQuick.Window 2.2
    import QtQuick.Controls 2.2
    import QtQuick.Layouts 1.3
    import QtGraphicalEffects 1.0
    
    ApplicationWindow {
      id: window
      width: 640
      height: 480
    
      Rectangle {
        id: main
        anchors.fill: parent
        
        Image {
          anchors.fill: parent
          source: 'http://placeimg.com/640/480/animals'
          fillMode: Image.PreserveAspectFit
        }
    
        MouseArea {
          anchors.fill: parent
          onClicked: popup.visible=true
        }
      }
    
      Popup {
        id: popup
        x: 0.5*(main.width-width)
        y: 0.5*(main.height-height)
        width: 320
        height: 240
        modal: true
        padding: 0.0
        background: Item {
          ShaderEffectSource {
            id: effectSource
            sourceItem: main
            anchors.fill: parent
            sourceRect: Qt.rect(popup.x,popup.y,popup.width,popup.height)
          }
          FastBlur{
            id: blur
            anchors.fill: effectSource
            source: effectSource
            radius: 32
          }
        }
    
        contentItem: ColumnLayout {
          anchors.fill: parent
          Label {
            text: '<b>Blurry popup</b>'
            Layout.alignment: Qt.AlignCenter
          }
          Button {
            text: 'OK'
            Layout.alignment: Qt.AlignCenter
            onClicked: popup.visible=false
          }
        }
      }
    }
    
    

    Not sure what you mean about having to blur the whole background; this doesn't.

    The thing about the "Cannot anchor to an item that isn't a parent or sibling."... not uncommon to run into that for non-trivial layouts; sometimes I find you just have to "do the math" and provide some explicit expressions using various x, y, width & height properties of the various items involved.


Log in to reply
 

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