Home > front end >  How to fill QAbstractTableModel with another's class attribute (2D array)
How to fill QAbstractTableModel with another's class attribute (2D array)

Time:11-05

I have class, which reads data from file to 2D array.

So i need to display that array in qml TableView.

I have QVector<QVector> table; to display it as data in my TableModel.

The OperatingFiles object creates in main.cpp it contains functions to encode/decode passwords and save them to file. Functions for this object is also called from qml code

So what i want is to make "table = passwordsDecoded" somewhere but i don't know how to do it.

OperatingFiles.h :

class OperatingFiles : public QObject
{
    Q_OBJECT
public:
    OperatingFiles();
public slots:
    QVector<QVector<QString>> getVector(); // returns passwordsDecoded
private:
    QVector<QVector<QString>> passwordsDecoded;
};
#endif // OPERATINGFILES_H

TableModel.h:

class TableModel : public QAbstractTableModel
{
    Q_OBJECT
    QVector<QVector<QString>> table;
public:
    explicit TableModel(QObject *parent = nullptr);
    int rowCount(const QModelIndex & = QModelIndex()) const override;
    int columnCount(const QModelIndex & = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role) const override;
    QHash<int, QByteArray> roleNames() const override;
};

TableModel.cpp:

#include "tablemodel.h"
TableModel::TableModel(QObject *parent)
    : QAbstractTableModel{parent}
{
    QVector<QString> mini;   // this only for test that it really appears in TableView (it appears)
    mini.append("rstrst");
    mini.append("rstrst");
    mini.append("rstrst");
    table.append(mini);
    table.append(mini);
    table.append(mini);
}
int TableModel::rowCount(const QModelIndex &) const
{
    return table.size();
}
int TableModel::columnCount(const QModelIndex &) const
{
    return table.at(0).size();
}
QVariant TableModel::data(const QModelIndex &index, int role) const
{
    switch (role) {
    case Qt::DisplayRole:
        return table.at(index.row()).at(index.column());
    default:
        break;
    }
    return QVariant();
}
QHash<int, QByteArray> TableModel::roleNames() const
{
    return { {Qt::DisplayRole, "display"} };
}

qml:

TableView {
            anchors.fill: parent
            columnSpacing: 1
            rowSpacing: 1
            clip: true
            model: TableModel{}
            delegate: Rectangle {
                implicitWidth: 100
                implicitHeight: 50
                border.width: 0
                Text {
                    text: display
                    anchors.centerIn: parent
                }
            }
        }

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "controlbuttons.h"
#include "operatingfiles.h"
#include "tablemodel.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);
    qmlRegisterType<TableModel>("TableModel", 0,1,"TableModel");
    QQmlApplicationEngine engine;
    ControlButtons *appManager = new ControlButtons(&app);
        engine.rootContext()->setContextProperty("appManager", appManager);
    OperatingFiles *fileOperator = new OperatingFiles();
        engine.rootContext() -> setContextProperty("fileOperator", fileOperator);
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    return app.exec();
}

I tried to make functions in TableModel that could fill "table" with data from my object which was called directly from qml ("OnClicked:"), tried make constructor which will get object with 2D array. I seen ton of vids and read docs but literally no idea how to do it.

So whole chain is: choose file✓ -> read file✓ -> decode✓ -> fill 2D array✓ -> send to model (Somehow) -> appear it in UI✓

Maybe it could be done if i make my 2D array global so i could access to it from anywhere but it not a solution.

Thanks!

CodePudding user response:

The easiest modification would be to add a Q_INVOKABLE to your TableModel which allows to set the table

class TableModel : public QAbstractTableModel
{
    ...
    Q_INVOKABLE void setTable(const QVariant& value)
    { //inline for briefity
        beginResetModel();
        table = value.value<QVector<QVector<QString>>>();
        endResetModel();
    }
}

Then from QML you can do <id of TableModel>.setTable(fileOperator.getVector())

Another option would be a Q_PROPERTY with a similar setter method. Then you would use <id of TableModel>.table = fileOperator.getVector()


I'm not sure about how you want your structure to look like, but if you don't need TableModel to be instantiatable from QML you could make it available as contextProperty the same way as you did with the fileOperator. Then you will have more control on the TableModel, for instance, you can call a fill function from C side when done.

  • Related