I am trying to create a semi transparent blur rectangle which is overlay on another rectangle in Qt Quick Qml.
Rectangle {
id: mainRect
anchors.fill: parent
color: "transparent"
// This is my background rect
Rectangle {
id: backgroundRect
anchors.fill: parent
color: "blue"
}
// This is my semi-transparent-blur overlay rect
Rectangle {
id: blurRect
anchors.fill: parent
color: "#000000"
opacity: 0.5
}
// I did try these but I see black rectangle
ShaderEffectSource {
id: effectSource
sourceItem: blurRect
anchors.fill: blurRect
}
FastBlur{
id: blur
anchors.fill: effectSource
source: effectSource
radius: 32
}
}
I see an black rectangle when I run this.
How should I create a semi transparent blur overlay Rectangle/Item.
Here is how I have done it in the past without layers or manually using ShaderEffectSource objects:
Image {
id: backgroundImage
source: "some_image.png"
}
Item {
id: blurRect
anchors.fill: parent
FastBlur {
anchors.fill: parent
source: backgroundImage
radius: 64
}
Rectangle {
anchors.fill: parent
color: "red"
opacity: 0.5
}
}
Look at this code:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtGraphicalEffects 1.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Rectangle {
id: backgroundRect
anchors.fill: parent
color: "blue"
}
Rectangle
{
id:blureRect
anchors.fill: parent
layer.smooth: true
layer.enabled: true
opacity: 0.5
layer.effect: ShaderEffect {
id: effectSource
anchors.fill: parent
FastBlur{
id: blur
anchors.fill: effectSource
source: effectSource
radius: 32
}
}
}
}
output:
before blur rect :
after blur rect :
If I use an image in the background you can see blur rect better :
Image {
id: img
anchors.fill: parent
source: "/images/monkey_off_128x128.png"
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
}
Rectangle
{
id:blureRect
anchors.fill: parent
layer.smooth: true
layer.enabled: true
opacity: 0.5
layer.effect: ShaderEffect {
id: effectSource
anchors.fill: parent
FastBlur{
id: blur
anchors.fill: effectSource
source: effectSource
radius: 32
}
}
}
Related
I am trying to create a semi transparent blur rectangle which is overlay on another rectangle in Qt Quick Qml.
Rectangle {
id: mainRect
anchors.fill: parent
color: "transparent"
// This is my background rect
Rectangle {
id: backgroundRect
anchors.fill: parent
color: "blue"
}
// This is my semi-transparent-blur overlay rect
Rectangle {
id: blurRect
anchors.fill: parent
color: "#000000"
opacity: 0.5
}
// I did try these but I see black rectangle
ShaderEffectSource {
id: effectSource
sourceItem: blurRect
anchors.fill: blurRect
}
FastBlur{
id: blur
anchors.fill: effectSource
source: effectSource
radius: 32
}
}
I see an black rectangle when I run this.
How should I create a semi transparent blur overlay Rectangle/Item.
Here is how I have done it in the past without layers or manually using ShaderEffectSource objects:
Image {
id: backgroundImage
source: "some_image.png"
}
Item {
id: blurRect
anchors.fill: parent
FastBlur {
anchors.fill: parent
source: backgroundImage
radius: 64
}
Rectangle {
anchors.fill: parent
color: "red"
opacity: 0.5
}
}
Look at this code:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtGraphicalEffects 1.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Rectangle {
id: backgroundRect
anchors.fill: parent
color: "blue"
}
Rectangle
{
id:blureRect
anchors.fill: parent
layer.smooth: true
layer.enabled: true
opacity: 0.5
layer.effect: ShaderEffect {
id: effectSource
anchors.fill: parent
FastBlur{
id: blur
anchors.fill: effectSource
source: effectSource
radius: 32
}
}
}
}
output:
before blur rect :
after blur rect :
If I use an image in the background you can see blur rect better :
Image {
id: img
anchors.fill: parent
source: "/images/monkey_off_128x128.png"
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
}
Rectangle
{
id:blureRect
anchors.fill: parent
layer.smooth: true
layer.enabled: true
opacity: 0.5
layer.effect: ShaderEffect {
id: effectSource
anchors.fill: parent
FastBlur{
id: blur
anchors.fill: effectSource
source: effectSource
radius: 32
}
}
}
I have a RowLayout with some items
RowLayout {
anchors.fill: parent
anchors.leftMargin: 3
Image {
id: icon
source: imgSource
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
}
Text {
id: caption
height: parent.height
fontSizeMode: Text.Fit
font.pointSize: textSize
verticalAlignment: Text.AlignVCenter
text: captionText
color: "white"
}
}
and I want to apply ColorOverlay on Image inside this layout:
ColorOverlay {
id: overlay
anchors.fill: icon
source: icon
color: "#ff0000ff"
}
But if I put ColorOverlay outside of the layout, then I can't use anchors.fill: icon. And if I make it a child
Image {
id: icon
source: imgSource
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
ColorOverlay {
id: overlay
anchors.fill: icon
source: icon
color: "#ff0000ff"
}
}
it seems to work but I get warnings in console ShaderEffectSource: 'recursive' must be set to true when rendering recursively.
To set an effect on an Item you can use Item layers, in your case it would be :
Image {
source: imgSource
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
layer {
enabled: true
effect: ColorOverlay {
color: "#ff0000ff"
}
}
}
Note that you don't have to set the source or the size of the effect, it is done automatically.
You could "pack" the image with its overlay in some custom item, for example:
MyImage.qml
import QtQuick 2.11
import QtGraphicalEffects 1.0
Item {
Image {
id: icon
source: "http://placeimg.com/200/200/any"
visible: false
}
ColorOverlay {
anchors.fill: icon
source: icon
color: "#8000ff00"
}
}
and so use it instead of image:
import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick.Layouts 1.11
Window {
visible: true
width: 640
height: 480
RowLayout {
width: parent.width
anchors.leftMargin: 3
MyImage {
Layout.preferredWidth: parent.width / 2
}
Text {
id: caption
fontSizeMode: Text.Fit
font.pointSize: 14
text: "Some caption here"
Layout.preferredWidth: parent.width / 2
}
}
}
Is there a way to call a signal from a mouseArea included in a component which is loaded somewhere else?
onClicked in the example below is not entered when i click on the rectangle.
The structure needs to remain as defined. To be able to define a qml component that applies a shadow to any source
Here is the code:
Window{
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item
{
id: mainRectangle
anchors.centerIn: parent
width: loaderId.width + 60
height: loaderId.height + 60
Rectangle {
id: rect2
anchors.right: mainRectangle.right
anchors.top: mainRectangle.top
anchors.rightMargin: -30
anchors.topMargin: -30
width: 100
height: 100
color: "red"
opacity: 0.5
}
Loader {
id: loaderId
anchors.centerIn: parent
sourceComponent: component
active:true
}
visible: false
}
ShaderEffectSource {
id: shader
anchors.fill: mainRectangle
anchors.margins: -30
sourceItem: mainRectangle
opacity: 0.5
visible: true
}
Component {
id: component
Rectangle {
id: rect
width: 100
height: 100
color: "black"
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Clicked!")
// call a signal from here
}
}
}
}
}
In the end the should show what it does now and the mouseArea should work.
onClicked in the example below is not entered when i click on the rectangle.
mainRectangle is not visible, and items that aren't visible don't get input events. Since the MouseArea is a child of mainRectangle, it won't get events either.
In the end the should show what it does now and the mouseArea should work.
Instead of hiding the source item and using ShaderEffectSource, you can set the opacity directly on mainRectangle and use item layers (the link has a similar example) to ensure that there is no overlap due to transparency:
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item {
id: mainRectangle
anchors.centerIn: parent
width: loaderId.width + 60
height: loaderId.height + 60
opacity: 0.5
layer.enabled: true
Rectangle {
id: rect2
anchors.right: mainRectangle.right
anchors.top: mainRectangle.top
anchors.rightMargin: -30
anchors.topMargin: -30
width: 100
height: 100
color: "red"
}
Loader {
id: loaderId
anchors.centerIn: parent
sourceComponent: component
active: true
}
}
Component {
id: component
Rectangle {
id: rect
width: 100
height: 100
color: "black"
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Clicked!")
// call a signal from here
}
}
}
}
}
I am working on application using Qt 5.4.1 and its Qt Quick module. I load some .svg pictures from /images directory and then show them in ListView, which works ok. But, how do I add shadow gradient around every loaded .svg image? Here is MWE:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import Qt.labs.folderlistmodel 2.1
Rectangle
{
id: ueMainWindow
visible: true
width: 800
height: 1280
color: "black"
property string ueRootDirectory:"/images"
property real ueImagesLoadProgress;
property bool ueImageLoading;
Rectangle
{
id: ueContainerThumbnails
antialiasing: true
color: "black"
anchors.bottom: ueMainWindow.bottom
width: ueMainWindow.width
height: 256
gradient: Gradient
{
GradientStop { position: 0.0; color: "black" }
GradientStop { position: 1.0; color: "grey" }
}
Text
{
id: ueTextImageName
antialiasing: true
color: "white"
anchors.horizontalCenter: ueContainerThumbnails.horizontalCenter
text: qsTr("TestApp")
}
ListView
{
id: ueViewThumbnails
antialiasing: true
orientation: ListView.Horizontal
anchors
{
topMargin: parent.height-(parent.height-50)
fill: parent
}
FolderListModel
{
id: ueModelImages
folder: "file://"+ueRootDirectory
nameFilters: ["*.svg"]
}
Component
{
id: ueDelegateImage
Image
{
id: ueImage
source: ueModelImages.folder + "/" + fileName
antialiasing: true
asynchronous: true
horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter
width: 192
height: 192
fillMode: Image.PreserveAspectFit
}
}
focus: true
spacing: 10
leftMargin: 10
rightMargin: 35
visible: ueModelImages.status==FolderListModel.Ready
model: ueModelImages
delegate: ueDelegateImage
}
}
}
Well, you should put that gradient into your delegate somehow. You can either:
create an empty Item and put the Rectangle and Image inside it
example:
Component {
id: ueDelegateImage
Item { // container
Rectangle {
// gradient rectangle
}
Image {
// image
}
}
}
or put the Image inside the Rectangle
example:
Component {
id: ueDelegateImage
Rectangle {
// gradient rectangle acts as a container
Image {
// image
}
}
}
In both cases stacking order will draw the gradient rectangle behind the image. A delegate should only have one root element, but is not limited to just one element, you can nest as many as you like.
I wonder how to make smooth transitions betwen image sources in QML, I try
import QtQuick 1.1
Image {
id: rect
source: "quit.png"
smooth: true
MouseArea {
id: mouseArea
anchors.fill: parent
anchors.margins: -10
hoverEnabled: true //this line will enable mouseArea.containsMouse
onClicked: Qt.quit()
}
states: State {
name: "mouse-over"; when: mouseArea.containsMouse
PropertyChanges { target: rect; scale: 0.8; source :"quit2.png" }
}
transitions: Transition {
NumberAnimation { properties: "scale, source"; easing.type: Easing.InOutQuad; duration: 1000 }
}
}
But It does not work on source as a transition just as final state change.. so I wonder how to make one image source fade into andothe and back?
You want the first image to fade out into the other? How about if you place two Image objects on top of each other, then animate the opacity property?
EDIT: This worked for me (I'm using QtQuick 1.0 because my Qt Creator installation is a bit outdated):
import QtQuick 1.0
Rectangle {
Image {
id: rect
source: "quit.png"
smooth: true
opacity: 1
MouseArea {
id: mouseArea
anchors.fill: parent
anchors.margins: -10
hoverEnabled: true //this line will enable mouseArea.containsMouse
onClicked: Qt.quit()
}
states: State {
name: "mouse-over"; when: mouseArea.containsMouse
PropertyChanges { target: rect; scale: 0.8; opacity: 0}
PropertyChanges { target: rect2; scale: 0.8; opacity: 1}
}
transitions: Transition {
NumberAnimation { properties: "scale, opacity"; easing.type: Easing.InOutQuad; duration: 1000 }
}
}
Image {
id: rect2
source: "quit2.png"
smooth: true
opacity: 0
anchors.fill: rect
}
}
To the question in your comment: you can place the image exactly on top of the other by copying the anchors thru anchors.fill: rect
Here is also a simple scroll transition between images:
import QtQuick 2.6
import QtQuick.Controls 1.4
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: imageRect
anchors.centerIn: parent
width: 240
height: 320
clip: true
property int currentIndex: 0
property var imageSources: [ "imageLeft.jpg", "imageCenter.jpg" ]
Repeater {
model: imageRect.imageSources
Image {
id: image
width: parent.width
height: parent.height
x: index * parent.width - imageRect.currentIndex * parent.width
fillMode: Image.PreserveAspectFit
source: imageRect.imageSources[index]
Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } }
}
}
}
Button {
id: leftButton
anchors.bottom: parent.bottom
text: "left"
onClicked: if(imageRect.currentIndex > 0) imageRect.currentIndex--
}
Button {
id: rightButton
anchors.bottom: parent.bottom
anchors.left: leftButton.right
text: "right"
onClicked: if(imageRect.currentIndex < imageRect.imageSources.length - 1) imageRect.currentIndex++
}
Button {
id: addButton
anchors.bottom: parent.bottom
anchors.left: rightButton.right
text: "+"
onClicked: imageRect.imageSources = [ "imageLeft.jpg", "imageCenter.jpg" , "imageRight.jpg" ]
}
}