How to use the LinearGradient in a ShapePath? - qt

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"
}
}

Related

QML/Qt gradient charts

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
}

How do I create a ripple button effect in QML?

I'm using QtQuick/QML and I want to create a ripple effect when I click on a button. I do know that this is available in Material Style, but I think it's an inherent property when you change the theme and I don't want to change anything else in my project.
Is there a way to add ONLY the ripple effect onto my button, and change nothing else? If so, how do I do it?
As Kostia Hvorov said, QtQuick.Controls.Material.impl.Ripple is the easiest way to go.
I would like to add my trick to handle rectangular background with radius:
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.Material.impl 2.12
import QtGraphicalEffects 1.12
Column
{
spacing: 20
Button
{
anchors.horizontalCenter: parent.horizontalCenter
id: button
text: "ripple demo"
}
Ripple {
id: ripple
anchors.horizontalCenter: parent.horizontalCenter
clipRadius: 4
width: 200
height: 64
pressed: button.pressed
active: button.down || button.visualFocus || button.hovered
color: "#20FFFFFF"
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle
{
width: ripple.width
height: ripple.height
radius: 4
}
}
}
}
Try it Online
Easiest way to do it - using Ripple from QtQuick.Controls.Material.impl
So just add Ripple to your background Rect:
Ripple {
clipRadius: height
width: parent.width
height: parent.height
pressed: control.pressed
anchor: control
active: control.down || control.visualFocus || control.hovered
color: control.flat && control.highlighted ? control.Material.highlightedRippleColor : control.Material.rippleColor
}
You can replace "control.Material.rippleColor" or/and "control.Material.highlightedRippleColor" to any color and get any ripple color effect.
But there is one problem, it will work only with rectangular background(without round) otherwise it will be looking bad.
I have made this with some PropertyAnimation. Here is how:
import QtQuick 2.15
import QtQuick.Controls 2.15
Button {
id: control
opacity: enabled ? 1.0 : 0.2
property int tripleWidth: width * 3
background: Rectangle {
border.width: 1
border.color: "black"
radius: 3
color: "white"
clip: true
Rectangle {
id: ripple
property int diameter: 0
property int pressX: 0
property int pressY: 0
x: pressX - radius
y: pressY - radius
color: "green"
radius: diameter / 2
width: diameter
height: diameter
opacity: 1 - diameter / control.tripleWidth
function animate(x, y, size) {
pressX = x
pressY = y
diameter = size
}
Behavior on diameter {
PropertyAnimation {
duration: 200
onRunningChanged: {
if(!running) {
duration = 0;
ripple.diameter = 0;
duration = 200;
}
}
}
}
}
}
onClicked: {
ripple.animate(pressX, pressY, control.tripleWidth)
}
contentItem: Item {
implicitWidth: txt.implicitWidth
implicitHeight: 20
Text {
id: txt
anchors.centerIn: parent
text: control.text
}
}
}
I Edit last Answer and its work.. Here is How:
import QtQuick 2.5
import QtQuick.Window 2.5
import QtQuick.Controls 2.5
RoundButton {
id: control
width: 93
height: 39
property int tripleWidth: width * 3
background: Rectangle {
border.width: 1
border.color: "black"
radius: 3
color: "white"
clip: true
Rectangle {
id: ripple
property int diameter: 0
property int pressX: 0
property int pressY: 0
x: pressX - radius
y: pressY - radius
color: "green"
radius: diameter / 2
width: diameter
height: diameter
opacity: 1
function animate(x, y, size) {
pressX = x
pressY = y
diameter = size
}
Behavior on diameter {
PropertyAnimation {
duration: 300
}
}
}
}
onHoveredChanged: {
ripple.opacity = 0
ripple.diameter = 0
}
onPressed: {
ripple.opacity = 0.8
ripple.animate(pressX, pressY, control.tripleWidth)
}
Timer {
id: timer
}
contentItem: Item {
implicitWidth: txt.implicitWidth
implicitHeight: 20
Text {
id: txt
font.pointSize: 15
anchors.centerIn: parent
}
}
onClicked: {
function delay(delayTime, cb) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
delay(10, function() {
ripple.opacity = 0
ripple.diameter = 0
})
}
}
Try it....

QT QML Circle and a text listview

I wanted to create an UI similar to below images. I understand Qt Pathview helps me to move the items in an circular fashion. But I couldn't get how to create the background similar to the images with equal space between the text. I tried with rectangle (radius:360) to draw circle, but the pathview items doesn't move along the center of the rectangle-circle.
Maybe this simple example could help you with PathView:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 400
height: 400
Item {
id: container
width: 300
height: 300
anchors.centerIn: parent
Rectangle {
anchors.fill: parent
radius: width /2
color: "orange"
Rectangle {
x: 50
y: 50
width: 200
height: 200
radius: 100
color: "white"
}
}
PathView {
anchors.fill: parent
model: 10
delegate: Rectangle {
width: 50
height: 50
radius: 25
color: "green"
}
path: Path {
startX: 150; startY: 25
PathArc {
x: 150; y: 275
radiusX: 125; radiusY: 125
direction: PathArc.Clockwise
}
PathArc {
x: 150; y: 25
radiusX: 125; radiusY: 125
direction: PathArc.Clockwise
}
}
}
}
}

QML rotating a Gauge needle - pivot correctly

I am trying to rotate a Gauge needle, but instead of pivoting at the base of the needle which have a circle with cross.. needle is pivots around the tip of the needle.. please see the attached image.. tip of the image is fixed/pivots but base is rotating.. please suggest how to correct this ?
main.qml :--
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 2.5
Window
{
visible: true
x :0
y :0
width: 800
height: 480
color: "grey"
Rectangle
{
id: cluster
Speed_Needle{
id: cluster_pointer_base
x : 214+16
y : 222
}
}
Slider
{
id : slide_1
width: parent.width
from: 0
to: 360
value: 0
enabled: true
onValueChanged:
{
cluster_pointer_base.value=slide_1.value
}
}
}
Speed_Needle.qml :--
import QtQuick 2.0
Item {
property int value: 0
width: 186
height: 36
Image
{
id: root
source: "files/pointer_needle2.png"
x : 0
y : 0
transform: Rotation {
id: needleRotation
angle : value
Behavior on angle {
SmoothedAnimation { velocity: 50 }
}
}
}
}
You have to set the origin of the Rotation:
Speed_Needle.qml :--
import QtQuick 2.0
Item {
property int value: 0
width: 186
height: 36
Image
{
id: root
source: "files/REE Demo images/pointer_needle2.png"
x : 0
y : 0
transform: Rotation {
id: needleRotation
angle : value
origin.x: root.width / 2 // here!
origin.y: root.height / 2
Behavior on angle {
SmoothedAnimation { velocity: 50 }
}
}
}
}

How to implement curved scrollview in qml?

How to get the look of curved Scroll bar/scroll view as shown below in QML with Label or TextArea?
Basically this application is not a touch application.
Environment, Qt 5.7.0 in Linux.
You can use PathInterpolator from Controls.2. The example below is some Slider modification, you can adopt it for your needs:
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
id: mainWindow
visible: true
width: 400
height: 400
Path {
id: myPath
startX: 0; startY: 20
PathCurve { x: 100; y: 40 }
PathCurve { x: 200; y: 10 }
PathCurve { x: 300; y: 40 }
}
Slider {
id: control
width: 300
height: 50
anchors.centerIn: parent
background: Rectangle {
anchors.fill: parent
color: "orange"
Canvas {
anchors.fill: parent
contextType: "2d"
onPaint: {
context.strokeStyle = "MediumPurple";
context.path = myPath;
context.stroke();
}
}
PathInterpolator {
id: motionPath
path: myPath
progress: control.visualPosition
}
}
handle: Rectangle {
width: 30
height: 30
radius: 15
color: "DodgerBlue"
x: motionPath.x - 15
y: motionPath.y - 15
}
}
}
You can use a Flickable to have your view. To this Flickable you attatch a ScrollBar which you can style.
To style this ScrollBar is a bit tricky, for some of its properties are bullshit.
The position-property, which is documented as
This property holds the position of the scroll bar, scaled to 0.0 - 1.0.
will never reach 1.0 unless, the handles size is 0. You don't really have the ability to set the size of the handle, though. It will be automatically resized. So if you don't want to have a handle that fills the width of the ScrollBar entirely, you need to use a Item as a base and add a the visual inside this, so you have the sovereignity again.
All together, it might look like this:
Flickable {
anchors.fill: parent
contentWidth: width
contentHeight: mainWindow.height * 10
Rectangle {
width: 640
height: mainWindow.height * 10
gradient: Gradient {
GradientStop { color: 'orchid'; position: 0 }
GradientStop { color: 'orange'; position: 1 }
}
}
ScrollBar.vertical: ScrollBar {
id: scrollBar
width: 50
contentItem: Item {
// This will deal with the bullshit of the position. Imperfect, as I do not consider any margins/paddings
property real normalizedPosition: scrollBar.position * (scrollBar.height / (scrollBar.height - height))
Rectangle {
// Draw the curve by defining a function for x in dependance of the position.
x: Math.sin(Math.PI * parent.normalizedPosition) * 40
width: 10
height: parent.height // I use the default height, so it
// really goes from top to bottom.
// A smaller height means, you should
// also alter the y value to have a
// more natural behavior.
radius: 5
color: 'green'
Text {
text: parent.parent.normalizedPosition
}
}
}
}
}

Resources