QML: DropShadow duplicates the source rectangle - qt

I'm trying to make my horizontal rectangle to drop a shadow. When I do it with the code below, the rectangle duplicates, so that there are two horizontal rectangles in two rows. It's shown in the image (the duplicated one is white). How can I get rid of the duplicated rectangle so that just the shadow and the original rectangle remain?
Window {
visible: true
width: 640
height: 480
color: "white"
Item {
anchors.fill: parent
ColumnLayout {
id: layout
anchors.fill: parent
spacing: 0
Rectangle {
id: bar
color: "blue"
height: 40
Layout.fillWidth: true
}
DropShadow {
anchors.fill: bar
horizontalOffset: 0
verticalOffset: 3
radius: 8.0
samples: 12
source: bar
color: "blue"
}
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: parent.width
color: "grey"
}
}
}
}

There is no duplicate rectangle, there is just a gap. You are using a layout, which will lay its containing items out based on their size. You do anchor the shadow to fill the rectangle, so that's where it is, but the layout is not supposed to be used in such a format, therefore it leaves an empty space where the shadow is supposed to go before placing the grey rectangle.
And the shadow doesn't show if you get rid of the gap because the grey rectangle is on top of it. Tinkering with the z value doesn't seem to help either. It might have to do with using a layout.
You can get the desired result if you get rid of the layout and use anchoring, which allows you to put the grey rectangle first, so it can be under the shadow.
Item {
anchors.fill: parent
Rectangle {
anchors.bottom: parent.bottom
anchors.top: bar.bottom
width: parent.width
color: "grey"
}
Column { // or you can put the layout here if you want
id: bar
anchors.top: parent.top
width: parent.width
Rectangle {
color: "blue"
height: 40
width: parent.width
}
// other stuff
}
DropShadow {
anchors.fill: bar
horizontalOffset: 0
verticalOffset: 3
radius: 8.0
samples: 12
source: bar
color: "blue"
}
}

Create DropShadow as Rectangle child:
Item {
ColumnLayout {
id: layout
anchors.fill: parent
spacing: 0
Rectangle {
id: bar
color: "blue"
height: 40
Layout.fillWidth: true
...
... // some buttons, images etc.
DropShadow {
anchors.fill: parent
horizontalOffset: 0
verticalOffset: 3
radius: 8.0
samples: 12
source: bar
color: "blue"
}
}
...
... // some other components to the layout ...
}
}
Also you can assign DropShadow object to layer.effect Property:
Item {
ColumnLayout {
id: layout
anchors.fill: parent
spacing: 0
Rectangle {
id: bar
color: "blue"
height: 40
Layout.fillWidth: true
...
... // some buttons, images etc.
layer.enabled: true // Set Layer for Enable
layer.effect: DropShadow {
horizontalOffset: 0
verticalOffset: 3
radius: 8.0
samples: 12
source: bar
color: "blue"
}
}
...
... // some other components to the layout ...
}
}

Related

Qml rounded corner of one side with border

Is there a way to have a Rectangle with one side rounded edges and also a border in Qt without using the Canvas.
Something like below.
I did try below code and I am able to create the rounded corner on one side.
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
width: 200
height: 200
visible: true
Item {
width: 100
height: 50
opacity: 0.5
layer.enabled: true
anchors.centerIn: parent
Rectangle {
color: "blue"
radius: 10
anchors.fill: parent
}
Rectangle {
color: "blue"
anchors.fill: parent
anchors.leftMargin: 10
}
}
}
With above code I am able to get the one side rounded corners but when I add border then I see overlapping borders.
Is there a clean way of doing this in Qml?
I can think of two ways to do that.
Not the "cleanest" way, but probably the simplest performance-wise. You can keep using the code you have above, but just draw another non-bordered rectangle that covers up the extra border line that you are seeing.
property int borderWidth: 4
Item {
width: 100
height: 50
opacity: 0.5
layer.enabled: true
anchors.centerIn: parent
Rectangle {
id: roundCorners
color: "blue"
radius: 10
border.width: borderWidth
anchors.fill: parent
}
Rectangle {
id: squareCorners
color: "blue"
border.width: borderWidth
anchors.fill: parent
anchors.leftMargin: 10
}
Rectangle {
anchors.left: squareCorners.left
anchors.verticalCenter: squareCorners.verticalCenter
width: borderWidth
height: squareCorners.height - borderWidth * 2
color: "blue"
}
}
You can use QML's Shape object and use a ShapePath to define it. The docs can be found here.
Shape {
ShapePath {
strokeWidth: 4
strokeColor: "black"
fillColor: "blue"
PathLine { ... }
PathLine { ... }
PathLine { ... }
PathArc { ... }
}
}

Putting an element between a child and parent (z values) QML

I was working with a GridView in QML. When I click on an element, I want to following highlight to happen:
However, my problem is that I want the blue color to appear below the delegate (not in the white area but still visible on the transparent side part) while the checkmark appears above (so it is visible). I have tried playing around with the z values so that the lowest z should be the blue rectangle, the middle should be the white rectangle part of the delegate, and the highest should be the check mark but i can't seem to make it work. Either the highlight or the delegate has to be on top. Does anyone know any way I can fix this so that it works correctly?
Code for highlight:
highlight:
Rectangle {
z:5
color: "steelblue"; radius: 5; opacity: 0.5
Image{
z:8
id: checkMark
visible: found;
x: parent.width-8-width
y: 8
width: 40;
height: 40;
source: "file:///Users/arjun/Documents/CompetitiveBall/images/checkMark.png"
}
}
Code for delegate:
Component {
id: contactsDelegate
Rectangle{
width: grid.cellWidth
height: grid.cellHeight
color: "transparent"
Rectangle {
z:7
width: grid.cellWidth-20
height: grid.cellHeight-20
id: wrapper
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
border.width: 3
border.color: "black"
radius: 5;
Image{
id: mImage
x:parent.x
width: 65
height:65;
source: picSource
}
Text{
width: grid.cellWidth-15
y: mImage.y+mImage.height+4
anchors.horizontalCenter: parent.horizontalCenter
id: nameText
text: name
font.family: "Palatino Linotype"
font.bold: (grid.isCurrentItem===true)?"true":"false"
horizontalAlignment: Text.AlignHCenter
color:"#050027"
}
MouseArea{
anchors.fill: parent
onClicked:{
console.log("Clicked on :" + name)
//what happens when u click
grid.currentIndex=index;
}
}
}
}
}
Since you want part of the highlight to be underneath the delegate and part of it to be on top, you need to break it up into different pieces. I tested the code below with Qt 5.15.0. I made the normal highlight object draw underneath the delegate. Then I added another Rectangle that follows the highlight that draws on top of the delegate.
GridView
{
id: lv
anchors.fill: parent
anchors.margins: 50
cellWidth: 50
cellHeight: 50
model: 30
// By default, highlight draws behind delegates
// (You can specify a positive z-value to make it draw on top)
highlight: Item
{
Rectangle
{
anchors.centerIn: parent
width: 50
height: 50
color: "green"
}
}
delegate: Rectangle
{
width: 30
height: 30
color: "red"
MouseArea
{
anchors.fill: parent
onClicked: lv.currentIndex = index;
}
}
// This will draw on top of the delegates
// (You can change that by specifying a negative z-value.)
Rectangle
{
id: checkbox
x: lv.highlightItem.x - lv.contentX
y: lv.highlightItem.y - lv.contentY
width: 10
height: 10
color: "blue"
}
}

Qt QML anchor not working in custom Item

I'm new of qml.
I'm starting to develop a little application with a custom item.
when I try to use in application anchor.top: first_item.bottom, to position the rectangles of the custom component, one below the other doesn't work.
content file main.qml:
import QtQuick 2.5
Item
{
id:main_screen
Rectangle
{
width: 300
height: 60
id: text_content
color: "DarkGray"
opacity: 0.9
border.color: "blue"
border.width: 3
radius: 5
z:6
Text {
id: titleText
width: parent.width
height: parent.height
font.pointSize: 20
font.family: "Arial"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "Test - title"
color: "White"; style: Text.Raised;
}
}
//..................This rectangle is shown below main_screen... so is OK
Custom_item
{
id:first_item
anchors.top: main_screen.bottom
}
//..................This rectangle is not shown below first_item... but it shown on absolute top, in overlap of retangle title
Custom_item
{
id:second_item
anchors.top: first_item.bottom
}
//..................This rectangle is not shown below second_item... but it shown on absolute top, in overlap of retangle title
Custom_item
{
id:third_item
anchors.top: second_item.bottom
}
}
content file Custom_item.qml
import QtQuick 2.5
Item
{
id:testComponent
Rectangle
{
width: 300
height: 60
id: text_content
color: "DarkGray"
opacity: 0.9
border.color: "blue"
border.width: 3
radius: 5
z:6
}
}
what am I doing wrong ?
Thanks
The problem lies within the dimensions of the objects your are anchoring to.
Though the Rectangles have a width and a height, the enclosing Item has none, so it is basically 0 pixels in height and width, while the Rectangle protrudes it.
If you don't have any reason for enclosing the Rectangle within the Item, I'd reccomend you, to take the Rectangle itself as the toplevel element of the file.
Reasons for having the Item might be those:
Hiding the Rectangles properties
Having multiple children for the Item that are logically siblings to the Rectangle
... other reasons might exist ;-)
Nevertheless, you need to make sure, that the toplevel item has always the right dimensions. So you should set the width and height, better the implicitWidth and implicitHeight in component declarations.
Example 1: Without an Item
import QtQuick 2.5
Rectangle {
id: root
width: 300
height: 60
color: "DarkGray"
opacity: 0.9
border.color: "blue"
border.width: 3
radius: 5
z:6
}
Example 2: With Item
import QtQuick 2.5
Item {
id:testComponent
implicitHeight: 60 // < This
implicitWidth: 300 // < and that are important to have the dimensions
Rectangle {
id: text_content
anchors.fill: parent
color: "DarkGray"
opacity: 0.9
border.color: "blue"
border.width: 3
radius: 5
z:6
}
}
You are anchoring all the Rectangle's to the Item hence you are not getting the desired result. Simple change the id of the top Rectangle as follows
Item
{
id: root
Rectangle
{
id:main_screen
...
}
}

DropShadow for translucent items

I have a problem to create a shadow in an item. The item is not completely opaque and the drawn shadow appears behind the item reducing the transparency effect.
I need something as the picture to the right, but what I got with my attempts is shown to the left. I need you to look through the object, because the background is not solid.
I tried to use maskEf but the object becomes completely opaque. The closest solution I've managed to define is to use another element of the same shape but fully transparent and with solid edge. However I don't like the solid edge, any suggestions?
First attempt. This makes opacity equal to 1 in rec1:
Rectangle {
id: rec1; color: "white"; opacity: 0.5
anchors.fill: parent; radius: CalcSize.getW(8)
layer.enabled: true
layer.effect: DropShadow {
id: shadowEf
anchors.fill: rec1
source: rec1
horizontalOffset: 3
verticalOffset: 3
radius: 15
samples: 16
color: "red"
transparentBorder: true
}
}
Second attempt. This maintains opacity of rec1 but show the border of sourceMaskEf
DropShadow {
id: shadowEf
anchors.fill: sourceMaskEf
source: sourceMaskEf
horizontalOffset: 3
verticalOffset: 3
radius: 15
samples: 16
color: "red"
transparentBorder: true
}
Rectangle {
id: sourceMaskEf; color: "transparent"
anchors.fill: rec1; radius: rec1.radius
border { width: offset; color: "white"; }
}
OpacityMask {
id: maskEf
opacity: 1
anchors.fill: rec1
source: ShaderEffectSource {
sourceItem: shadowEf
hideSource: false
}
maskSource: ShaderEffectSource {
sourceItem: sourceMaskEf
hideSource: false // if set true the shadow is hide to
}
cached: true
}
Rectangle {
id: rec1; color: "white"; opacity: 0.5
anchors.fill: parent; radius: CalcSize.getW(8)
}
Edit
Well, after the suggestion of BaCaRoZzo, this is my solution. It is much closer to what I'm looking for:
Component {
id: fondoItemPromo
Item {
id: item1; opacity: 0.5
layer.enabled: true; anchors.fill: parent
anchors.margins: CalcSize.getW(5) //Just for test
Rectangle {
id: rec1; color: "white"
anchors.fill: parent; radius: CalcSize.getW(8)
Item {
id: item2; opacity: 0.5; layer.enabled: true
anchors.fill: parent; clip: true
Rectangle {
id: rec2; color: "white"
anchors.fill: parent; radius: CalcSize.getW(8)
layer.enabled: true
}
DropShadow {
anchors.fill: rec2
source: rec2
transparentBorder: true
horizontalOffset: 3
verticalOffset: 3
radius: 15
samples: 16
color: "black"; clip: true
}
}
}
}
}
However, the shadow does not extend beyond the limits of the element, as can be seen in the corners:
Any suggestions?
Assuming also the shadow should be semi-transparent - the overall effect would be pretty ugly otherwise - you can solve the issue with the following approach:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
import QtQuick.Controls.Styles 1.3
ApplicationWindow {
width: 200
height: 300
visible: true
color: "steelblue"
Item {
id: layered
opacity: 0.2
layer.enabled: true
anchors.fill: parent
Rectangle {
id: rec1
width: 100
height: 100
anchors.centerIn: parent
radius: 8
}
DropShadow {
id: drop
anchors.fill: rec1
source: rec1
horizontalOffset: 5
verticalOffset: 5
radius: 15
samples: 16
color: "red"
transparentBorder: true
}
}
}
Here is the resulting Rectangle barely visible w.r.t. the background color and with the correct shadow applied:
Edit
The effect can be combined at various level as done in this example.
Given your edit, I think you have overcomplicated a bit the stuff here. The example I've given above served as a way to show that opacity should work as expected. Given the error you have shown I decided to provide a general solution which you should (hopefully) apply out of the box.
The white Rectangle acts as a container for the actual content. Hence, it should be defined in a different QML file. This way we can provide a default property, i.e. define where children Items should be positioned when added to the component. By adding aliases we are also able to fine tune the component, changing colors, shadow orientation and other graphical aspects. A possible definition of your component is the following:
// ShadowedComponent.qml
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
opacity: 0.5
layer.enabled: true
clip: true
property alias color: rec.color
property alias dropColor: drop.color
property alias voff: drop.verticalOffset
property alias hoff: drop.horizontalOffset
property alias radius: rec.radius
property alias dropRadius: drop.radius
property alias samples: drop.samples
default property alias childrenz: rec.children //(1)
property int margins: 20 //(2)
Rectangle {
id: rec
width: 100
height: 100
anchors.fill: parent
anchors.margins: margins
radius: 8
clip: true
}
DropShadow {
id: drop
anchors.fill: rec
source: rec
horizontalOffset: 5
verticalOffset: 5
radius: 15
samples: 16
color: "darkgray"
transparentBorder: true
}
}
The declaration in (1) is crucial as hinted in the previous text: with that we specify that any child of ShadowedComponent is automagically child of the inner Rectangle positioning it inside the component (with the desired alignement - see below). Also crucial is the property margins in (2): it gives the necessary gap for the shadow to correctly appear. A value equal to zero result in the error you get as the shadow cannot exceed boundaries of an item.
The component can be used like this:
ShadowedComponent {
color: "red"
dropColor: "black"
voff: 3
hoff: 3
radius: 8
dropRadius: 8
samples: 16
// inner content...
}
or, since all the properties have a default value, like this:
ShadowedComponent {
// inner content...
}
Finally a possible usage example can be the following:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
ApplicationWindow {
width: 300
height: 600
visible: true
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "cyan" }
GradientStop { position: 0.5; color: "#0099FF" }
GradientStop { position: 1.0; color: "#6699FF" }
}
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
ShadowedComponent {
Layout.fillHeight: true
Layout.fillWidth: true
voff: -5
hoff: -10
Image {
source: "http://avatarmaker.net/free-avatars/avatars/animals_216/cats_237/kitty_close_up_avatar_100x100_36619.jpg"
anchors.fill: parent
anchors.margins: 3
}
}
ShadowedComponent {
Layout.fillHeight: true
Layout.fillWidth: true
dropColor: "red"
opacity: 0.7
Text {
anchors.centerIn: parent
text: qsTr("QML ROCKS!!!")
}
}
ShadowedComponent {
Layout.fillHeight: true
Layout.fillWidth: true
voff: -5
hoff: -10
dropColor: "red"
BusyIndicator {
anchors.centerIn: parent
running: true
}
}
ShadowedComponent {
Layout.fillHeight: true
Layout.fillWidth: true
opacity: 0.6
Test {
anchors.fill: parent
opacity: 1
margins: 10
Text {
anchors.centerIn: parent
text: qsTr("QML ROCKS!!!")
}
}
}
}
}
}
Using a component defined in a different file you are able to compose it, declaratively, with any other (custom) component thanks to the default property. The overall result of our example is the following. Note how each component is unique in its overall appearence thanks to the numerous aliases we defined, and used. Note also that the component can be composed with itself (by also carefully tuning the margin w.r.t. the given shadow parameters):

Wrapping ListView inside rectangle

My problem is when i scroll ListView elements , the elements scroll over the rectangle border however i have wrapped the ListView inside the Rectangle.How can i make elements scroll without effecting the Rectangle borders.
Here are the result links
https://drive.google.com/file/d/0Bx616yTb6y_xQzNxRy1UcktrVzA/view?usp=sharing
https://drive.google.com/file/d/0Bx616yTb6y_xdl9CbWt4MTJ3Smc/view?usp=sharing
Following is the code
ListModel{
id: mod
}
Rectangle{
id:listviewrec
x: 347
y:644
width: 700
height: 91
radius: 4
border.color:"#7CC7FF"
border.width: 4
visible: true
ListView{
id:modlistview
width: listviewrec.width
height: listviewrec.height
clip: true
boundsBehavior: Flickable.DragOverBounds
spacing:25
model:mod
delegate: delegateimage
orientation: Qt.Horizontal
anchors.fill: listviewrec
}
}
Component{
id:delegateimage
Item{
id:imageitem
width:50
height:60
visible:true
Rectangle{
id:imagerec
x:10
y:6
width: 60
height:70
border.color: "#7CC7FF"
border.width: 5
radius: 2
visible:true
Image{
x: 3
y: 3
height : imagerec.height
visible: true
width : imagerec.width
anchors.fill: imagerec
source:fileUrl
}
}
}
}
I don't think qml has the concept of inner- and outer- rects as far as borders are concerned, (or if it does, borders are drawn in the inner-rect so children will be drawn on top).
Your best bet here is to probably do something like this:
Item {
id:listviewrec
x: 347
y:644
width: 700
height: 91
visible: true
ListView{
id:modlistview
width: listviewrec.width
height: listviewrec.height
clip: true
boundsBehavior: Flickable.DragOverBounds
spacing:25
model:mod
delegate: delegateimage
orientation: Qt.Horizontal
anchors.fill: listviewrec
}
Rectangle {
radius: 4
border.color:"#7CC7FF"
border.width: 4
color: 'transparent'
anchors.fill: parent
}
}
It simply draws a transparent rect with the border you want on top of the ListView
At the moment I am unable to run your code, but it seems a matter of removing explicit width and height settings, since you are using anchors.fill

Resources