Qt Qml ChartView align to left - qt

I have below ChartView using Qt Quick Qml.
Rectangle {
anchors.left: parent.left
anchors.leftMargin: 10
anchors.top: parent.top
anchors.topMargin: 10
width: parent.width
height: 100
ChartView {
id: myChartView
anchors.left: parent.left
width: parent.width
height: parent.height
// For removing extra padding around chart
margins { top: 0; bottom: 0; left: 0; right: 0 }
plotArea: Qt.rect(0, 0, parent.width, parent.height)
antialiasing: true
LineSeries {
id: mySeries
name: "mySeries"
axisX: myAxisX
axisY: myAxisY
width: 2
XYPoint { x: 0; y: 0 }
XYPoint { x: 5; y: 2 }
}
ValueAxis {
id: myAxisX
min: 0
max: 20
}
ValueAxis {
id: myAxisY
min: 0
max: 10
}
}
}
The issue that I am facing is my chart 0,0 starts from somewhere center of the screen/parent.
If I update the myAxisX.max to some 300 or 400 then I see 0,0 getting shifted to left.
But I want to start my chart always from the left-bottom independent of the myAxisX.max.

Related

Set correct size for custom QML slider

I'm trying to create a reusable slider. I'm having trouble to set implicit sizes correctly so that the CustomSlider includes the Slider and the Label. I would like to have a implicit size specified, but let the user set a width for the slider itself.
I tried using childrenRect but that gives me a binding loop error.
How can I have the yellow background span across all the components: the slider and the green label?
Currently:
Would like:
CustomSlider.qml
Item {
id: root
property int startval: 0
property int endval: 20
property int sliderWidth: 200
// This results in binding loop
//implicitHeight: childrenRect.height
implicitHeight: control.height + label.height
implicitWidth: sliderWidth
Rectangle {
color: "yellow"
width: root.width
height: root.height
}
Slider {
id: control
stepSize: 1
anchors.centerIn: parent
snapMode: Slider.SnapOnRelease
width: root.sliderWidth
from: root.startval
to: root.endval
handle: Rectangle {
id: handleId
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
width: 20
height: 20
radius: 20
color: "gray"
}
background: Rectangle {
y: (control.height - height) / 2
height: 4
radius: 2
color: "green"
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
color: "red"
radius: 2
}
}
}
Label {
id: label
width: 20
height: 20
text: control.value
font.pixelSize: 15
color: "black"
x: handleId.x + control.x
y: handleId.y - 20
Rectangle {
color: "green"
anchors.fill: parent
opacity: 0.3
}
}
}
Main.qml
CustomSlider {
anchors.centerIn: parent
startval: 0
endval: 10
//sliderWidth: 100
}
I usually set the Width and height based on the parent.
I set sliderWidth: parent.width/2.0 and for your green label I add TextMetrics and calculate its width based on the text that it wants to show.
import QtQuick 2.15
import QtQuick.Controls 2.15
Item {
id: root
property int startval: 0
property int endval: 0
property int sliderWidth: parent.width/2.0
// This results in binding loop
//implicitHeight: childrenRect.height
implicitHeight: control.height + label.height
implicitWidth: sliderWidth
Rectangle {
color: "yellow"
width: root.width
height: root.height
}
Slider {
id: control
stepSize: 1
anchors.centerIn: parent
snapMode: Slider.SnapOnRelease
width: root.sliderWidth
from: root.startval
to: root.endval
handle: Rectangle {
id: handleId
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
width: 20
height: 20
radius: 20
color: "gray"
}
background: Rectangle {
y: (control.height - height) / 2
height: 4
radius: 2
color: "green"
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
color: "red"
radius: 2
}
}
}
Label {
id: label
width: t_metrics.tightBoundingRect.width +4
height: t_metrics.tightBoundingRect.height +7
text: control.value
font.pixelSize: 15
color: "black"
x: handleId.x + control.x
y: handleId.y - 20
Rectangle {
color: "green"
anchors.fill: parent
opacity: 0.3
}
}
TextMetrics {
id: t_metrics
text: control.value.toString()
}
}
Updated:
in CustomSlider.qml , changed it to this code:
import QtQuick 2.15
import QtQuick.Controls 2.15
Item {
id: root
property int startval: 0
property int endval: 0
property int sliderWidth: parent.width/2.0
implicitHeight: control.height + label.height
implicitWidth: sliderWidth
Rectangle {
color: "yellow"
width: root.width +10
height: root.height +control.height + label.height + t_metrics.tightBoundingRect.height +7
Slider {
id: control
stepSize: 1
anchors.centerIn: parent
snapMode: Slider.SnapOnRelease
width: root.sliderWidth
from: root.startval
to: root.endval
handle: Rectangle {
id: handleId
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
width: 20
height: 20
radius: 20
color: "gray"
}
background: Rectangle {
y: (control.height - height) / 2
height: 4
radius: 2
color: "green"
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
color: "red"
radius: 2
}
}
}
Label {
id: label
width: t_metrics.tightBoundingRect.width +4
height: t_metrics.tightBoundingRect.height +7
text: control.value
font.pixelSize: 15
color: "black"
x: handleId.x + control.x
y: handleId.y /2 + 4
Rectangle {
color: "green"
anchors.fill: parent
opacity: 0.3
}
}
TextMetrics {
id: t_metrics
text: control.value.toString()
}
}
}
This makes your text label shows inside the yellow rectangle and in main.qml I add one Row with labels and spinboxes for the test.
If you want that user to set sliderWidth or startval and endval and then show him Slider you need to create that object dynamically.
and if you want to be displayed in the Column and don't overlap you need ColumnLayout.
If you want to scroll them then you need to use ScrollView.
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Window {
width: 660
height: 480
visible: true
title: qsTr("Hello World")
ScrollView {
width: parent.width
height : parent.height
contentWidth: slidersColumn.width
contentHeight: slidersColumn.height
clip : true
ColumnLayout {
id: slidersColumn
anchors.fill: parent
spacing:50
}
}
function addSlider(sliderWidth,startval,endval) {
var obj = Qt.createComponent("CustomSlider.qml");
var slider = obj.createObject(slidersColumn);
slider.startval=startval;
slider.endval=endval;
slider.sliderWidth=sliderWidth;
}
Row
{
x: 0
y: 5
width: parent.width
height: 30
Label {
id: lbl_slider_width
text: qsTr(" Slider width ")
}
SpinBox {
id: spinBox_slider_width
editable: true
from:0
to:parent.width
}
Label {
id: lbl_startval
text: qsTr(" Startval ")
}
SpinBox {
id: spinBox_startval
editable: true
from:0
to:parent.width
}
Label {
id: lbl_endval
text: qsTr(" Endval ")
}
SpinBox {
id: spinBox_endval
editable: true
from:0
to:parent.width
}
Button {
id: button
text: qsTr(" Create Slider")
onClicked:
{
addSlider(spinBox_slider_width.value,spinBox_startval.value,spinBox_endval.value)
}
}
}
}
The result is:

Implementing a slider in QML with a VU-meter like image as a background

I am trying to create a slider that I can move up and down with my mouse. However, I want to use my own image as the background. I am currently trying to implement this with a OpacityMask. Basically, I am trying to make the opacity 0 from where the handle is to the right end of the slider.
I would ordinarily just move a rectangle that is same color as the background over it. However, I want whatever element is under the slider to be displayed when the slider is pulled back.
How can I create this behavior?
import QtQuick 2.7
import QtQuick.Templates 2.0 as T
import QtGraphicalEffects 1.12
import "."
T.Slider {
id: control
implicitWidth: 200
implicitHeight: 26
handle: Rectangle {
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
width: 20
height: 15
radius: 5
color: control.pressed ? "#f0f0f0" : "#f6f6f6"
border.color: "gray"
}
background: OpacityMask {
anchors.fill: sliderImage
source: sliderImage
maskSource: mask
}
Image{
id: sliderImage
source: "./Jarvis2/images/volume_barH.png"
height: 20
width: parent.width
visible: false
}
Item{
id: mask
anchors.fill: sliderImage
Rectangle{
id: outer
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: control.visualPosition*parent.width
color: "gray"
opacity: 1
visible: false
}
Rectangle {
id: inner
color: "transparent"
z: 1
opacity: 1
anchors.left: outer.right
anchors.right: parent.right
anchors.top: outer.top
anchors.bottom: outer.bottom
visible: false
}
}
}
The slider at 100%:
The slider at around 70%:
The slider at around 24%
I think you can omit the OpacityMask and simply use a clipping Item:
Slider {
id: slider
width: 100
height: 300
orientation: Qt.Vertical
background: Item {
id: background
Item {
clip: true
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: (1 - slider.visualPosition) * slider.height
Rectangle { //Your image goes here
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: background.height
gradient: Gradient {
GradientStop { position: 0; color: "blue" }
GradientStop { position: 1; color: "red" }
}
}
}
}
}
You might have to fiddle a bit with the height of the clipping Item since there is some padding involved.
If you nevertheless want to use OpacityMask (because you want a different shape), you should put them together in the background:
Slider {
id: slider
width: 100
height: 300
orientation: Qt.Vertical
background: Item {
id: background
Rectangle { //Your image goes here
id: image
anchors.fill: parent
visible: false
gradient: Gradient {
GradientStop { position: 0; color: "blue" }
GradientStop { position: 1; color: "red" }
}
}
OpacityMask {
anchors.fill: parent
source: image
maskSource: mask
}
Item {
id: mask
visible: false
anchors.fill: parent
Rectangle {
radius: 10
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: parent.height * slider.position
color: "white"
}
}
}
}

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
}

QML - Opacity of stacked elements

I have two items that are stacked. Both items have a semi-transparent background. The circle now shows the the rounded rect below.
Is there any way I can hide the part of the long rounded rect that overlaps with the circle? Maybe changing the parent, that the background of the circle is pulled from the ancestor higher up, and therefore ignoring the rect immediately below it?
Here is the code:
Item
{
id: choice1
width: 300
height: 100
Rectangle
{
id: choiceLabel1
width: 0
height: parent.height / 1.5
radius: parent.height * 0.5
color: "#88808080"
anchors
{
verticalCenter: choice1.verticalCenter
left: choice1.left
leftMargin: choiceIcon1.width / 2
}
border
{
width: 2
color: "red"
}
}
Rectangle
{
id: choiceIcon1
width: choice1.height
height: choice1.height
radius: width * 0.5
color: "#88808080"
anchors
{
verticalCenter: choice1.verticalCenter
left: choice1.left
}
border
{
width: 2
color: "red"
}
}
}
A solution, albeit a bit hacky would be to implement your own QML MultiRectangle component, which allow to set an opacity and draw a border around a bunch of QML Rectangle
MultiRectangle.qml
import QtQuick 2.0
Item
{
id: root
layer.enabled: true
property int borderWidth: 2
property color borderColor
Component
{
id: rectangle
Rectangle{}
}
Component.onCompleted:{
var temp = children.length
for(var i=0; i<temp; i++)
rectangle.createObject(this,
{
"z":-100,
"anchors.centerIn": children[i],
"color": borderColor,
"width": children[i].width+borderWidth*2,
"height": children[i].height+borderWidth*2,
"radius": Math.max((children[i].height+borderWidth*2)
/children[i].height*children[i].radius,
(children[i].height+borderWidth*2)
/children[i].height*children[i].radius)
})
}
}
This will dynamically create a pseudo border behind the rectangles added to a MultiRectangle item.
Example
import QtQuick 2.5
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
Window {
id: root
visible: true
height: 200
width: 400
RadialGradient {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "white"}
GradientStop { position: 0.3; color: "#444"}
GradientStop { position: 1; color: "white"}
}
}
MultiRectangle {
anchors.centerIn: parent
width: 300
height: 100
borderWidth: 2
borderColor: "red"
opacity: 0.5
Rectangle {
color: "cyan"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: parent.borderWidth
height: parent.height - 2 * parent.borderWidth
width: height
radius: height / 2
}
Rectangle {
color: "cyan"
anchors.horizontalCenter: parent.horizontalCenter
anchors.margins: parent.borderWidth
anchors.top: parent.top
height: 10
width: height
radius: height / 2
}
Rectangle {
color: "cyan"
anchors.horizontalCenter: parent.horizontalCenter
anchors.horizontalCenterOffset: 30
anchors.margins: parent.borderWidth
anchors.top: parent.top
height: 30
width: height
radius: height / 2
}
Rectangle {
color: "cyan"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 50
height: parent.height * 0.6
anchors.right: parent.right
anchors.margins: parent.borderWidth
radius: height / 2
}
}
}
Result
Note that since layer.enabled is set to true, clip is also set to true. Therefore, the border of child items too close to the MultiRectangle bounds will be clipped.

How to anchor to a rotated rectangle edge?

I want to draw a few lines in qml and to relatively place them (and used Rectangle with small width for it).
Line 2 is rotated 45 degrees.
Line 3 is anchored to Line 1 and Line 2.
The issue is when I anchor a Line 3 to Line 2, it takes points before rotation. Is there a way to resolve this?
Rectangle {
id: idLine1
height: 2
color: "white"
width: idFluidStatus.width/3
anchors.left: idRect.right
anchors.verticalCenter: idRect.verticalCenter
}
Rectangle {
id: idLine2
height: 2
color: "white"
transformOrigin: Item.BottomLeft
rotation: 45
width: idFluidStatus.width/3
anchors.left: idRect.horizontalCenter
anchors.top: idLine1.bottom
}
Rectangle {
id: idLine3
height: 2
color: "red"
anchors.left: idLine2.right
anchors.right: idLine1.right
anchors.bottom: idLine2.bottom
}
Expected:
Obtained:
Adding running example code:
import QtQuick 2.0
Rectangle {
id: idFluidStatus
width: 500; height: 400
color: "darkgray"
Rectangle {
id: idLine1
height: 2
color: "white"
width: idFluidStatus.width/3
anchors.left: idRect.right
anchors.verticalCenter: idRect.verticalCenter
}
Rectangle {
id: idLine2
height: 2
color: "white"
transformOrigin: Item.BottomLeft
rotation: 45
width: idFluidStatus.width/3
anchors.left: idRect.horizontalCenter
anchors.top: idLine1.bottom
Component.onCompleted: {
console.log(x, y, width, height)
}
}
Rectangle {
width: 50
height: 50
color: "green"
x: idLine2.x+idLine2.width
y: idLine2.y
}
Rectangle {
id: idLine3
height: 2
color: "red"
anchors.left: idLine2.right
anchors.right: idLine1.right
anchors.bottom: idLine2.bottom
}
Rectangle {
width: idRect.width + 5
height: width
radius: width/2
color: "white"
anchors.centerIn: idRect
}
Rectangle {
id: idRect
width: (idFluidStatus.width < idFluidStatus.height) ? idFluidStatus.width/6 : idFluidStatus.height/6
height: width
radius: width/2
color: "#155B5E"
opacity: 0.7
anchors {
top: idFluidStatus.top
topMargin: idFluidStatus.height/10
left: idFluidStatus.left
leftMargin: idFluidStatus.width/10
}
}
}

Resources