How to Remove Spacing between chartview and it's Plotarea in QML - qt

1) My requirement is that Plotarea of chartview in Qml should acquire whole space.
2) I don't want spacing between chartview and plotarea grids.
3) For this, i made
margins.top: 0
margins.bottom: 0
margins.left: 0
margins.right: 0
4) After Doing this, there was still little spacing between grids and chartview.
5) Then i did this, by giving minus values to x,y axis and increasing width and height.
Rectangle
{
width : 400
height: 200
clip:true
ChartView
{
height: parent.height+42
width: parent.width+51
x:-32
y:-15
legend.visible:false
margins.top: 0
margins.bottom: 0
margins.left: 0
margins.right: 0
}
}
6) After doing this it got adjusted properly.
7) But when i am chaning Valueaxis(max), then it is again chaing it's position.
8) Valueaxis which is inside chartview, there is min max value, if max=5 then it's
displaying properly, if i change max=10 then it's changing its position, on some value's
it's showing properly, on some it's not
ValueAxis
{
id:y_axis
min: 0
max: 5 // on 5 it's proper, if i change it to 10 grids position is changing
tickCount: 4
labelsVisible: false
}
Any Possible Solution ?

Here's how to do that:
ChartView
{
height: parent.height+42
width: parent.width+51
x:-32
y:-15
legend.visible:false
plotArea: Qt.rect(x, y, width, height)
}
You're forcing your plotArea to be at the same position of the ChartView and to have same dimensions.
It might probably be Qt.rect(0, 0, width, height). I haven't tried it with your numbers. I'm assuming it's 0, 0 because that's the offset from the parent ChartView.

Related

Proper way of defining and composing custom elements in QML

Lets say I want to create a field element in QML which has its "field" part and could have icon on the right, left side or not show it at all. Basic qml code would look like this (without functionality to change sides):
// TestField.qml
Item
{
Image
{
anchors.right: field.left
anchors.top: field.top
source: "qrc:/res/settings/logOptions.svg"
height: 40
width: 40
}
Rectangle
{
id: field
anchors.fill: parent
color: "blue"
}
}
Then I will use it like this:
// Main.qml
TestField
{
x: 100
y: 100
height: 100
width: 100
}
Or use it in some grid layout, anchor it to another element, etc. I used hardcoded coordinates and sizes just to keep the question simpler.
The problem with this is that I specified sizes for the element (100x100) and my field rectangle would fill the whole space, leaving icon "hanging" out of bounds of this element. In this case QML will treat this element as of the size 100x100, but since the icon is out of bounds the actual size of the whole element with the icon is bigger (140x100) and could overlap with other such elements when placed into layout.
Worth noting that for such elements I want to be able to change position of the icon to be to the left or right of the rectangle (it will be some sort of property with enum value, that I will define in code, it won't change dynamically throughout application work) so some rectangles will have icon from different sides.
One solution I see is to rework TestField so its elements will be tied to parents width or height, for example:
Item
{
Image
{
x: 0
y: 0
width: parent.width / 2
height: parent.width / 2
}
Rectangle
{
id: field
x: parent.width / 2
y: 0
width: parent.width / 2
height: parent.height
}
}
The question is - is this a good solutions or there are proper ways to tackle such issue? My main concern is that element size should be actually the size that I could query with element.width or element.height and none of the internal part are out of bounds possibly overlapping with other elements. Maybe I'm missing some basic concept that will allow me to make elements that always keep their parts inside its bounds?
The problem with your sizing is that your Rectangle takes up the whole size of its parent. You want to shrink that to account for the size of the Image. I also added a way to switch the image between left and right side.
Item
{
property bool imageOnLeft: true
Image
{
id: img
anchors.left: imageOnLeft ? parent.left : field.right
source: "qrc:/res/settings/logOptions.svg"
height: 40
width: 40
}
Rectangle
{
id: field
anchors.left: imageOnLeft ? img.right : parent.left
width: parent.width - img.width
height: parent.height
color: "blue"
}
}

How to create QML slider with a custom shape?

I have to create a slider with a custom shape like the one shown below (blue is the slider handle):
The red color one is groove and the blue color one is handle.
For the groove, you can use any Item to draw this shape, e.g. a Image
For the handle, you just use a Rectangle and place it according to the Slider.position, e.g. like so:
Slider {
id: slider
width: 400
height: 150
y: 200
handle: Rectangle {
x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)
y: Math.max(slider.topPadding, slider.availableHeight - height + slider.topPadding - ((slider.availableHeight - height) * (slider.position * 2)))
width: 15
height: 30
radius: 5
color: 'blue'
}
}
If you have a stranger shape, just change the function for y.
You can use any function that maps a value position (range [0, 1]) to an y-value. You can use every property of the slider, to calculate an appropriate position.
Here another example, where the slider draws the sine function:
Slider {
width: 400
height: 150
id: slider1
y: 200
handle: Rectangle {
x: slider1.leftPadding + slider1.visualPosition * (slider1.availableWidth - width)
y: slider1.topPadding + (slider1.availableHeight - height) / 2 + (slider1.availableHeight - height) / 2 * Math.sin(slider1.position * 10)
width: 15
height: 30
radius: 5
color: 'blue'
}
}
And here for the fun of it: A random function. But I don't think you can draw a fitting groove to it
Slider {
id: slider
width: 400
height: 150
y: 200
onPositionChanged: {
var a = Math.round(Math.random() * 5) - Math.round(Math.random() * 5)
console.log(a)
handle.handleY = handle.y + (a)
console.log(handle.handleY)
}
handle: Rectangle {
property int handleY: slider.topPadding + slider.availableHeight / 2 - height / 2
x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)
y: Math.max(slider.topPadding, Math.min(handleY, slider.availableHeight - height + slider.topPadding))
width: 15
height: 30
radius: 5
color: 'blue'
}
}
You can do this directly in QML using Canvas or in Qt C++ (example with a circular slider) and then expose the element to QML. While not a direct copy-and-paste solution check this to see a custom circular progress bar that uses arc() to draw the element. You can use line() if you want straight lines. The behaviour of the slider is also something you will have to do on your own.
You can try to inherit from Slider to try and get some (or even most) of the functionality that your element requires.

Drawing to the left of x,y coordinates

I'm working currently on Qt, when i try to draw something (for e.x Rectangle) giving its x,y coordinates & its width & height Qt starts to draw the rectangle starting from its x, y coordinates to the right direction, to demonstrate what I'm talking about see the following picture:
and the following code:
Rectangle {
id: rectangle1
x: 257
y: 221
width: 50
height: 50
color: "#000000"
}
I would like to know if there is anyway i can start drawing to the left of x,y coordinates, it's like drawing giving the width & height negative values. see the following image for illustration:
I have tried drawing giving the width a negative value, it works fine on the design mode but when i run or debug my application the rectangle does not show up, any ideas on this would be appreciated
You can not use negative values for this purpose since negative width or height is not supported in QML. But you can use Scale type to accomplish this :
Rectangle {
id: rectangle1
x: 257
y: 221
width: 50
height: 50
color: "#000000"
transform: Scale { origin.x: 0; origin.y: 0; xScale: -1}
}
Scale allows you to scale your item relative to an arbitrary point. Here we scaled the X axis of the item relative to it's interior point (0, 0).
To draw rectangle 50px from the left parent area:
Rectangle {
id: rectangle1
x: parent.width - 50 // rectangle start 50px from the left
y: 221 // similar with y pos: parent.height - 50
width: 50
height: 50
color: "#000000"
}
But I am not sure If I understood your question properly.

How to use QML Scale Element for incremental scaling with different origin

I'm trying to use a QML Scale Element to perform view scaling around a point clicked by the user, but it's not always working as documented.
To reproduce the problem, run the minimal QML example below (I'm using Qt 5.3.1 on Ubuntu 14.04 x86_64) and then:
Click in the center of the blue rectangle at the top left.
See that everything is scaled up, but the center of the blue rectangle remains at your click location. This is as documented in http://doc.qt.io/qt-5/qml-qtquick-scale.html - "[The origin] holds the point that the item is scaled from (that is, the point that stays fixed relative to the parent as the rest of the item grows)."
Now click in the center of the red rectangle.
See that everything is scaled up, but the center of the red rectangle did not remain at your click point, it was translated up and to the left. This is not as documented.
My goal is to have it always zoom correctly maintaining the click point as the origin, as stated in the documentation.
P.S. Interestingly, if you now click again in the center of the red rectangle, it scales up around that point as promised. Clicking again now on the center of the blue rectangle, you see the same unexpected translation behaviour.
P.P.S. I'm working on an application where the user can mouse-wheel / pinch anywhere on the containing rectangle, and everything inside should scale up or down around the mouse / pinch position. Many applications have exactly this behaviour. See for example inkscape.
import QtQuick 2.2
import QtQuick.Controls 1.1
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
x: 100
y: 100
width: 300
height: 300
transform: Scale {
id: tform
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(mouse.x + " " + mouse.y)
tform.xScale += 0.5
tform.yScale += 0.5
tform.origin.x = mouse.x
tform.origin.y = mouse.y
}
}
Rectangle {
x: 50
y: 50
width: 50
height: 50
color: "blue"
}
Rectangle {
x: 100
y: 100
width: 50
height: 50
color: "red"
}
}
}
(I filed this as a Qt bug, because the behaviour does not follow the documentation. At the moment of writing, the bug seems to have been triaged as "important". https://bugreports.qt.io/browse/QTBUG-40005 - I'm still very much open to suggestions of work-arounds / fixes over here)
In fact it is not a deviant behavior, just a different one from what you may expect after reading the doc.
When you change the Scale transform of your rectangle, the transformation is applied on the original rectangle. The point you click on stay in the same place from the original rectangle point of view.
That's why your rectangle "moves" so much when you click on one corner then the opposite corner.
In order to achieve what you want, you can't rely on transform origin. You have to set the actual x y coordinates of your rectangle.
Here's a working example:
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: rect
x: 100
y: 100
width: 300
height: 300
Rectangle {
x: 50
y: 50
width: 50
height: 50
color: "blue"
}
Rectangle {
x: 100
y: 100
width: 50
height: 50
color: "red"
}
transform: Scale {
id: tform
}
MouseArea {
anchors.fill: parent
property double factor: 2.0
onWheel:
{
if(wheel.angleDelta.y > 0) // zoom in
var zoomFactor = factor
else // zoom out
zoomFactor = 1/factor
var realX = wheel.x * tform.xScale
var realY = wheel.y * tform.yScale
rect.x += (1-zoomFactor)*realX
rect.y += (1-zoomFactor)*realY
tform.xScale *=zoomFactor
tform.yScale *=zoomFactor
}
}
}
}

QML NumberAnimation.duration behaviour

I'm trying to make a player move smoothly towards a destination in QML. I'm using a NumberAnimation to animate the x,y position changes. The NumberAnimation's duration should be proportional to the distance the player has to travel, so that the player moves at the same speed regardless of how far away they are from their destination.
import QtQuick 1.1
Item {
width: 720
height: 720
MouseArea {
anchors.fill: parent
onClicked: {
var newXDest = mouse.x - player.width / 2;
var newYDest = mouse.y - player.height / 2;
var dist = player.distanceFrom(newXDest, newYDest);
// Make duration proportional to distance.
player.xMovementDuration = dist; // 1 msec per pixel
player.yMovementDuration = dist; // 1 msec per pixel
console.log("dist = " + dist);
player.xDest = newXDest;
player.yDest = newYDest;
}
}
Rectangle {
id: player
x: xDest
y: yDest
width: 32
height: 32
color: "blue"
property int xDest: 0
property int yDest: 0
property int xMovementDuration: 0
property int yMovementDuration: 0
function distanceFrom(x, y) {
var xDist = x - player.x;
var yDist = y - player.y;
return Math.sqrt(xDist * xDist + yDist * yDist);
}
Behavior on x {
NumberAnimation {
duration: player.xMovementDuration
// duration: 1000
}
}
Behavior on y {
NumberAnimation {
duration: player.yMovementDuration
// duration: 1000
}
}
}
Rectangle {
x: player.xDest
y: player.yDest
width: player.width
height: player.height
color: "transparent"
border.color: "red"
}
}
My problem can be demonstrated by running the application above and following these steps:
Click on the bottom right hand corner of the screen.
Immediately click in the centre (or closer towards the top left) of the screen.
On the second click (while the rectangle is still moving), it seems that the rectangle's number animation is stopped (which is what I want) but it assumes the position of the destination (not what I want). Instead, I want the animation to stop and the rectangle to assume the position at which it was stopped, then to continue on to the new destination.
The correct behaviour - ignoring that the movement speed becomes disproportional - can be seen by setting both of the NumberAnimation.durations to 1000.
I think that you are looking for SmoothedAnimation. There are only two types of animation that deal nicely with the destination changing before the animation is completed. That is SmoothedAnimation and SpringAnimation. Both of these use the current position and velocity to determine the position in the next frame. Other animation types move the position along a predetermined curve.
Simply changing NumberAnimation to SmoothedAnimation makes your example look correct to me.

Resources