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.
-
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.
@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.
-
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).
-
@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.
-
@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.
@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 } }
-
@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.
@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!
-
@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."
-
@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."
Hmmm you got me playing around with this a bit myself... my code produces this:
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.