QML:拖动曲线坐标点修改曲线

        通过移动坐标点上的滑块实现修改折线的坐标点的值。具体效果如下:

大体分为两点:1、实现可移动的滑块,并获取实时x,y坐标。

                        2、根据滑块的x,y坐标转换为折线图上的坐标点并实时更新折线。

一、可移动滑块的实现

完整代码:

import QtQuick 2.0

Item {
    property real mouseXTMP: 0   //鼠标坐标临时值
    property real mouseYTMP: 0

    property string backgroundDefaultImage: imageSource("heat_curve_point_unselected")  //滑块选中和未选状态图片
    property string backgroundActiveImage: imageSource("heat_curve_point_selected")
    property bool clickedFlag: false    //滑块的状态标志
    property bool editEnable: false   //可编辑标志
    onEditEnableChanged: {
        if(!editEnable)
            clickedFlag = false
    }

    property string movingDirection: "Arbitrary"   //Horizontal  Vertical   Arbitrary
    property int y_Max: 371
    property int y_Min: 33
    property int x_Max: 800
    property int x_Min: 33
    property int curVal: 35

    signal mousePosition(int x_pos,int y_pos)
    signal btnClicked()

    id: rect
    width: 70
    height: 80
    Rectangle{
        id:btn_temp_rect
        width: 52
        height: 28
        color: "#161821"
        radius:4
        visible: !clickedFlag
        anchors.horizontalCenter: parent.horizontalCenter
        Text{
            id:btn_temp_text
            anchors.fill: parent
            text: curVal + "\u00B0C"
            color: "#FFFFFF"
            font.pixelSize: 16
            opacity: 0.6
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignTop
        }
    }
    Item{
        width: 70
        height: 70
        anchors.bottom: parent.bottom
        Image {
            id:activeImage
            width: 70
            height: 70
            anchors.fill:parent
            visible: {
                if(backgroundActiveImage === backgroundDefaultImage)
                    return false
                else
                    return clickedFlag
            }
            source:backgroundActiveImage
        }
        Image {
            id:defaultImage
            width: 30
            height: 30
            anchors.centerIn: parent
            visible:{
                if(backgroundActiveImage === backgroundDefaultImage)
                    return true
                else
                    return !clickedFlag
            }
            source:backgroundDefaultImage
        }
    }
    MouseArea {
        anchors.fill: parent
        onPressed: {
            if(editEnable){
//                if(!clickedFlag)
//                    clickedFlag = !clickedFlag  //切换状态标志,取消选中由外面操作,当其他滑块被选中才取消选中状态
                mouseXTMP = mouseX
                mouseYTMP = mouseY
                rect.btnClicked()
            }
        }
        onPositionChanged: {
            if(editEnable){
                var tmpX = mouseX + rect.x - mouseXTMP  //计算移动后的坐标
                var tmpY = mouseY + rect.y - mouseYTMP
                if(tmpX<=x_Min - rect.width/2)
                    tmpX = x_Min - rect.width/2
                if(tmpX>=x_Max - rect.width/2)
                    tmpX = x_Max - rect.width/2
                if(tmpY<=y_Min - rect.width/2 -10)
                    tmpY = y_Min - rect.width/2 -10
                if(tmpY>=y_Max - rect.width/2 -10)
                    tmpY = y_Max - rect.width/2 -10
                if(movingDirection == "Arbitrary"){
                    rect.x = tmpX
                    rect.y = tmpY
                }
                else if(movingDirection == "Horizontal")
                     rect.x = tmpX
                else if(movingDirection == "Vertical")
                    rect.y = tmpY
                mousePosition(rect.x + rect.width/2,rect.y + rect.width/2 + 10)
                console.log(rect.x + rect.width/2,rect.y + rect.width/2 + 10)  //圆形中心位置
            }
        }
    }
}

        这部分的核心在鼠标事件上,点击的时候记录鼠标的x、y坐标mouseXTMP,mouseYTMP,鼠标移动后新的坐标x,y减去开始时的mouseXTMP,mouseYTMP就等于移动距离,将这个移动距离加到滑块的x,y即可实现移动,最后通过信号发送坐标。

        二、折线

部分代码:

//曲线
import QtQuick 2.12
import QtCharts 2.3
import "../../../Common"
import "../../"
import "../OverviewOfSystemParameters"
import "../../SettingPopup"

Rectangle{
    property string titleText1: "Please drag the control point to adjust"    //曲线图标题文本
    property string titleText2: "the ambient temp Te and corresponding water temp Tw"
    property string legendText1: "Tw-Low-temp water temp"
    property string legendText2: "Te-Ambient temp"
    property bool editEnable: false
    property string curBtn: ""  //当前被点击的btn
    property int twMax: 40  //制热设定温度  环温最值
    property int twMin: 20
    property int teMax: 25
    property int teMin: -25
    property var defaultValue: [[-25,40],[-15,37],[-5,33],[5,20],[10,20]]
    onDefaultValueChanged: {
        init(1)
    }
    property var curValue: [[-25,40],[-15,37],[-5,33],[5,29],[10,25]]
    signal curveValue(var curValue)
    signal backBtnClicked()

    id:root
    width: 906
    height: 600
    color: "#05060A"   

    ChartView {      //绘制曲线图
        id: chartView
        width: 833
        height: 404
        z:0
//        plotArea: Qt.rect(33, 33, 800, 371)
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 36
        anchors.left: parent.left
        anchors.leftMargin: 46
        antialiasing: true    //抗锯齿
        backgroundColor: "#05060A"
//        backgroundColor: "red"
        legend.visible: false

        ValueAxis {   //横轴
            id: xAxis
            min: teMin
            max: teMax
            tickCount: 7
            visible: false
            gridVisible: false
//            labelFormat: "%.0f h"
//            labelsColor: "#9B9B9D"
        }
        ValueAxis {   //纵轴
            id: yAxis
            min: twMin
            max: twMax
            tickCount: 6
            visible: false
            gridVisible: false
//            labelFormat: "%.0f&deg;C"
//            labelsColor: "#9B9B9D"
        }
        LineSeries  {
            id: lineSeries
            name: "series1"
            axisX: xAxis
            axisY: yAxis
            color: "#E98017"
            width: 3
            XYPoint { x: defaultValue[0][0]; y: defaultValue[0][1] }
            XYPoint { x: defaultValue[1][0]; y: defaultValue[1][1] }
            XYPoint { x: defaultValue[2][0]; y: defaultValue[2][1] }
            XYPoint { x: defaultValue[3][0]; y: defaultValue[3][1] }
            XYPoint { x: defaultValue[4][0]; y: defaultValue[4][1] }

            function updatePoint(index, x, y) {
                var chartPos = chartView.mapToValue(Qt.point(x, y), lineSeries);
                this.replace(index, chartPos.x, chartPos.y);
                curValue[index][0] = Math.round(chartPos.x)
                curValue[index][1] = Math.round(chartPos.y)
                curTw.text = Math.round(chartPos.y) + "\u00B0C"
                switch (index){
                case 0:
                    curTe1.text = Math.round(chartPos.x)  + "\u00B0C"
                    btn1.curVal= Math.round(chartPos.y)
                    break
                case 1:
                    curTe2.text = Math.round(chartPos.x)  + "\u00B0C"
                    btn2.curVal= Math.round(chartPos.y)
                    break
                case 2:
                    curTe3.text = Math.round(chartPos.x)  + "\u00B0C"
                    btn3.curVal= Math.round(chartPos.y)
                    break
                case 3:
                    curTe4.text = Math.round(chartPos.x)  + "\u00B0C"
                    btn4.curVal= Math.round(chartPos.y)
                    break
                case 4:
                    curTe5.text = Math.round(chartPos.x)  + "\u00B0C"
                    btn5.curVal= Math.round(chartPos.y)
                    break
                }
                console.log( "val:",chartPos.x, chartPos.y)
            }
        }
        CustomRemoveableBtn{
            id:btn1
            x:100
            y:100
            z:1
            x_Max: btn2.x + btn2.width/2
            editEnable: root.editEnable
            onMousePosition: {
                console.log("x_pos:",x_pos,"y_pos:",y_pos)
                console.log("x:",btn1.x,"y:",btn1.y)
                lineSeries.updatePoint(0, x_pos, y_pos);
            }
            onBtnClicked: {
                clickedFlag = true
                btn2.clickedFlag = false
                btn3.clickedFlag = false
                btn4.clickedFlag = false
                btn5.clickedFlag = false
                curBtn = "btn1"
                curTw.text = curValue[0][1] + "\u00B0C"
            }
        }

        CustomRemoveableBtn{
            id:btn2
            x:100
            y:100
            z:1
            x_Min:btn1.x + btn1.width/2
            x_Max:btn3.x + btn3.width/2
            editEnable: root.editEnable
            onMousePosition: {
                console.log("x:",x,"y:",y)
                lineSeries.updatePoint(1, x_pos, y_pos);
            }
            onBtnClicked: {
                clickedFlag = true
                btn1.clickedFlag = false
                btn3.clickedFlag = false
                btn4.clickedFlag = false
                btn5.clickedFlag = false
                curBtn = "btn2"
                curTw.text = curValue[1][1] + "\u00B0C"
            }
        }

        CustomRemoveableBtn{
            id:btn3
            x:100
            y:100
            z:1
            x_Min:btn2.x + btn2.width/2
            x_Max:btn4.x + btn4.width/2
            editEnable: root.editEnable
            onMousePosition: {
                console.log("x:",x,"y:",y)
                lineSeries.updatePoint(2, x_pos, y_pos);
            }
            onBtnClicked: {
                clickedFlag = true
                btn1.clickedFlag = false
                btn2.clickedFlag = false
                btn4.clickedFlag = false
                btn5.clickedFlag = false
                curBtn = "btn3"
                curTw.text = curValue[2][1] + "\u00B0C"
            }
        }

        CustomRemoveableBtn{
            id:btn4
            x:100
            y:100
            z:1
            x_Min:btn3.x + btn4.width/2
            x_Max:btn5.x + btn5.width/2
            editEnable: root.editEnable
            onMousePosition: {
                console.log("x:",x,"y:",y)
                lineSeries.updatePoint(3, x_pos, y_pos);
            }
            onBtnClicked: {
                clickedFlag = true
                btn1.clickedFlag = false
                btn2.clickedFlag = false
                btn3.clickedFlag = false
                btn5.clickedFlag = false
                curBtn = "btn4"
                curTw.text = curValue[3][1] + "\u00B0C"
            }
        }

        CustomRemoveableBtn{
            id:btn5
            x:100
            y:100
            z:1
            x_Min:btn4.x + btn4.width/2
            editEnable: root.editEnable
            onMousePosition: {
                console.log("x:",x,"y:",y)
                lineSeries.updatePoint(4, x_pos, y_pos);
            }
            onBtnClicked: {
                clickedFlag = true
                btn1.clickedFlag = false
                btn2.clickedFlag = false
                btn3.clickedFlag = false
                btn4.clickedFlag = false
//                dottedLine6.visible = true
//                dottedLine6.y = btn5.y + btn5.width/2 + 10
//                dottedLine6.width = btn5.x
                curBtn = "btn5"
                curTw.text = curValue[4][1] + "\u00B0C"
            }
        }
        Component.onCompleted: {
            init()
        }

        DottedLine{     //虚线
            id:dottedLine1
            x: btn1.x+btn1.width/2
            y: btn1.y+btn1.height/2+10
            height: 371-y
            lineColor: btn1.clickedFlag ? "#E98017" : "#FFFFFF"
            opacity: btn1.clickedFlag ? 1 : 0.2
        }
        DottedLine{     //虚线
            id:dottedLine2
            x: btn2.x+btn2.width/2
            y: btn2.y+btn2.height/2+10
            height: 371-y
            lineColor: btn2.clickedFlag ? "#E98017" : "#FFFFFF"
            opacity: btn2.clickedFlag ? 1 : 0.2
        }
        DottedLine{     //虚线
            id:dottedLine3
            x: btn3.x+btn3.width/2
            y: btn3.y+btn3.height/2+10
            height: 371-y
            lineColor: btn3.clickedFlag ? "#E98017" : "#FFFFFF"
            opacity: btn3.clickedFlag ? 1 : 0.2
        }
        DottedLine{     //虚线
            id:dottedLine4
            x: btn4.x+btn4.width/2
            y: btn4.y+btn4.height/2+10
            height: 371-y
            lineColor: btn4.clickedFlag ? "#E98017" : "#FFFFFF"
            opacity: btn4.clickedFlag ? 1 : 0.2
        }
        DottedLine{     //虚线
            id:dottedLine5
            x: btn5.x+btn5.width/2
            y: btn5.y+btn5.height/2+10
            height: 371-y
            lineColor: btn5.clickedFlag ? "#E98017" : "#FFFFFF"
            opacity: btn5.clickedFlag ? 1 : 0.2
        }
        DottedLine{     //横轴虚线
            id:dottedLine6
            x: 33
            y: {
                switch (curBtn){
                case "btn1":
                    return btn1.y + btn1.width/2 + 10
                case "btn2":
                    return btn2.y + btn2.width/2 + 10
                case "btn3":
                    return btn3.y + btn3.width/2 + 10
                case "btn4":
                    return btn4.y + btn4.width/2 + 10
                case "btn5":
                    return btn5.y + btn5.width/2 + 10
                default:break
                }
            }
            width: {
                switch (curBtn){
                case "btn1":
                    return btn1.x
                case "btn2":
                    return btn2.x
                case "btn3":
                    return btn3.x
                case "btn4":
                    return btn4.x
                case "btn5":
                    return btn5.x
                default:break
                }
            }
            height: 2
            visible: false
            lineDirection: "horizontal"
            lineColor: "#E98017"
        }
        Text {
            text: "Te/℃"
            color: "#FFFFFF"
            font.pixelSize: 16
            opacity: 0.6
            anchors.right: parent.right
            anchors.rightMargin: 8
            anchors.bottom: parent.bottom
            anchors.bottomMargin: 40
        }
    }
    function init(val=0){
        for(var i=0;i<5;i++)
        {
//                var screenPos = chartView.mapToPosition(Qt.point(defaultValue[i][0], defaultValue[i][1]), splineSeries);
            var X_tmp = ((defaultValue[i][0] - teMin)/(teMax-teMin)) * 757
            var Y_tmp = (1-((defaultValue[i][1] - twMin)/(twMax-twMin))) * 338 -10
            if(val)
                lineSeries.replace(lineSeries.at(i).x,lineSeries.at(i).y,defaultValue[i][0],defaultValue[i][1])
            curValue[i][0] = defaultValue[i][0]
            curValue[i][1] = defaultValue[i][1]
            switch(i){
            case 0:
                btn1.x = X_tmp
                btn1.y = Y_tmp
                curTe1.text = defaultValue[i][0]  + "\u00B0C"
                btn1.curVal= defaultValue[i][1]
                console.log("-----btn1,x,y-----")
                console.log(btn1.x,btn1.y)
                break;
            case 1:
                btn2.x = X_tmp
                btn2.y = Y_tmp
                curTe2.text = defaultValue[i][0]  + "\u00B0C"
                btn2.curVal= defaultValue[i][1]
                console.log("-----btn2,x,y-----")
                console.log(btn2.x,btn2.y)
                break;
            case 2:
                btn3.x = X_tmp
                btn3.y = Y_tmp
                curTe3.text = defaultValue[i][0]  + "\u00B0C"
                btn3.curVal= defaultValue[i][1]
                console.log("-----btn3,x,y-----")
                console.log(btn3.x,btn3.y)
                break;
            case 3:
                btn4.x = X_tmp
                btn4.y = Y_tmp
                curTe4.text = defaultValue[i][0]  + "\u00B0C"
                btn4.curVal= defaultValue[i][1]
                console.log("-----btn4,x,y-----")
                console.log(btn4.x,btn4.y)
                break;
            case 4:
                btn5.x = X_tmp
                btn5.y = Y_tmp
                curTe5.text = defaultValue[i][0]  + "\u00B0C"
                btn5.curVal= defaultValue[i][1]
                console.log("-----btn5,x,y-----")
                console.log(btn5.x,btn5.y)
                break;
            default:
                break;
            }
//                console.log("----------")
//                console.log(((defaultValue[i][0] - teMin)/(teMax-teMin)))
        }
    }
}

       1、qml中图形的绘制都是用ChartView,然后根据需求选择LineSeries(折线)、SplineSeries(曲线)。ChartView犹如一张画布,可以在上面绘制不同的图形。

     2.1 ChartView中的两种坐标

        ChartView上有两种坐标,第一种是原点固定在ChartView左上方的位置坐标,与我们平时给控件设置的x,y位置属性相同。第二种是因为我们图形中设置横轴纵轴产生的新的坐标系,在最开始的效果图中,横坐标从左向右-25到25,纵轴从下到上是20到40,这就是我们绘制图形中新的坐标系。

     2.2 坐标转换

        在第一部分移动滑块中信号发送出来的坐标是第一种,想要将这个坐标用于曲线或者折线的坐标点,需要转换为第二种坐标。

        ChartView里面有mapToPosition()、mapToValue()两个方法,第一个函数用于将第二种坐标转换为第一种坐标,第二个函数用于将第一种坐标转换为第二种坐标。我们可以在折线下创建一个更新函数updatePoint()。该函数将坐标进行转换,并且使用replace()函数更换对应的坐标点以达到实时移动折线的效果。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

优雅人字拖

老板大气

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值