You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

QML StackedBarSeries如何将数据列日期设为X轴标签?

解决QML ChartView中StackedBarSeries显示日期X轴的问题

我完全懂你遇到的麻烦——默认的VBarModelMapper会把模型索引当成X轴标签,完全没法体现你需要的日期维度。要把QDateTime转换成DateTimeAxis能识别的X轴标签,核心是把日期转成时间戳数值,让图表能正确解析并渲染成日期格式。下面分两种方案给你详细说明:

方案一:修改模型/查询,添加时间戳列(推荐用VBarModelMapper原生支持)

这个方案利用VBarModelMapperxColumn属性,直接绑定存储时间戳的列,不用手动处理BarSet

1. 调整SQL查询或自定义模型

如果你的SQL查询可以修改,直接把日期转成毫秒级时间戳作为额外列:

SELECT date, sent, recv, strftime('%s', date) * 1000 AS timestamp FROM your_table;

(这里strftime('%s', date)获取秒级时间戳,乘1000转成毫秒,适配Qt的DateTimeAxis

如果不想改SQL,就自定义一个QSqlQueryModel子类,添加时间戳角色:

#include <QSqlQueryModel>
#include <QDateTime>

class DateSqlModel : public QSqlQueryModel
{
    Q_OBJECT
public:
    enum CustomRoles {
        TimestampRole = Qt::UserRole + 1
    };

    explicit DateSqlModel(QObject* parent = nullptr) : QSqlQueryModel(parent) {}

    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override {
        if (role == TimestampRole && index.column() == 0) {
            QDateTime date = QSqlQueryModel::data(index, Qt::DisplayRole).toDateTime();
            return date.toMSecsSinceEpoch(); // 返回毫秒时间戳
        }
        return QSqlQueryModel::data(index, role);
    }

    QHash<int, QByteArray> roleNames() const override {
        auto roles = QSqlQueryModel::roleNames();
        roles[TimestampRole] = "timestamp";
        return roles;
    }
};

记得在main.cpp里把这个模型注册到QML,或者用setContextProperty暴露给QML环境。

2. QML中配置ChartView

现在可以直接用VBarModelMapper绑定时间戳列,同时把AxisX设为DateTimeAxis

import QtQuick 2.15
import QtCharts 2.15

ChartView {
    width: 800
    height: 600
    title: "Sent/Received Data by Date"

    // 配置日期X轴
    DateTimeAxis {
        id: dateAxis
        format: "yyyy-MM-dd" // 自定义日期显示格式,比如"MM-dd"或"yyyy-MM-dd HH:mm"
        tickCount: 6
        labelsAngle: 45 // 旋转标签避免重叠
        gridVisible: true
    }

    // 数值Y轴
    ValueAxis {
        id: valueAxis
        titleText: "Data Amount"
        min: 0
    }

    StackedBarSeries {
        axisX: dateAxis
        axisY: valueAxis

        VBarModelMapper {
            model: dateSqlModel // 你的自定义模型或带时间戳列的SQL模型
            firstBarSetColumn: 1 // 对应sent列的索引
            lastBarSetColumn: 2 // 对应recv列的索引
            xColumn: 3 // 如果是SQL查询加的timestamp列,这里填列索引
        }
    }
}

方案二:手动创建BarSet,绑定时间戳角色

如果不想修改模型或SQL,可以手动遍历模型数据,给每个BarSet的点设置时间戳X值:

import QtQuick 2.15
import QtCharts 2.15

ChartView {
    width: 800
    height: 600
    title: "Sent/Received Data by Date"

    DateTimeAxis {
        id: dateAxis
        format: "yyyy-MM-dd"
        labelsAngle: 45
    }

    ValueAxis {
        id: valueAxis
        titleText: "Data Amount"
        min: 0
    }

    StackedBarSeries {
        axisX: dateAxis
        axisY: valueAxis

        BarSet { id: sentSet; label: "Sent" }
        BarSet { id: recvSet; label: "Received" }

        Component.onCompleted: {
            const rowCount = dateSqlModel.rowCount();
            for (let i = 0; i < rowCount; i++) {
                // 获取时间戳和数值
                const timeStamp = dateSqlModel.data(dateSqlModel.index(i, 0), DateSqlModel.TimestampRole);
                const sentVal = dateSqlModel.data(dateSqlModel.index(i, 1), Qt.DisplayRole);
                const recvVal = dateSqlModel.data(dateSqlModel.index(i, 2), Qt.DisplayRole);
                // 添加到BarSet,第一个参数是X值(时间戳),第二个是Y值
                sentSet.append(timeStamp, sentVal);
                recvSet.append(timeStamp, recvVal);
            }
        }
    }
}

常见坑点提醒

  • DateTimeAxis只认数值:必须把QDateTime转成毫秒/秒级时间戳,直接传QDateTime对象会失效。
  • 标签重叠处理:用labelsAngle旋转标签,或者调整tickCount减少显示的标签数量。
  • 时间戳单位统一:如果用秒级时间戳,要在DateTimeAxis里设置tickInterval适配,比如tickInterval: 86400000(一天的毫秒数)。

内容的提问来源于stack exchange,提问作者strnmn

火山引擎 最新活动