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

QtCharts中如何动态填充CandlestickSeries数据?Repeater及JS方法失效问题解决

解决QML中CandlestickSeries动态填充数据的问题

你遇到的问题其实很常见:Repeater不能直接作为CandlestickSeries的子项,因为Repeater的父组件必须是Item或其派生类(比如Rectangle、Column等),而CandlestickSeries属于AbstractSeries,不在Item的视觉层级里,所以Repeater生成的CandlestickSet不会被自动添加到Series中。

下面给你两种可行的解决方案,分别适用于纯QML场景和从C++自定义类获取数据的场景:


方案一:纯QML动态生成数据

我们可以在Component.onCompleted信号里,通过JavaScript循环创建CandlestickSet,并手动添加到CandlestickSeries中:

ChartView { 
    title: "Candlestick Series" 
    width: 400 
    height: 300 
    CandlestickSeries { 
        id: candleSeries
        name: "Acme Ltd." 
        increasingColor: "green" 
        decreasingColor: "red" 

        Component.onCompleted: {
            // 模拟100条数据
            for(let i=0; i<100; i++){
                let set = CandlestickSet {
                    timestamp: 1000 * 60 * i + 1436313600000 
                    open: 400 + Math.random()*50; 
                    high: 450 + Math.random()*50; 
                    low: 350 + Math.random()*50; 
                    close: 380 + Math.random()*50;
                }
                candleSeries.append(set); // 手动添加到series
            }
        }
    } 
}

这种方法简单直接,适合快速测试或纯QML内的数据生成。


方案二:从C++自定义类获取数据(推荐)

如果你的数据来自C++自定义类,最佳实践是实现一个QAbstractListModel的子类,将数据封装成模型,然后在QML中遍历模型来创建CandlestickSet。

步骤1:C++端实现数据模型

首先定义一个数据类(比如CandleData),然后实现模型类(比如CandleModel):

#include <QAbstractListModel>
#include <QDateTime>

// 单条蜡烛数据
struct CandleData {
    qint64 timestamp;
    qreal open;
    qreal high;
    qreal low;
    qreal close;
};

class CandleModel : public QAbstractListModel
{
    Q_OBJECT
public:
    enum CandleRoles {
        TimestampRole = Qt::UserRole + 1,
        OpenRole,
        HighRole,
        LowRole,
        CloseRole
    };

    explicit CandleModel(QObject *parent = nullptr) : QAbstractListModel(parent) {}

    // 重写模型的必要方法
    int rowCount(const QModelIndex &parent = QModelIndex()) const override {
        Q_UNUSED(parent);
        return m_data.size();
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
        if (!index.isValid() || index.row() >= m_data.size())
            return QVariant();

        const CandleData &candle = m_data[index.row()];
        switch(role){
        case TimestampRole: return candle.timestamp;
        case OpenRole: return candle.open;
        case HighRole: return candle.high;
        case LowRole: return candle.low;
        case CloseRole: return candle.close;
        default: return QVariant();
        }
    }

    // 暴露给QML的方法,用于添加数据
    Q_INVOKABLE void addCandle(qint64 timestamp, qreal open, qreal high, qreal low, qreal close){
        beginInsertRows(QModelIndex(), m_data.size(), m_data.size());
        m_data.append({timestamp, open, high, low, close});
        endInsertRows();
    }

protected:
    QHash<int, QByteArray> roleNames() const override {
        QHash<int, QByteArray> roles;
        roles[TimestampRole] = "timestamp";
        roles[OpenRole] = "open";
        roles[HighRole] = "high";
        roles[LowRole] = "low";
        roles[CloseRole] = "close";
        return roles;
    }

private:
    QList<CandleData> m_data;
};

别忘了在main.cpp中注册这个模型到QML:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "candlemodel.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<CandleModel>("com.example", 1, 0, "CandleModel");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

步骤2:QML端使用模型填充数据

在QML中,我们可以监听模型的rowsInserted信号,动态创建CandlestickSet并添加到Series:

import QtQuick 2.15
import QtCharts 2.15
import com.example 1.0

ChartView { 
    title: "Candlestick Series" 
    width: 400 
    height: 300 

    CandleModel {
        id: candleModel
        // 可以在这里初始化测试数据,或者从C++端传入
        Component.onCompleted: {
            for(let i=0; i<100; i++){
                addCandle(1000 * 60 * i + 1436313600000, 
                          400+Math.random()*50, 
                          450+Math.random()*50, 
                          350+Math.random()*50, 
                          380+Math.random()*50);
            }
        }
    }

    CandlestickSeries { 
        id: candleSeries
        name: "Acme Ltd." 
        increasingColor: "green" 
        decreasingColor: "red" 

        // 监听模型数据变化,动态添加蜡烛
        Connections {
            target: candleModel
            function onRowsInserted(parent, start, end){
                for(let i=start; i<=end; i++){
                    let data = candleModel.get(i);
                    let set = CandlestickSet {
                        timestamp: data.timestamp
                        open: data.open
                        high: data.high
                        low: data.low
                        close: data.close
                    }
                    candleSeries.append(set);
                }
            }
        }
    } 
}

这种方式的优势在于:

  • 符合Qt的Model-View架构,数据和UI分离
  • 支持动态更新数据(比如实时行情)
  • 可以方便地从C++自定义类中获取数据(比如从数据库、网络请求加载)

另外,如果你尝试过JS方法没成功,大概率是没有手动调用append()方法将CandlestickSet添加到Series中——直接创建对象不会自动关联到Series,必须显式调用append()或者insert()方法。

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

火山引擎 最新活动