Search code examples
c++qtqmlqtcharts

QML Chart using QAbstractTableModel doesn't dynamically update


I have a QAbtractTableModel that is accessible to a QML file with chart and series and XYModelMapper. When trying to update the model, nothing shows up on the chart. I've tried different methods(even trying QStandardItemModel before) and I can't seem to get any charts to update once it's finished loading. Is there something I'm doing wrong using either the model or model mapper? I've included simplified version of the files here.

class MyModel : public QAbstractTableModel
{
    Q_OBJECT

public:

    QVariant data(const QModelIndex& index, int role) const override;

    int columnCount(const QModelIndex& parent) const override;

    int rowCount(const QModelIndex& parent) const override;

    QVariant headerData(int section, Qt::Orientation orientation, int role) const override;

    Qt::ItemFlags flags(const QModelIndex & index) const override;

    void clear();

    void addData(QDateTime time, float temperature, quint32 brightness, quint8 moisture, quint16 conductivity);

private:
    struct data {
        QDateTime time;
        float value;

    };
    QList<data> tableData;

};

class Obj : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QAbstractTableModel* model READ getModel NOTIFY updated)

public:
    QAbstractTableModel* getModel() {return myModel;}
    Q_INVOKABLE void startUpdate(); //updated emitted here eventually as well as addData called on model.

signals:
    void updated();

private:
    MyModel *myModel = new MyModel();

};

QVariant MyModel::data(const QModelIndex& index, int role) const
{
    if(role == Qt::DisplayRole && tableData.size()-1 >= index.row()) {
        if(index.column() == 0) {
            return QVariant(tableData[index.row()].time.toMSecsSinceEpoch());
        } else if(index.column() == 1) {
            return QVariant(tableData[index.row()].value);
        } else {
            return QVariant();
        }
    } else {
        return QVariant();
    }
}

int MyModel::columnCount(const QModelIndex& parent) const
{
    return 5;
}

int MyModel::rowCount(const QModelIndex& parent) const
{
    return 24;
}

void MyModel::addData(QDateTime time, float value)
{
    tableData.append(data{time, value}); //Previously tried dynamic row count with begin/end row inserted.
    emit dataChanged(createIndex(0,0),createIndex(23,4));
}

Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);


    QQmlApplicationEngine engine;
    qmlRegisterType<Obj>("org.eyecreate.testmodel",1,0,"ObjModel");
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

    if (engine.rootObjects().isEmpty()) {
        return -1;
    }

    return app.exec();
}
import QtCharts 2.3 as Charts
import org.eyecreate.testmodel 1.0

ObjModel {
    id: myObj
}

Charts.ChartView {
    antialiasing: true
    legend.visible: false
    anchors.fill: parent
    Charts.LineSeries {
        axisX: Charts.DateTimeAxis {
            format: "MMM d yyyy ha"
        }
        axisY: Charts.ValueAxis {
            min: 0
            max: 50
        }

        Charts.VXYModelMapper {
            model: myObj.model
            xColumn: 0
            yColumn: 1

        }
    }
}

Button {
    onClicked: {
        myObj.startUpdate();
    }
}

EDIT: I found code very similar to mine that shows the same issue here: https://bitbucket.org/johnwoltman/chartmodelmappertest/src/master/ It seems this might be a bug: https://bugreports.qt.io/browse/QTBUG-60336


Solution

  • I found out through trying everything that the data points are in the series correctly, just that the graph needed to be adjusted so the points were in view. Adjusting the min/max for each axis has allowed the lines to show up.