qml用基础控件自定义柱状图

本文描述了作者如何使用自定义方式在Qt应用中创建柱状图,以处理图例数量变化、标签数量变化及值为0时的隐藏功能。通过repeater实现重复项,重点在于计算柱子位置和整体布局的调整。
摘要由CSDN通过智能技术生成

本想用qtchart来做,但是用了一下发现限制太多不太满足需求,所以使用自定义的方式实现,支持图例数量变化,标签数量变化,值为0时不显示
在这里插入图片描述
内容过长可滑动查看
在这里插入图片描述
用的都是基础控件,思路是把一个标签中的每个柱子视为重复项,用repeater构建,把柱状图中每个标签的所有内容(柱子)整体视为一个重复项,用repeater构建.
主要难点在计算位置上,对柱子xy值的计算,标签位置居中的计算.以及整个内容所占的宽度,具体解释在代码注释中.
注意约束,vDataModel中data里的元素的数量要和vLegendModel的元素数量相同:

import QtQuick 2.9
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
Rectangle{
    property var vDataModel: [
        {"text":"公交", "data":[20, 6, 0, 4]},
        {"text":"地铁", "data":[5, 6, 1, 4]},
        {"text":"飞机", "data":[5, 6, 1, 4]},
        {"text":"高铁", "data":[5, 6, 1, 4]},
        {"text":"出租", "data":[5, 6, 1, 4]},
        {"text":"火箭", "data":[5, 6, 1, 4]},
        {"text":"飞船", "data":[5, 6, 1, 4]},
        {"text":"其它", "data":[5, 6, 1, 4]}
    ]
    property var vLegendModel: [
        {"text":"首次出行选择", "color":"#ff8040"},
        {"text":"第二次出行选择", "color":"#008000"},
        {"text":"第三次出行选择", "color":"#0080ff"},
        {"text":"未选择", "color":"#ff0000"}
    ]
    width: parent.width
    height: 480 - 45 - 40 + 10
    color: "transparent"
    Rectangle{
        id:verticalLine
        anchors.left: parent.left
        anchors.leftMargin: 20
        anchors.top: parent.top
        anchors.topMargin: 20
        width: 1
        height: 330
        color: "black"
    }
    Rectangle{
        id:horizontalLine
        anchors.left: verticalLine.right
        anchors.top: verticalLine.bottom
        width: parent.width - legnedRect.width - 10 - 40
        height: 1
        color: "black"
    }
    ScrollView{//标签 柱状图中有很多标签, 一个标签(30 * 柱子数 - 10) 标签之间70, 因此内容宽度 = 标签数 * (30 * 柱子数 + 60) - 70
        anchors.left: verticalLine.right
        anchors.leftMargin: 20
        anchors.top: verticalLine.top
        width: horizontalLine.width - 20
        height: verticalLine.height + 36
        contentWidth: vDataModel.length * (30 * vDataModel[0].data.length + 60) - 70
        contentHeight: height
        clip: true
        Row{
            spacing: 70
            Repeater{
                model:vDataModel
                //柱子 一个标签中有很多柱子, 一个柱子20 柱子之间10间隙, 因此宽度 = 30 * 柱子数 - 10
                Rectangle{
                    width: 30 * vDataModel[index].data.length - 10
                    height: verticalLine.height
                    x: index * (width + 70)//初始x:0 index:0, 每加一个标签右移width + 70
                    y: 0
                    color: "transparent"
                    Row{
                        anchors.fill: parent
                        spacing: 10
                        Repeater{
                            model: vDataModel[index].data
                            delegate: Rectangle{
                                x: index * (width + 10)
                                y: verticalLine.height - height
                                width: 20
                                height: modelData * 15
                                color: vLegendModel[index].color
                                visible: modelData != 0
                                Text{
                                    anchors.bottom: parent.top
                                    anchors.bottomMargin: 5
                                    anchors.horizontalCenter: parent.horizontalCenter
                                    verticalAlignment: Text.AlignVCenter
                                    font.pixelSize: 15
                                    font.family: "Droid Sans Fallback"
                                    text: String(modelData)
                                }
                            }
                        }
                    }
                    Text{
                        x: (30 * vDataModel[index].data.length - 10 - width) / 2
                        y: verticalLine.height + 1 + 5
                        verticalAlignment: Text.AlignVCenter
                        horizontalAlignment: Text.AlignHCenter
                        font.pixelSize: 15
                        font.family: "Droid Sans Fallback"
                        text: vDataModel[index].text
                    }
                }
            }
        }
    }

    //图例, 自动排版
    Rectangle{
        id:legnedRect
        width: 130
        height: legnedRepeater.count * 25
        anchors.right: parent.right
        anchors.rightMargin: 10
        anchors.verticalCenter: parent.verticalCenter
        color: "transparent"
        Column{
            anchors.fill: parent
            spacing: 5
            Repeater{
                id:legnedRepeater
                model: vLegendModel
                Rectangle{
                    width: 130
                    height: 20
                    color: "transparent"
                    Rectangle{
                        id:rect
                        anchors.left: parent.left
                        anchors.leftMargin: 10
                        width: 10
                        height: 10
                        color: modelData.color
                        anchors.verticalCenter: parent.verticalCenter
                    }
                    Text {
                        anchors.left: rect.right
                        anchors.leftMargin: 10
                        anchors.verticalCenter: parent.verticalCenter
                        verticalAlignment: Text.AlignVCenter
                        font.pixelSize: 13
                        font.family: "Droid Sans Fallback"
                        text: modelData.text
                    }
                }
            }
        }
    }
}

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值