QML gradient allows only from top to bottom in a Rectangle. The documentation says that
it has to be done through combination of rotation and clipping.
I have just started learning QML (and little experience with HTML/CSS). Here is my code which I think can be improved for a lot better:
import QtQuick 1.0
Rectangle {
width: 400; height: 400;
Rectangle {
width: 567; height: 567;
gradient: Gradient {
GradientStop {
position: 0.0;
color: "white";
}
GradientStop {
position: 1.0;
color: "blue";
}
}
x: 116.5;
transformOrigin: Item.Top;
rotation: 45.0;
}
}
Can you please suggest what are the better ways to do this?
I've solve this probling with the following code: https://code.google.com/p/ytd-meego/source/browse/trunk/playground/FeedBook/qmltube/HorizontalGradient.qml?r=144
Here is what I've done using the example of NielsMayer:
Rectangle {
width: parent.height
height: parent.width
anchors.centerIn: parent
rotation: 90
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
GradientStop { position: 1.0; color: "white" }
}
}
And this is working well. Have fun !
The Qt Graphical Effects module introduced in Qt 5.1 provides three gradient types.
With the LinearGradient item (effect) it is no longer necessary to apply rotation in order to achieve e.g. a horizontal color gradient.
In particular by means of the start and end point (attributes) of LinearGradient any gradient direction is possible.
The following code implements a 45° angle (as proposed in the original post) by starting top right with white and ending bottom left with black:
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
id:myItem
width: 300
height: 300
LinearGradient {
anchors.fill: parent
start: Qt.point(myItem.width, 0)
end: Qt.point(0, myItem.height)
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: 1.0; color: "black" }
}
}
}
I'm afraid the documentation is correct.
The only other way I can think of is to write a custom QML component in C++ which does what you want.
If you have Qt/C++ knowledge you could start here:
http://doc.qt.nokia.com/4.7-snapshot/qml-extending.html
http://doc.qt.nokia.com/4.7-snapshot/declarative-tutorials-extending-chapter1-basics.html
The Rectangle could be a good template or base class:
http://qt.gitorious.org/qt/qt/blobs/4.8/src/declarative/graphicsitems/qdeclarativerectangle_p.h
You can use the orientation property from Qt 5.12
Related
I have implemented a cover flow similar to Itunes. But there is still one thing that I can't solve, even after researching and reading the documentation...
I have the following result, but I would like to display only half of the reflection.
I have found the following StackOverflow post : How do I make a gradient opacity in an image - QML which is very similar to what I would like to achieve. Except that as my background is a gradient, I can't select the white color (or any plain color for the last GradientStop element in the solution code offered as solution).
Here is my code so far:
Image {
id: rectDelegate
anchors.fill: parent
source: images[index % images.length]
}
ShaderEffectSource {
id: reflection
sourceItem: rectDelegate
y: sourceItem.height
width: sourceItem.width
height: sourceItem.height
transform: [
Rotation {
origin.x: reflection.width / 2
origin.y: reflection.height / 2
axis.x: 1
axis.y: 0
axis.z: 0
angle: 180
}
]
visible: reflection_visible
}
Rectangle {
anchors.fill: reflection
gradient: Gradient {
GradientStop {
position: 0.0
color: "#55ffffff"
}
GradientStop {
// This determines the point at which the reflection fades out.
position: 1
color: "#ffffff"
}
}
visible: reflection_visible
}
I tried to embed the ShaderEffectSource element inside a transparent rectangle whose height would be half of the reflection height and to clip the ShaderEffectSource inside, but the reflection wouldn't appear :/
Here is the code :
Rectangle {
anchors.top: rectDelegate.bottom
color: "transparent"
width: rectDelegate.width
height: rectDelegate.height - 300
visible: reflection_visible
clip: true
border.color: "yellow"
ShaderEffectSource {
id: reflection
sourceItem: rectDelegate
y: sourceItem.height
width: sourceItem.width
height: sourceItem.height
transform: [
Rotation {
origin.x: reflection.width / 2
origin.y: reflection.height / 2
axis.x: 1
axis.y: 0
axis.z: 0
angle: 180
}
]
visible: reflection_visible
}
}
Any idea would be welcome :) I tried to make my post as clear as possible but if there is something missing for understanding, please, ask :)
read this post:
How do I make a gradient opacity in an image? - QML
or you can use Canvas type to draw your image with transparent gradient , but the proper way is the first one.
I'm using a PieSeries in QML as a way to create a makeshift mask.
I have a circular animated gif and on top of it, I've added a PieSeries.
The PieSeries has 3 PieSlices. 2 of them are "black" essentially blocking out there corresponding portions of the gif. The remaining PieSlice is transparent.
This works fine, but I would like the 2 black PieSlices to have a gradient to them so that their edge is not so obvious (gradient transparency).
I've tried using a LinearGradient with an OpacityMask as described here, but this did not have any effect when used on a PieSlice.
Any suggestions would be appreciated :)
Here's my code:
import QtQuick 2.0
import QtCharts 2.2
import QtGraphicalEffects 1.0
Item {
anchors.fill: parent //Fill the gif area
ChartView {
id: chart
anchors.centerIn: parent
height: parent.height+200
width: parent.width
legend.visible: false
antialiasing: false
backgroundColor: "transparent"
PieSeries {
id: pieOuter
size: 1.5
holeSize: 0.2
PieSlice { id: black1; value: 1; color: "black"; borderColor: "transparent" }
PieSlice { id: valSlice; value: d.val; color: "transparent"; borderColor: "transparent" }
PieSlice { id: black2; value: 1 - d.val; color: "black"; borderColor: "transparent" }
}
}
OpacityMask{
source: mask
maskSource: black1
}
LinearGradient {
id: mask
anchors.fill: black1
gradient: Gradient {
GradientStop { position: 0.2; color: "transparent"}
GradientStop { position: 0.5; color: "white" }
}
}
}
Note: d.val here holds a value between 0 and 1
Edit
Some images to help visualise what I'm trying to achieve:
The GIF that I'm starting off with (source - original file was too large to attach):
Snapshot of original Gif
This is how it is currently animated to look:
Low d.val
Higher d.val
Max d.val
This is what I want it to actually look like (depicted here for d.val):
Higher d.val with gradient
Today I tried the Slider in QtQuick.Controls, my slider is left to right, I want to set my slider as from right to left by using LayoutMirroring.enabled, at last I found I cann't inverted the slider.
Here is my little demo code, so how can we invert a slider?
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Slider{
id:test
value: 0.2
width:400
LayoutMirroring.enabled: true
}
}
If you use the Slider from QtQuick.Controls 2.x - at least for me - it works like a charm. If you use the Slider from QtQuick.Controls 1.x it does not.
From the documentation:
Keep in mind, however, that mirroring does not affect any positioning that is defined by the Item x coordinate value, so even with mirroring enabled, it will often be necessary to apply some layout fixes to support the desired layout direction.
The QtQuick.Controls 1.x-Slider however uses a largely coordinate based implementation and has no further precautions to support the LayoutMirroring.
However the Sliders layout is usually symetrically, so all you need to do is to map the values like from (0,1) to (1,0). This should be a easy task to a developer.
import QtQuick.Controls 1.3
import QtQuick.Controls.Layouts 1.3
import QtQuick.Controls.Private 1.3 // Needed for a mysterious value from the original, now mirrored style.
Slider {
y: 40
id: sli
width: parent.width
minimumValue: 50
maximumValue: 100
property real mirroredValue: maximumValue - value + minimumValue
// Invert style
style: SliderStyle {
groove: Item {
property color fillColor: "#49d"
anchors.verticalCenter: parent.verticalCenter
// Whatever TextSingleton is. You need to import QtQuick.Controls.Private 1.x for it.
implicitWidth: Math.round(TextSingleton.implicitHeight * 4.5)
implicitHeight: Math.max(6, Math.round(TextSingleton.implicitHeight * 0.3))
Rectangle {
radius: height/2
anchors.fill: parent
border.width: 1
border.color: "#888"
gradient: Gradient {
GradientStop { color: "#bbb" ; position: 0 }
GradientStop { color: "#ccc" ; position: 0.6 }
GradientStop { color: "#ccc" ; position: 1 }
}
}
Item {
clip: true
x: styleData.handlePosition // let the fill-stuff start at the handle position...
width: parent.width - styleData.handlePosition // and end at the end of the groove.
height: parent.height
Rectangle {
anchors.fill: parent
border.color: Qt.darker(fillColor, 1.2)
radius: height/2
gradient: Gradient {
GradientStop {color: Qt.lighter(fillColor, 1.3) ; position: 0}
GradientStop {color: fillColor ; position: 1.4}
}
}
}
}
}
}
If you wan't to set the value of your slider, you need to install a bidirectional binding between mirroredValue and value.
I had a similar problem. My slider was vertical with values increasing from bottom to the top. I wanted them to increase from top to bottom. I accomplished it using rotation. I think that you could have solved your problem like this:
Slider {
id: test
value: 0.2
width: 400
rotation: 180 // This should make the slider right-to-left
}
I would like to have a more specific gradient than the default vertical one for a Rectangle. I try adding a LinearGradient for a diagonal effect, but it overwrites the border.
Consider this example. Top Rectangle ok with vertical gradient and border. Bottom Rectangle gradient overwrites border and radius. I tried clip and gradient: LinearGradient but they didn't work either.
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
ApplicationWindow
{
visible: true
width: 640
height: 480
Column
{
spacing: 20
width: parent.width
Rectangle
{
width: 200
height: 200
border.width: 4
border.color: "#888"
radius: 10
// adds a vertical gradient to button
gradient: Gradient
{
GradientStop
{
position: 0
color: "#eee"
}
GradientStop
{
position: 1
color: "#ccc"
}
}
}
Rectangle
{
width: 200
height: 200
border.width: 4
border.color: "#888"
radius: 10
// try to add diagonal gradient, but overwrites button border
// also can't do, gradient: LinearGradient ?
LinearGradient
{
anchors.fill: parent
start: Qt.point(0,0)
end: Qt.point(parent.width,parent.height)
gradient: Gradient
{
GradientStop
{
position: 0
color: "#eee"
}
GradientStop
{
position: 1
color: "#ccc"
}
}
}
}
}
}
Results in this:
I can see why this might have this result, but how to clip the gradient to a Rectangle with a radius?
clip always clips at the bounding rectangle of the Item that is clipping, and does not care for alpha-values.
However the LinearGradient has another tool, to achive what you want:
- the source-property.
See this example:
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
Window {
width: 1024
height: 800
visible: true
Rectangle {
id: rect1
width: 100
height: 100
radius: 20
}
LinearGradient {
anchors.fill: rect1
source: rect1 <-- Here is where you specify its shape.
start: Qt.point(0, 0)
end: Qt.point(300, 300)
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: 1.0; color: "black" }
}
}
}
QML only supports vertical gradients. You can fake horizontal gradients by flipping the item's width and height and rotating it.
For a diagonal that won't work, as the rectangle would also be rotated.
As for the plan to use clipping, that won't work either, because the QML screnegraph only clips to the item's rectangle, not its actual visible pixels.
There are two approaches you ca take:
1 - try to accomplish the desired result via the Canvas element.
2 - use a ShaderEffect to which you pass a ShaderEffectSource texture with the gradient and a rounded rectangle, then in the actual shader use the rgb from the first source (the gradient) and the alpha from the second (the rounded rectangle) to manually clip.
3 - if you are going to be using ShaderEffect you can easily skip using a gradient as a source, and look up how to implement a gradient at an arbitrary angle in GLSL, and only use the rounded rectangle source for the alpha, even though the "rounded" part can just as well be implemented in the shader.
I need to apply Linear Gradient along x-axis in my project. But it doesn't seem to work. Even with the simplest code, that is from Qt documentation of Linear Gradient right away, it doesn't show the expected output.
Here's my code.
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item {
width: 300
height: 300
LinearGradient {
anchors.fill: parent
end: Qt.point(300, 0)
start: Qt.point(0, 0)
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: 1.0; color: "black" }
}
}
}}
My code produces this output.
Anyone has any idea about what's going on. Please help. Thanks in advance.
It's weird, I'm using 2.5 version and I have the correct output...
Anyway, you still can define your gradient vertically and apply a rotation
end: Qt.point(0, 300)
start: Qt.point(0, 0)
rotation: -90