• QML动态标注线


    QML动态标注线

    1,目的

    有些情况对某个位置进行标注,但是背景过于复杂, 需要将标注点和标注内容进行分离,这时就需要用到标注线。我们即明确知道了标注的的信息也让界面更加均衡。
    效果图:

    图1

    图2

    2,设计分析

    如果单纯将标识点连线到标注区,这样在标注内容较多时是会给人杂乱不堪的感觉。这里我们先使用30度倾角拉出斜线,再使用水平画线延伸到目标点。后期在逻辑上控制斜线尽量不发生交叉,那么给人的感觉就较为整齐。
    基本原理:我们已知信息是起始点、结束点坐标,首先通过起始点向结束的点的水平面画倾角30度的斜线,与结束点水平面重叠时转为画水平线直至结束坐标。

    3,设计内容

    首先在主qml中创建tagLine.qml组件,添加组件属性和基本元素。代码如下:

    import QtQuick 2.0
    
    Item {
        id: tagLine
    
        property point startPoint: Qt.point(0, 0)
        property point endPoint: Qt.point(0, 0)
        property var lineColor: "70ffe42f"
        property var lineWidth: 1
    
        //斜线长度
        property var oblLineLength: 0
        //水平线长度
        property var horLineLength: 0
    
        Rectangle{
            id: oblLine
    
            antialiasing: true
            height: lineWidth
            color: lineColor
            transformOrigin: Item.TopLeft
        }
    
        Rectangle{
            id: horLine
    
            antialiasing: true
            height: lineWidth
            color: lineColor
            transformOrigin: Item.TopLeft
        }
    }

    从代码中可知 我们是使用rectangle作为线条进行绘制。现在基本元素已经齐全,下一步就是计算线条长度,和添加画线动画。
    我们先实现线条长度计算函数。
    首先我们需要了解界面的坐标系,水平方向右是x轴正向,垂直向下是y轴正向。

    图3

    在这个坐标系中,结束点可能会出现在起始点的如下4个区域中,我们先实现区域1中的计数,其他区域只需要在这个基础上稍微调整角度即可。

    图4

    下图5所示,我们最终需要的是a,c这两条线长。利用三角函数,已知b、f先算a=b/cos30°,d=b*tan30° 。下图是收藏的常用三角函数值表图6

    图5

    图6

    这里还有一种情况就是d大于f的情况,这时我们就不能使用30度斜边改用垂线。实现代码如下

    function drawCala() {
        //相对角度
        var angle= 0
    
        //实际角度值
        var realAngle = 0;
    
        var newOblLeng = 0;
        var newHorLeng = 0;
    
        var tmpx = Math.abs(startPoint.x - endPoint.x);
        var tmpy = Math.abs(startPoint.y - endPoint.y);
    
        //情况1 30°夹角
        if (tmpx >= Math.floor((Math.sqrt(3) / 3) * tmpy))
        {
            newOblLeng = Math.floor(tmpy / (Math.sqrt(3) / 2));
            newHorLeng = tmpx - Math.floor((Math.floor((Math.sqrt(3) / 3) * tmpy)));
            angle = 60;
        }
        //情况2 垂线和直线配合
        else
        {
            newOblLeng = tmpy;
            newHorLeng = tmpx;
            angle = 90;
        }
    
        oblLine.width = newOblLeng;
        horLine.width = newHorLeng;
    }

    到此我们已经计算出了这两根线的线长。还需要继续处理如下内容才算完成。
    1,计算出c/a交汇的位置坐标,作为水平线c的起始点;
    2,根据终点在起点的4个不同区域内,计算出线段a的倾角;
    3,根据终点在起点的4个不同区域内,计算出水平线c的延伸方向;
    4,添加动画,在a从起点开始延伸到达计算值后,水平线开始延伸,最终到达终点。
    这里就不多说了,直接看代码吧,效果如下

    图7

    最终实现的代码:
    tagLine.qml

    import QtQuick 2.0
    
    Item {
        property point startPoint: Qt.point(0, 0)
        property point endPoint: Qt.point(0, 0)
        property var lineColor: "#70ffe42f"
        property var lineWidth: 1
    
        //斜线长度
        property var oblLineLength: 0
        //水平线长度
        property var horLineLength: 0
    
        onStartPointChanged: {
            drawCala();
        }
        onEndPointChanged: {
            drawCala();
        }
    
        function drawCala() {
            //相对角度
            var angle= 0
    
            //实际角度值
            var realAngle = 0;
    
            var newOblLeng = 0;
            var newHorLeng = 0;
    
            var tmpx = Math.abs(startPoint.x - endPoint.x);
            var tmpy = Math.abs(startPoint.y - endPoint.y);
    
            //情况1 30°夹角
            if (tmpx >= Math.floor((Math.sqrt(3) / 3) * tmpy))
            {
                newOblLeng = Math.floor(tmpy / (Math.sqrt(3) / 2));
                newHorLeng = tmpx - Math.floor((Math.floor((Math.sqrt(3) / 3) * tmpy)));
                angle = 60;
            }
            //情况2 垂线和直线配合
            else
            {
                newOblLeng = tmpy;
                newHorLeng = tmpx;
                angle = 90;
            }
    
            //水平线的Y坐标 和结束点Y坐标相同
            horLine.y = endPoint.y;
    
            //结束的点在起始点的左上方
            if ((startPoint.x >= endPoint.x) && (startPoint.y >= endPoint.y))
            {
                realAngle = 180 + angle;
                horLine.x = endPoint.x + newHorLeng;
                horLine.rotation = 180;
            }
            //结束的点在起始点的右上方
            else if ((startPoint.x <= endPoint.x) && (startPoint.y >= endPoint.y))
            {
                realAngle = -angle;
                horLine.x = endPoint.x - newHorLeng;
                horLine.rotation = 0;
            }
            //结束的点在起始点的右下方
            else if ((startPoint.x <= endPoint.x) && (startPoint.y <= endPoint.y))
            {
                realAngle = angle;
                horLine.x = endPoint.x - newHorLeng;
                horLine.rotation = 0;
            }
            //结束的点在起始点的左下方
            else if ((startPoint.x >= endPoint.x) && (startPoint.y <= endPoint.y))
            {
                realAngle = 180 - angle;
                horLine.x = endPoint.x + newHorLeng;
                horLine.rotation = 180;
            }
    
            oblLine.x = startPoint.x;
            oblLine.y = startPoint.y;
            oblLine.rotation = realAngle
            oblLineLength = newOblLeng;
            horLineLength = newHorLeng;
    
            if (oblLineLength > 0)
            {
                oblAnimation.restart();
            }
            else
            {
                //当使用垂线时斜线长度清零
                oblLine.width = oblLineLength;
                //直接进行水平延伸
                horLine.visible = true;
                horAnimation.restart();
            }
        }
    
        Rectangle{
            id: oblLine
    
            antialiasing: true
            height: lineWidth
            color: lineColor
            transformOrigin: Item.TopLeft
        }
    
        Rectangle{
            id: horLine
    
            antialiasing: true
            height: lineWidth
            color: lineColor
            transformOrigin: Item.TopLeft
        }
    
        PropertyAnimation {
            id: oblAnimation
            target: oblLine
            property: "width"
            duration: 500
            from: 0
            to: oblLineLength
            onStopped: {
                if (horLineLength > 0)
                {
                    horLine.visible = true
                    horAnimation.restart()
                }
            }
            onStarted: {
                horLine.visible = false
            }
        }
    
        PropertyAnimation {
            id: horAnimation
            target: horLine
            property: "width"
            duration: 600
            from: 0
            to: horLineLength
        }
    }

    使用标注线main.qml

    import QtQuick 2.5
    import QtQuick.Window 2.2
    
    Window {
        visible: true
         480
        height: 240
    
        color: "#1f1f1f"
    
        TagLine {
            id: myTagLine
        }
    
        MouseArea {
            anchors.fill: parent
            onClicked: {
                myTagLine.startPoint = Qt.point(parent.width / 2, parent.height / 2)
                myTagLine.endPoint = Qt.point(50, 50)
            }
        }
    }

    4,总结

    利用Rectangle组件进行画线,然后再进行动画拼接,最终实现线条延伸效果,此组件比较适合应用在标识内容较多的场合。后续还可以配合标识框的组合动画让效果更佳。对以上代码稍作调整可实现如图1,2的效果。

    下来大家发现有什么问题或需要讨论交流,可以在简书、博客园、或邮箱将问题进行留言,我会及时回复和更新。
    邮箱: whqcxz@163.com
    原创:https://www.simbahiker.com/news/0220200524001.html

  • 相关阅读:
    ACM FPGA 2019 -- Reconfigurable Convolutional Kernels for Neural Networks on FPGAs 论文解读
    VLSI基础-- 第六章 时序逻辑电路
    ISSCC-2020:GANPU 论文解读
    fabric知识梳理图解
    在浏览器端获取文件的MD5值
    mysql实现随机获取几条数据的方法
    数据仓库之Data Vault模型总结
    大数据分析基础——维度模型
    ArrayList类源码解析——ArrayList动态数组的实现细节(基于JDK8)
    Java的四个标记接口:Serializable、Cloneable、RandomAccess和Remote接口
  • 原文地址:https://www.cnblogs.com/hiker-blogs/p/12953043.html
Copyright © 2020-2023  润新知