QML/Qt gradient charts - qt

I want to create a charts in QML/Qt (solutions for both "platforms" will suffice). Here is an example of what I want:
I draw charts like this:
ChartView {
title: "Температура"
antialiasing: true
legend.visible: false
height: parent.height
anchors.right: parent.right
anchors.left: parent.left
SplineSeries {
color: "#5fafff"
XYPoint { x: 0; y: 0 }
XYPoint { x: 0.5; y: 1.1 }
XYPoint { x: 1.0; y: 2.9 }
XYPoint { x: 1.5; y: 2.1 }
XYPoint { x: 2.0; y: 4.9 }
XYPoint { x: 2.5; y: 3.4 }
XYPoint { x: 3.0; y: 4.1 }
}
}
But how to add a gradient here?

if you want just gradient in your series, not like area gradient you can use Glow and Linear Gradient together which you will anchor with your glow. Also you can use that link for create your visual gradient easly. https://cssgradient.io/
so here is the simple example of usage:
Glow {
id:glow
anchors.fill: yourchartid
radius: 18
samples: 168
color: "purple"
source: yourchartid
}
LinearGradient {
id:gradient
// 200 is length of gamut
start:Qt.point(200,0)
end:Qt.point(0,0)
gradient: Gradient {
GradientStop {
position: 1;
color: "#312c36";
}
GradientStop {
position: 0.5;
color: "#5f4a69";
}
GradientStop {
position: 0.2;
color: "#a600ff";
}
}
anchors.fill = glow
source = glow
}

Related

How to use the LinearGradient in a ShapePath?

I'd like to draw a gradient inside a custom shape. I have used the property fillColor previously and try to use the property fillGradient now. The shape is fine I would say - at least it looks like expected :) What isn't fine in any way is this gradient thing. It just doesn't look anything like expected.
Here is what I want to do. This should run as it is in Qt Design Studio.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Shapes 1.15
Rectangle {
id: btn
color: "white"
readonly property alias fieldHeight: p.fieldHeight
Shape {
ShapePath {
id: p
property int r: 172
property int fieldWidth: 123
property int fieldHeight: 79
property int deltaX: 30
startX: 0
startY: 0
strokeColor: "black"
strokeStyle: ShapePath.SolidLine
fillGradient: LinearGradient {
GradientStop {
position: 0
color: "#6c6c6c"
}
GradientStop {
position: 1
color: "#000000"
}
}
PathArc {
id: upperBorder
x: p.fieldWidth
y: 0
radiusX: p.r
radiusY: p.r
}
PathLine {
x: p.fieldWidth - p.deltaX
y: p.fieldHeight
}
PathArc {
x: p.deltaX
y: p.fieldHeight
radiusX: p.r
radiusY: p.r
direction: PathArc.Counterclockwise
}
PathLine {
x: 0
y: 0
}
}
}
}
The problem is you're not specifying the start and end point of the line that the gradient should follow. Qt annoyingly has 2 different objects called LinearGradient and they have different property names. One is from QtGraphicalEffects, and the other is from QtQuick.Shapes. You're using the shapes version, so your gradient should look something like this:
fillGradient: LinearGradient {
x1: 0
y1: 0
x2: p.fieldWidth
y2: p.fieldHeight
GradientStop {
position: 0
color: "#6c6c6c"
}
GradientStop {
position: 1
color: "#000000"
}
}

Animated progress bar in QML

I need to create a Progress bar as below using QML Controls 2 :
ProgressBar{
id:progressBar
width : parent.width * 0.80
height:parent.height * 0.05
anchors.bottom:parent.bottom
anchors.bottomMargin: (parent.height * 0.03)
anchors.left:parent.left
anchors.leftMargin: (parent.width * 0.05)
value : 0.5
background: Rectangle {
color: "#e6e6e6"
radius: 3
}
contentItem: Item {
Rectangle {
width: progressBar.visualPosition * parent.width
height: parent.height
radius: 2
color: "#17a81a"
gradient: Gradient {
GradientStop {
position: 0.0
SequentialAnimation on color {
loops: Animation.Infinite
ColorAnimation { from: "#14148c"; to: "#0E1533"; duration: 5000 }
ColorAnimation { from: "#0E1533"; to: "#14148c"; duration: 5000 }
}
}
GradientStop {
position: 1.0
SequentialAnimation on color {
loops: Animation.Infinite
ColorAnimation { from: "#14aaff"; to: "#437284"; duration: 5000 }
ColorAnimation { from: "#437284"; to: "#14aaff"; duration: 5000 }
}
}
}
}
}
}
I have never used animations in QML and I tried with sequential animation as above which animates top to bottom. But i need it to animate left to right.
Can anyone help me to achieve this?
As for me I guess its bad idea to overwrite system behavior of controls.
Anyway, you can play with animated gradient. For example:
ProgressBar {
id: control
anchors.centerIn: parent
value: 0
height: 20
clip: true
background: Rectangle {
implicitWidth: 200
implicitHeight: 6
border.color: "#999999"
radius: 5
}
contentItem: Item {
implicitWidth: 200
implicitHeight: 4
Rectangle {
id: bar
width: control.visualPosition * parent.width
height: parent.height
radius: 5
}
LinearGradient {
anchors.fill: bar
start: Qt.point(0, 0)
end: Qt.point(bar.width, 0)
source: bar
gradient: Gradient {
GradientStop { position: 0.0; color: "#17a81a" }
GradientStop { id: grad; position: 0.5; color: Qt.lighter("#17a81a", 2) }
GradientStop { position: 1.0; color: "#17a81a" }
}
PropertyAnimation {
target: grad
property: "position"
from: 0.1
to: 0.9
duration: 1000
running: true
loops: Animation.Infinite
}
}
LinearGradient {
anchors.fill: bar
start: Qt.point(0, 0)
end: Qt.point(0, bar.height)
source: bar
gradient: Gradient {
GradientStop { position: 0.0; color: Qt.rgba(0,0,0,0) }
GradientStop { position: 0.5; color: Qt.rgba(1,1,1,0.3) }
GradientStop { position: 1.0; color: Qt.rgba(0,0,0,0.05) }
}
}
}
PropertyAnimation {
target: control
property: "value"
from: 0
to: 1
duration: 5000
running: true
loops: Animation.Infinite
}
}

How to create a prespective image in qml

I am trying to create perceptive image from a normal image
I need something like this
from something like this
I tried different ways like rotate and use a mask like this
Image {
id: bug
source: "./Graphics/sample.png"
width: 200
height: 200
anchors.centerIn: parent
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
transform: Rotation { origin.x: 30; origin.y: 30; axis { x: 0; y: 1; z: 0 } angle: 46 }
visible: true
layer.enabled: true
layer.effect: OpacityMask {
maskSource:
Image {
id: mask
source: "./mask.png"
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
visible: false
}
}
}
Is there any proper way to actually create an effect like this.
I am not sure, if I got it right, but is it something like this, you want to achive?
Item {
width: 1000
height: 500
anchors.centerIn: parent
RectangularGlow {
id: effect
anchors.fill: img
glowRadius: 25
spread: 0.2
color: "black"
cornerRadius: 50
}
Image {
id: img
anchors.centerIn: parent
width: 1000
height: 500
source: 'source.png'
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: 1000
height: 500
radius: 25
}
}
}
transform: Rotation { axis {x: 0.5; y: 1; z: 0} angle: 45 }
}
Or maybe it is a DropShadow you want to apply, instead of the RectangularGlow
DropShadow {
anchors.fill: img
horizontalOffset: -15
verticalOffset: 8
radius: 20
samples: 40
color: "#80000000"
source: Rectangle {
width: 1000
height: 500
radius: 25
}
}

Qml slider style, assigning different groove color before and after the slider's handle

So I wanted to create a slider style, similar to the default one, and also more matching to my applications style, but I found it hard to assign a different color before and after the slider's handle.
Here's a simplified version of my code, without gradients, anchor points and other properties:
Slider{
id: widthSlider
style: SliderStyle {
groove: Rectangle {
height: widthSlider.height*0.17
width: widthSlider.width
color: "black"
radius: 8
}
handle: Rectangle {
color: "grey"
}
}
}
I tried a rough workaround, to put two rectangles in the slider, anchored to the handle position like this:
Slider{
id: widthSlider
Rectangle {
anchors.left: widthSlider.left
anchors.right: widthSlider.__handlePos
color: "black"
}
Rectangle {
anchors.left: widthSlider.__handlePos
anchors.right: widthSlider.right
color: "white"
}
...
}
but I cannot anchor to the handle's position since it's just a double(I get the error: Unable to assign double to QQuickAnchorLine).
Does anyone have an idea of how I could do this in Qml?
Something like this?
Slider {
anchors.centerIn: parent
value: 0.5
width: 400
style: SliderStyle {
groove: Item {
implicitHeight: 10
LinearGradient {
anchors.fill: parent
start: Qt.point(0, control.height / 2)
end: Qt.point(control.width, control.height / 2)
gradient: Gradient {
GradientStop { position: 0.0; color: "orange" }
GradientStop { position: control.value; color: "brown" }
GradientStop { position: 1.0; color: "orange" }
}
}
}
}
}
Or:
Slider {
anchors.centerIn: parent
value: 0.5
width: 400
style: SliderStyle {
groove: Rectangle {
implicitHeight: 10
color: "lightgrey"
border {
color: "#999"
width: 1
}
Rectangle {
implicitHeight: 10
color: "orange"
implicitWidth: control.value * parent.width
border {
color: "#999"
width: 1
}
}
}
}
}
I realize this is an old question. However for future reference the Rectangle that represents the colour before the handle should have a width of styleData.handlePosition. The below code is from folibis second solution with this change.
Slider {
anchors.centerIn: parent
value: 0.5
width: 400
style: SliderStyle {
groove: Rectangle {
implicitHeight: 10
color: "lightgrey"
border {
color: "#999"
width: 1
}
Rectangle {
implicitHeight: 10
color: "orange"
implicitWidth: styleData.handlePosition
border {
color: "#999"
width: 1
}
}
}
}
}

How to add animation onPressed and onReleased in QML Slider?

http://doc.qt.io/qt-5/qml-qtquick-controls-styles-sliderstyle.html
Slider {
anchors.centerIn: parent
style: SliderStyle {
groove: Rectangle {
implicitWidth: 200
implicitHeight: 8
color: "gray"
radius: 8
}
handle: Rectangle {
anchors.centerIn: parent
color: control.pressed ? "white" : "lightgray"
border.color: "gray"
border.width: 2
implicitWidth: 34
implicitHeight: 34
radius: 12
}
}
How to access the onReleased and onPressed of the slider in order to start and stop some animation?
Here is what I tried:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls 1.4
Window {
visible: true
Slider
{
id: head
property Rectangle thumb: thumb
anchors.centerIn: parent
style: SliderStyle {
groove: Rectangle {
implicitWidth: 200
implicitHeight: 8
color: "gray"
radius: 8
}
handle: Rectangle {
id: thumb
anchors.centerIn: parent
color: control.pressed ? "white" : "lightgray"
border.color: "gray"
border.width: 2
implicitWidth: 34
implicitHeight: 34
radius: 12
}
}
onPressedChanged:
{
if(pressed)
{
console.log("pressed")
returnAnimation.stop()
}
else
{
console.log("released")
returnAnimation.start()
}
}
ParallelAnimation {
id: returnAnimation
NumberAnimation { target: thumb.anchors; property: "horizontalCenterOffset";
to: 0; duration: 200; easing.type: Easing.OutSine }
NumberAnimation { target: thumb.anchors; property: "verticalCenterOffset";
to: 0; duration: 200; easing.type: Easing.OutSine }
}
}
}
Error:
ReferenceError: thumb is not defined
Here is a fully working example. You will have to create your own images referenced here since I can't attach them.
I have found scoping is tricky in QML with component objects. The ":style:handle" component in Slider can "see out" to the higher levels but the higher levels cannot "see in" to the ":style:handle" component.
General Strategy
Create a property in the Top Level Slider scope
Use the property inside the ":style:handle" component since it can "see out"
Use the higher level onPressedChanged handler and the pressed property to adjust the high level property which will be "seen" by the low level component.
Slider {
id: portVoltageSlider
width: 100; height: 27
maximumValue: 150; minimumValue: -150
value: 0.00
stepSize: 10
anchors { centerIn: parent }
// style:handle component will be able to see/access this property
// opacity value of style: SliderStyle:handle.sliderHover
property real hoverOpacity: 0
// adjust property on slider pressed
onPressedChanged: {
// show slider Hover when pressed, hide otherwise
if( pressed ) {
console.log("slider pressed. show hover.")
hoverShowAnimation.start()
}
else {
console.log("slider released. hide hover.")
hoverHideAnimation.start()
}
}
// gratuitous animation using opacity
PropertyAnimation {
id: hoverShowAnimation
target: portVoltageSlider; properties: "hoverOpacity"; from: portVoltageSlider.hoverOpacity; to: 1; duration: 500
}
PropertyAnimation {
id: hoverHideAnimation
target: portVoltageSlider; properties: "hoverOpacity"; from: portVoltageSlider.hoverOpacity; to: 0; duration: 500
}
style: SliderStyle {
id: sliderStyle
property bool hoverVisible: false
groove: Rectangle {
// x: slider1.leftPadding
y: portVoltageSlider.topPadding + portVoltageSlider.availableHeight / 2 - height / 2
implicitWidth: 200; implicitHeight: 4
width: portVoltageSlider.availableWidth; height: implicitHeight
radius: 2
color: "#bdbebf"
Rectangle {
width: portVoltageSlider.visualPosition * parent.width; height: parent.height
color: "yellow"
radius: 2
}
}
handle: Image {
id: sliderHandle
width: 22; height: 24
source: "sliderThumb.svg"
anchors { centerIn: parent }
Image {
id: sliderHover
width: 22; height: 24
source: "sliderValue.svg"
anchors { bottom: sliderHandle.top }
opacity: portVoltageSlider.hoverOpacity
Label {
id: check
anchors {centerIn: parent; verticalCenterOffset: -4 }
text: portVoltageSlider.value
font.pointSize: 6
font.bold: true
}
}
}
}
}
That what I meant in the comment above:
Slider {
...
onPressedChanged: {
if(pressed)
console.log("pressed")
else
console.log("released")
}
}
Would this work?
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls 1.4
Window {
visible: true
Slider
{
id: head
property Rectangle thumb: thumb
//Added these signals:
signal startAnim
signal stopAnim
anchors.centerIn: parent
style: SliderStyle {
groove: Rectangle {
implicitWidth: 200
implicitHeight: 8
color: "gray"
radius: 8
}
handle: Rectangle {
id: thumb
anchors.centerIn: parent
color: control.pressed ? "white" : "lightgray"
border.color: "gray"
border.width: 2
implicitWidth: 34
implicitHeight: 34
radius: 12
//Moved animation within the confines of the object that it actually pertains to
ParallelAnimation {
id: returnAnimation
NumberAnimation { target: thumb.anchors; property: "horizontalCenterOffset";
to: 0; duration: 200; easing.type: Easing.OutSine }
NumberAnimation { target: thumb.anchors; property: "verticalCenterOffset";
to: 0; duration: 200; easing.type: Easing.OutSine }
}
//Signal connections done here:
Component.onCompleted: {
head.startAnim.connect(returnAnimation.start)
head.stopAnim.connect(returnAnimation.stop)
}
}
}
onPressedChanged:
{
if(pressed)
{
console.log("pressed")
startAnim()
}
else
{
console.log("released")
stopAnim()
}
}
}
}

Resources