I have:
- a c++ model class (Bank) for storing simple data objects (Coefficient):
typedef quint32 Coefficient;
class Bank : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<Coefficient> coefficients READ coefficients WRITE setCoefficients NOTIFY coefficientsChanged)
public:
explicit Bank(QList<Coefficient> coefficients = QList<Coefficient>(), QObject *parent = nullptr);
QList<Coefficient> coefficients() const;
void setCoefficients(QList<Coefficient> coefficients);
// ...
signals:
void coefficientsChanged(QList<Coefficient> coefficients);
private:
QList<Coefficient> _coefficients;
};
- an AbstractListModel class (BankClass) for working with data throug views:
class Bank;
class BankModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(Bank* bank READ bank WRITE setBank)
public:
enum {
CoefficientRole = Qt::UserRole
};
explicit BankModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = CoefficientRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
QHash<int, QByteArray> roleNames() const override;
Bank* bank() const;
void setBank(Bank* bank);
private:
Bank* _bank;
};
- a QObjectList-based model to store several AbstractListModel's (BankModel's)
class CoefficientListModel;
class ConfigModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QObject*> banks READ banks WRITE setBanks NOTIFY banksChanged)
public:
explicit ConfigModel(QList<QObject*> banks = QList<QObject*>(), QObject *parent = nullptr);
QList<QObject*> banks() const;
void setBanks(QList<QObject*> banks);
signals:
void banksChanged(QList<QObject*> banks);
private:
QList<QObject*> _banks;
};
- and a qml view to set it all up (main.qml):
Window {
// ...
ListView {
// ...
model: cfg // ConfigModel
delegate: ConfigDelegate {
// ...
ListView {
model: model.bank // BankModel
delegate: BankDelegate {
some int property: coefficient // my role in bank model
}
}
}
}
}
where cfg is a registered in main.cpp object:
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<CoefficientListModel>("Config", 1, 0, "CoefficientListModel");
qmlRegisterType<ConfigModel>("Config", 1, 0, "ConfigModel");
ConfigModel cfg;
cfg.setBanks(QList<QObject*>()
<< new CoefficientListModel(QList<Coefficient>({ Coefficient { 11 }, Coefficient { 21 }, Coefficient { 31 }, Coefficient { 41 } }))
// ...
<< new CoefficientListModel(QList<Coefficient>({ Coefficient { 15 }, Coefficient { 25 }, Coefficient { 35 }, Coefficient { 45 } }))
);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty(QStringLiteral("cfg"), &cfg);
engine.rootContext()->setContextProperty(QStringLiteral("client"), &client);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
So, how to set c++ models in this qml depth from upper level? Or what's wrong here? Is it right application architecture?
It should looks like in the picture below.
Edit:
Now I've got a class as a tree item:
class CoefficientItem
{
public:
CoefficientItem(quint32 value = -1, int row = 0, CoefficientItem* parent = nullptr);
~CoefficientItem();
CoefficientItem *childAt(int i);
int childrenCount();
CoefficientItem *parent();
quint32 value() const;
int row() const;
void setValue(const quint32& value);
void setParent(CoefficientItem* parent_item);
void appendChild(CoefficientItem* child);
private:
quint32 _value;
CoefficientItem* _parent_item;
QHash<int, CoefficientItem*> _child_items;
int _row_number;
};
and tree model:
class ConfigModel : public QAbstractItemModel
{
Q_OBJECT
enum { CoefficientRole = Qt::UserRole };
public:
explicit ConfigModel(const QVector<QVector<quint32>>& config, CoefficientItem* root = nullptr, QObject *parent = nullptr);
~ConfigModel();
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = CoefficientRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
void setModelUp(const QVector<QVector<quint32> >& config);
private:
CoefficientItem* _root_item;
};
And the problem now is in access to internal level of tree model. In main.qml i have a list view:
ListView {
anchors.fill: parent
model: DelegateModel {
model: cfg
delegate: BankView {}
}
}
BankView.qml is the delegate which consists of BankViewHeader.qml (as a checkbox) and BankViewDescription.qml (as a Component with List of TextFields)
BankView.qml:
Rectangle {
id: bank_view
width: parent.width
height: bank_view_column.height
color: "#946782"
Column {
id: bank_view_column
spacing: 0
clip: true
BankViewHeader {
id: checker
text: qsTr("Bank " + model.index)
checked: true
implicitWidth: bank_view.width
}
BankViewDescription {
id: description
isOpened: checker.checked
width: bank_view.width
}
}
Component.onCompleted: checker.checked = false
}
BankViewDescription.qml:
RowLayout {
// ...
ListView {
model: DelegateModel {
model: model // <-- problem here ???
delegate: Row {
TextField {
//... use my role here - coefficient (uint32)
}
}
// ...
}
// ...
}
}
So what's wrong? no any errors in log, and top level of tree works fine (i think), view shows 4 banks as were initialized in main.cpp.
Bank
class. And you can actually use typedef instead of struct with one member, unless you are planning to have more members, then you could consider usingQ_GADGET
– Amfasis