QML Slider Handle is not moving - qt

I am having issues in moving a slider handle when I try to style "handle:Rectangle" ,Below is the code:
Slider {
id: slider
x: 372
y: 70
width: 33
height: 457
spacing: 0
anchors.rightMargin: 395
rotation: 0
orientation: Qt.Vertical
font.family: "Arial"
value: 0.5
anchors.right: parent.right
background: Rectangle {
anchors.centerIn: parent
x: slider.topPadding + slider.availableWidth / 2 - width / 2
y: slider.leftPadding
implicitWidth: 200
implicitHeight: 4
width: slider.availableHeight
height: implicitHeight
radius: 2
rotation: 90
color: "#bdbebf"
}
handle: Rectangle {
anchors.centerIn: parent
color: slider.pressed ? "white" : "red"
border.color: "gray"
//border.width: 2
width: 20
height: 20
radius: 6
}
}
I am able to move the slider if i am not styling handle:Rectangle.
please Suggest.

That is, because you can't anchor it to the center. You need to specify the x and y values in dependance of the visualPosition.
See the example on how to customize a slider.
Be aware, that the customization provided there does not account for vertical sliders, so you need to adapt it:
y: slider.topPadding + slider.visualPosition * (slider.availableHeight - height)
x: slider.leftPadding + slider.availableWidth / 2 - width / 2
should do it for you. Remove the anchoring of course!

Related

How to create a Progress Bar in Qml with slant lines?

Hello ,
I am looking for some solution to create a progress bar in qml having slant lines.
I dont having any snippet to share here, as I am not aware how to do so.
Can anyone please guide ??
I am going to solve the problem in stages. This is reflective of how I go about solving QML problems myself. The first goal is to create a 200x32 ProgressBar and to set it to 25% progress. First, I start with a blank Rectangle for my custom ProgressBar:
ProgressBar {
implicitWidth: 200
implicitHeight: 32
contentItem: Rectangle {
border.color: "black"
}
}
Next, I decide to craft a 32x32 SVG of a diagonal line and I repeat this line at 4 pixel intervals covering the whole width (i.e. 200 / 4 === 50).
ProgressBar {
implicitWidth: 200
implicitHeight: 32
contentItem: Rectangle {
border.color: "black"
Repeater {
model: 200 / 4
Image {
x: index * 4
y: 0
source: `data:image/svg+xml;utf8,
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path fill="none" stroke="black" d="M 0 0 L 32 32" />
</svg>`
}
}
}
}
I observe two problems with the above:
The triangle gap at the left
The overshoot at the right
To fix these problems, (1) shift the lines 32 pixels to the left to cover the gap, (2) I extend the lines to be (200 + 32) / 4 === 58, (3) use clip to crop clean the diagonals that are outside my Rectangle.
ProgressBar {
implicitWidth: 200
implicitHeight: 32
contentItem: Rectangle {
border.color: "black"
clip: true
Repeater {
model: (200 + 32) / 4
Image {
x: index * 4 - 32
y: 0
source: `data:image/svg+xml;utf8,
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path fill="none" stroke="black" d="M 0 0 L 32 32" />
</svg>`
}
}
}
}
Next, I want to represent 25%. I do this by drawing a 75% white Rectangle covering the slant lines on the right.
ProgressBar {
implicitWidth: 200
implicitHeight: 32
value: 0.25
contentItem: Rectangle {
border.color: "black"
clip: true
Repeater {
model: (200 + 32) / 4
Image {
x: index * 4 - 32
y: 0
source: `data:image/svg+xml;utf8,
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path fill="none" stroke="black" d="M 0 0 L 32 32" />
</svg>`
}
}
Rectangle {
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
implicitWidth: parent.width * 0.75
implicitHeight: parent.height
border.color: "black"
color: "white"
}
}
}
Finally, we try to generalize our solution:
ProgressBar {
id: progressBar
implicitWidth: 200
implicitHeight: 32
contentItem: Rectangle {
border.color: "black"
clip: true
Repeater {
model: (parent.width + parent.height) / 4
Image {
x: index * 4 - parent.height
y: 0
source: `data:image/svg+xml;utf8,
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${parent.height} ${parent.height}">
<path fill="none" stroke="black" d="M 0 0 L ${parent.height} ${parent.height}" />
</svg>`
}
}
Rectangle {
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
implicitWidth: parent.width * (1 - parent.parent.value)
implicitHeight: parent.height
border.color: "black"
color: "white"
}
}
}
There are assumptions that we made:
ProgressBar is 200x32
Color is white bar with a black outline with black diagonal lines
The bar to the right is filled white
A SVG image is used
To generalize further, we can consider (1) replacing the SVG Image with a more efficient equivalent, (2) allow the colours to be configurable.
I recommend using ShaderEffect to create a more efficient result.
So, as everyone else implemented their own code, I did as well.
The results are shown below.
SlantLines.qml
// SlantLines.qml
import QtQuick 2.12
ShaderEffect {
id: effect
property real seed: 0 // To animate the lines' x axis.
property real num: width / 6 // The number of lines changes with width and may even be fixed.
property color color: '#000' // Color of lines (background is transparent)
property vector2d ratio: {
const max = Math.max(width, height);
return Qt.vector2d(width/max, height/max);
}
fragmentShader: "
uniform lowp float qt_Opacity;
uniform lowp float seed;
uniform lowp float num;
uniform highp vec2 ratio;
uniform highp vec4 color;
varying highp vec2 qt_TexCoord0;
void main() {
vec2 uv = qt_TexCoord0*ratio/ ratio.x;
// Slope can be changed by multiplying 'y' by any number.
uv.x -= uv.y + seed/num;
vec2 grid = fract(uv * vec2(num,1.));
// You may also change the line width from 0.0 to 1.0. (change 0.5)
gl_FragColor = color * smoothstep(0.0,ratio.x*1e-1,grid.x - 0.5) * qt_Opacity;
}"
}
Preview
An example of how it works.
component SlantLinesColumn: Column {
property real xSeed: 0
spacing: 5
Repeater {
model: 12
SlantLines {
height: 10
width: (index + 1) * 20
color: Qt.hsva(index/13,1,1,1)
seed: xSeed
}
}
}
SlantLinesColumn { }
SlantLinesColumn {
y: 190
Timer {
running: true; repeat: true
interval: 50 // Almost 20Hz.
onTriggered: parent.xSeed -= 0.1
}
}
ProgressBar.qml
SlantLines can also be embedded in a progressbar.
This template is available from the Qt source code.
// ProgressBar.qml
import QtQuick 2.15
import QtQuick.Templates 2.15 as T
T.ProgressBar {
id: control
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding)
property int orientation: Qt.Vertical
readonly property bool vertical: orientation == Qt.Vertical
contentItem: Item {
SlantLines {
y: control.vertical ? parent.height - height : 0
width: !control.vertical && !control.indeterminate ?
parent.width * control.position : parent.width
height: control.vertical && !control.indeterminate ?
parent.height * control.position : parent.height
color: control.palette.dark
Timer {
running: control.visible && control.indeterminate
repeat: true; interval: 50
onTriggered: parent.seed -= 0.1
}
}
}
background: Rectangle {
implicitWidth: !control.vertical ? 200 : 18
implicitHeight: control.vertical ? 200 : 18
color: control.palette.midlight
}
}
Edit (NumberAnimation)
As #Mitch mentioned in the comments, Timer may also be replaced with NumberAnimation, as shown in the following code:
The Timer is just used to limit the animation refresh rate, which also reduces resource use.
SlantLines {
...
NumberAnimation on seed {
running: control.visible && control.indeterminate
loops: Animation.Infinite
from: 0; to: -1
duration: 500
}
}
Yet another solution.
ProgressBar {
id: control
property color contentItemColor: "white"
property color backgroundColor: "yellow"
property color borderColor: "red"
property int borderWidth: 1
property color stripColor: "green"
property int stripGap: 10
property int stripWidth: 2
property color indicatorColor: "red"
property int indicatorWidth: 2
property int indicatorRadius: 0
property int indicatorExtend: 0
value: 0.5
width: 600
height: 80
background: Rectangle {
color: control.backgroundColor
border.width: control.borderWidth
border.color: control.borderColor
Canvas {
x: control.borderWidth
y: control.borderWidth
width: control.width - (2 * control.borderWidth)
height: control.height - (2 * control.borderWidth)
onPaint: {
var ctx = getContext("2d");
ctx.strokeStyle = control.stripColor
ctx.lineWidth = control.stripWidth
ctx.lineCap = "square"
var p1, p2
let n = Math.ceil((control.width + control.height) / (control.stripGap)) + 1
for (let i = 0; i != n; ++i) {
let p = i * control.stripGap
p1 = Qt.vector2d(p - control.height, 0)
p2 = Qt.vector2d(p, control.height)
ctx.beginPath()
ctx.moveTo(p1.x, p1.y)
ctx.lineTo(p2.x, p2.y)
ctx.closePath()
ctx.stroke()
}
}
}
}
contentItem: Item {
Rectangle {
anchors.fill: parent
anchors.margins: control.borderWidth
anchors.leftMargin: Math.max(control.borderWidth,
control.visualPosition * control.width)
color: control.contentItemColor
}
Rectangle {
x: control.visualPosition * control.width - (control.indicatorWidth / 2)
y: -control.indicatorExtend
width: control.indicatorWidth
height: control.height + (2 * control.indicatorExtend)
color: control.indicatorColor
radius: control.indicatorRadius
visible: control.visualPosition > 0.0 && control.visualPosition < 1.0
}
}
}
The indeterminate Fusion style ProgressBar does something similar, where it has moving slanted lines.
Here's the code from that adjusted to show the lines for determinate bars as well, using only public APIs:
import QtQuick
import QtQuick.Controls
ApplicationWindow {
width: 640
height: 480
visible: true
ProgressBar {
id: control
value: 0.5
contentItem: Item {
implicitWidth: 120
implicitHeight: 24
Rectangle {
height: parent.height
width: control.position * parent.width
radius: 2
border.color: "steelblue"
gradient: Gradient {
GradientStop {
position: 0
color: Qt.lighter("steelblue", 1.2)
}
GradientStop {
position: 1
color: Qt.darker("steelblue", 1.2)
}
}
}
Item {
x: 1
y: 1
width: parent.width - 2
height: parent.height - 2
clip: true
Image {
width: Math.ceil(parent.width / implicitWidth + 1) * implicitWidth
height: parent.height
mirror: control.mirrored
fillMode: Image.TileHorizontally
source: "qrc:/qt-project.org/imports/QtQuick/Controls/Fusion/images/progressmask.png"
opacity: 0.25
NumberAnimation on x {
running: control.visible
from: -31 // progressmask.png width
to: 0
loops: Animation.Infinite
duration: 750
}
}
}
}
}
}
If you don't want the animation, just remove the NumberAnimation.
Note that since this example uses an image from the Fusion style (for convenience), it must be run with the Fusion style.
If you want to run it with another style, replace the image's URL with another, and make sure you're using a non-native style:
Note: The macOS and Windows styles are not suitable for customizing. It is instead recommended to always base a customized control on top of a single style that is available on all platforms, e.g Basic Style, Fusion Style, Imagine Style, Material Style, Universal Style. By doing so, you are guaranteed that it will always look the same, regardless of which style the application is run with. For example:

How to change QML checkbox indicator and checkmark color?

I have CheckBox element in QML:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.Material 2.12
Item
{
id: root
CheckBox
{
id: timeCheckbox
height: 30
anchors.left: parent.left
anchors.leftMargin: 30
anchors.top: parent.top
anchors.topMargin: 10
text: "Display time"
checked: true
}
CheckBox
{
id: delayCheckBox
height: 30
anchors.left: parent.left
anchors.leftMargin: 30
anchors.top: timeCheckbox.bottom
anchors.topMargin: 10
text: "Enable Delay"
checked: true
}
}
I want to change the indicator background color to blue and check mark sign to black. But If I try with adding this in CheckBox element everything breaks and there is only blue rectangle displayed:
indicator: Rectangle
{
background: "blue"
}
I also tryed with this but no success:
Component.onCompleted: indicator.children[0].color = "blue"
And for checkmark color I could not find any sources for changing the color.
I have this:
And I want to modify it to this:
Any hint or help is welcome. Thanks in advance.
Unfortunately you cannot modify QML checkbox by accessing the property but here there are 2 possibles solutions
-1 you can work via stylesheet like that:
#QCheckBox::indicator{
background-color: #0000FF;
}
#
-2 you can copy the qml implementation of the checkbox and change de property like here
ApplicationWindow {
id: window
title: "Stack"
visible: true
width: 300
CheckBox {
id: control
indicator: Rectangle {
implicitWidth: 28
implicitHeight: 28
x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
y: control.topPadding + (control.availableHeight - height) / 2
color: control.down ? control.palette.light : control.palette.base
border.width: control.visualFocus ? 2 : 1
border.color: control.visualFocus ? control.palette.highlight : control.palette.mid
ColorImage {
x: (parent.width - width) / 2
y: (parent.height - height) / 2
defaultColor: "#353637"
color: "blue" // you can add your color here
source: "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png"
visible: control.checkState === Qt.Checked
}
Rectangle {
x: (parent.width - width) / 2
y: (parent.height - height) / 2
width: 16
height: 3
color: control.palette.text
visible: control.checkState === Qt.PartiallyChecked
}
}
}
}
hope it helps , bye

QML, How to tell the Item rendered size after scale

So I have an Image inside a Flickable. I want to know the size of the image after the scale is applied so that I can assign it to the Flickable's contentWidth and contentHeight. Is there a way to get the size after the scale has been applied?
Flickable{
contentWidth: target.width
contentHeight: target.height
Image{
id: target
horizontalAlignment: Image.AlignLeft
verticalAlignment: Image.AlignTop
fillMode: Image.PreserveAspectFit
scale: slider_bar.value
source: "/image.png"
}
}
Slider{
id: slider_bar
from: 0
to : 2
value: 1
}
Another example is where I want to make the rect_1 large and the rect_2 to stay to the right of it. When running the following rect_1 resizes but rect_2 does not move.
Rectangle{
id:rect_1
height: 100
width: 100
scale: slider_bar.value
transformOrigin: Item.TopLeft
color: "green"
}
Rectangle{
id: rect_2
anchors.left: rect_1.right
height: 100
width: 100
color:"red"
}
Slider{
id: slider_bar
from: 0
to : 2
value: 1
}
I could do something like
ScaledItem.qml
Item{
height: implicitHeight
width:implicitWidth
implicitHeight: childrenRect.height * scale
implicitWidth: childrenRect.width * scale
scale:1
}
then
ScaledItem{
scale: slider_bar.value
transformOrigin: Item.TopLeft
id:rect_1
Rectangle{
height: 100
width: 100
color: "green"
}
}
Rectangle{
anchors.left: rect_1.right
height: 100
width: 100
color:"red"
}
Slider{
id: slider_bar
from: 0
to : 2
value: 1
}

custom Slider without using the QML one?

I'm looking for sliders examples without using the QML one. Just by using rectabgle but i dont really know how to handle it?
The QML one dont have so much properties:
Slider {
id: sliderHorizontal1
x: 69
y: 52
activeFocusOnPress: true
tickmarksEnabled: true
minimumValue: 0
}
Thanks,
I found answer by using QML slider.
Slider {
id: slider
x: 56
y: 53
width: 450
height: 30
tickmarksEnabled: true
activeFocusOnPress: true
updateValueWhileDragging: true
value: 10
maximumValue: 30
style: SliderStyle {
handle: Rectangle {
height: 40
width: height
radius: width/2
color: "#fff"
}
groove: Rectangle {
implicitHeight: 10
implicitWidth: 100
radius: height/2
border.color: "#333"
color: "#222"
Rectangle {
height: parent.height
width: styleData.handlePosition
implicitHeight: 6
implicitWidth: 100
radius: height/2
color: "red"
}
}
}
}
I can add modification inorder to match to my needs...
Thanks #Tarod

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