经验大分享:QML动态标注线

简介: 经验大分享: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=btan30° 。下图是收藏的常用三角函数值表图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.y))

{

realAngle = -angle;

horLine.x = endPoint.x - newHorLeng;

horLine.rotation = 0;

}

//结束的点在起始点的右下方

else if ((startPoint.x <= endPoint.x) (startPoint.y = endPoint.x) (startPoint.y 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

}//代码效果参考:http://www.ezhiqi.com/zx/art_7400.html

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

width: 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

原创:

相关文章
|
前端开发 JavaScript C++
打造卓越 QML 层级设计:从入门到精通(一)
打造卓越 QML 层级设计:从入门到精通
3516 1
|
设计模式 编解码 前端开发
打造卓越 QML 层级设计:从入门到精通(三)
打造卓越 QML 层级设计:从入门到精通(三)
1742 0
|
缓存 Ubuntu JavaScript
踩坑记录:QML加载图片资源
踩坑记录:QML加载图片资源
2008 0
|
7月前
|
网络协议 数据安全/隐私保护 网络架构
|
关系型数据库 MySQL 测试技术
MySQL性能测试(完整版)
MySQL性能测试(完整版)
1613 1
|
算法 C++ 开发者
【QML文件结构】理解QML中 多层嵌套控件之间的关系
【QML文件结构】理解QML中 多层嵌套控件之间的关系
1088 2
QML 界面切换的方法
QML 界面切换的方法
794 1
Qt 目录操作(QDir 类)及展示系统文件实战 & QFilelnfo 类介绍和获取文件属性项目实战
Qt 目录操作(QDir 类)及展示系统文件实战 & QFilelnfo 类介绍和获取文件属性项目实战
Qt 目录操作(QDir 类)及展示系统文件实战 & QFilelnfo 类介绍和获取文件属性项目实战
|
运维 Kubernetes 负载均衡
# 阿里云ACK产品评测
阿里云 ACK (Alibaba Cloud Container Service for Kubernetes) 是一站式容器管理服务,简化容器应用部署、管理及运维。具备友好Web界面与CLI工具;无缝集成阿里云RDS、SLB、OSS等服务;提供RBAC、网络策略及镜像安全扫描等功能确保安全;基于阿里云基础设施,支持自动伸缩与负载均衡保证高性能。通过部署WordPress案例演示具体流程,包括集群创建、kubectl配置及WordPress+MySQL部署。ACK适合各类用户,高效便捷。注意:官方镜像可能拉取失败,建议使用阿里云ECS拉取或上传至容器镜像服务。
382 3
|
监控 Linux 数据库连接
手把手教你从本地到云端:全面解析Blazor应用的部署流程与最佳实践,助你轻松掌握发布Blazor WebAssembly应用到Azure的每一个细节
【8月更文挑战第31天】本文详细介绍了将 Blazor 应用从本地部署到 Azure 的全过程。首先确保已在 Visual Studio 中创建 Blazor WebAssembly 应用,接着清理项目并配置发布选项。然后在 Azure 中创建 App Service 并完成应用部署。最后,配置环境变量、SSL 和监控,确保应用稳定运行。附带示例代码,展示如何加载和使用 Azure 环境变量。通过最佳实践指导,帮助你顺利完成 Blazor 应用的云端部署。
523 0