我是QML的新手,最近我在集成QML和C ++方面遇到了一些麻烦,现在我尝试正确地进行集成。
所以,我正在尝试使用动态模型创建QML TreeView,我看到了不同的方法来构建TreeView模型。
在文档中,示例使用TableViewColumn:
https://doc-snapshots.qt.io/qt5-5.9/qml-qtquick-controls-treeview.html
在一些互联网研究中我发现: 使用C ++创建:
https://forum.qt.io/topic/56497/request-treeview-c-model-to-qml-example/4
所以,我的问题是,为QML TreeView创建模型的正确方法是什么? 该模型将是动态的动态数据。
对于动态,我的意思是会有不确定数量的节点,但信息将是相同的,它遵循一个json和一个示例图像:
[
{
"description": "screen1",
"source": "qrc/screen1.qml",
"popups":
[
{
"description": "screen1popup1",
"source": "qrc/screen1popup1.qml"
},
{
"description": "screen1popup2",
"source": "qrc/screen1popup2.qml"
}
]
},
{
"description": "screen2",
"source": "qrc/screen2.qml",
"popups":
[
{
"description": "screen2popup1",
"source": "qrc/screen2popup1.qml",
"subs": [
{
"description": "screen2popup1sub1",
"source": "qrc/screen2popup1sub1.qml"
}
]
}
]
},
{
"description": "screen3",
"source": "qrc/screen3.qml"
}
]
答案 0 :(得分:1)
我做了类似的解决方案。有我的模特:
树项目
treeitem.h
#ifndef TREEITEM_H
#define TREEITEM_H
#include <QList>
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonDocument>
class TreeItem
{
public:
explicit TreeItem(const QJsonValue &data, const QString childrenPath, TreeItem *parentItem = 0);
~TreeItem() { qDeleteAll(m_childItems); }
bool insertChild(int i, TreeItem *child);
TreeItem *child(int row) { return m_childItems.at(row); }
int childCount() const { return m_childItems.count(); }
int columnCount() const { return m_itemData.toObject().count(); }
QVariant data(const QString &roleName) const;
bool setParentItem(TreeItem *item);
int row() const;
TreeItem *parentItem() { return m_parentItem; }
QJsonValue jsonValue() const;
bool removeChild(int row, int count);
bool isTheIdExist(QString id);
bool isParent(TreeItem *item);
private:
QVector<TreeItem*> m_childItems;
QJsonValue m_itemData;
TreeItem *m_parentItem;
QString childrenPath;
};
#endif // TREEITEM_H
treeitem.cpp
#include <QDateTime>
#include "treeitem.h"
TreeItem::TreeItem(const QJsonValue &data, const QString childrenPath, TreeItem *parentItem) :
m_parentItem(parentItem), childrenPath(childrenPath)
{
QJsonObject jObject = data.toObject();
jObject.remove(childrenPath);
m_itemData = QJsonValue(jObject);
}
bool TreeItem::insertChild(int i, TreeItem *child)
{
if (i >= m_childItems.count())
m_childItems.append(child);
else
m_childItems.insert(i, child);
return true;
}
QVariant TreeItem::data(const QString &roleName) const
{
QJsonValue val = m_itemData.toObject().value(roleName);
if (val.type() == QJsonValue::String) {
QString strVal = val.toString();
QDateTime dtVal = QDateTime::fromString(strVal, Qt::ISODate);
if (dtVal.isValid())
return dtVal;
}
else if (val.type() == QJsonValue::Double) {
int intVal = val.toInt(0);
if (intVal != 0)
return intVal;
}
else if (val.type() == QJsonValue::Bool) {
return val.toBool();
}
return val.toVariant();
}
bool TreeItem::setParentItem(TreeItem *item)
{
if (item == this)
return false;
foreach (TreeItem *i, m_childItems) {
if (item->isParent(i)) {
return false;
}
}
m_parentItem = item;
return true;
}
int TreeItem::row() const
{
if (m_parentItem)
return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this));
return 0;
}
QJsonValue TreeItem::jsonValue() const {
QJsonObject jObj = m_itemData.toObject();
QJsonArray jArray;
if (m_childItems.count() > 0) {
foreach (TreeItem *i, m_childItems)
jArray.append(i->jsonValue());
jObj.insert(childrenPath, jArray);
}
if (m_itemData.toObject().empty()) {
return QJsonValue(jArray);
}
else {
return QJsonValue(jObj);
}
}
bool TreeItem::removeChild(int row, int count)
{
if (row > -1 && row+count <= m_childItems.count()) {
for (int i = count; i > 0; i--)
m_childItems.removeAt(row + i - 1);
return true;
}
return false;
}
bool TreeItem::isTheIdExist(QString id)
{
if (m_itemData.toObject().value("id").toInt() == id.toInt())
return true;
foreach (TreeItem *item, m_childItems) {
if (item->isTheIdExist(id))
return true;
}
return false;
}
bool TreeItem::isParent(TreeItem *item)
{
bool result = false;
if (parentItem() != Q_NULLPTR)
if (parentItem()->isParent(item)) result = true;
if (parentItem() == item) result = true;
return result;
}
<强>模型强>
treejsonmodel.h
#ifndef TREEJSONMODEL_H
#define TREEJSONMODEL_H
#include <QAbstractItemModel>
#include <QFile>
#include <QJSValue>
#include <QDebug>
#include "treeitem.h"
class TreeJsonModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit TreeJsonModel(QObject *parent = 0);
~TreeJsonModel();
Q_PROPERTY(bool hasChanges READ hasChanges NOTIFY hasChangesChanged)
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
Q_INVOKABLE int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &) const Q_DECL_OVERRIDE { return _columns.count(); }
bool hasChildren(const QModelIndex &parent) const Q_DECL_OVERRIDE;
QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column, const QModelIndex &parent) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE;
void registerColumn(const QString &name);
void setUrl(const QString &url) { _fileUrl = url; }
bool hasChanges() const { return _hasChanges; }
Q_INVOKABLE bool submit() Q_DECL_OVERRIDE;
Q_INVOKABLE void refresh();
signals:
void dataReady();
void hasChangesChanged();
private:
QString _fileUrl;
QString _childrenPath = "parents"; // this is the name of path with children
QStringList _columns;
TreeItem *rootItem = Q_NULLPTR;
bool _hasChanges = false;
void addNewItem(const QJsonValue &data, TreeItem *parent = nullptr);
void addNewItem(const QJsonValue &data, int row, TreeItem *parent = nullptr);
};
#endif // TREEJSONMODEL_H
*treejsonmodel.cpp*
#include "treejsonmodel.h"
TreeJsonModel::TreeJsonModel(QObject *parent) :
QAbstractItemModel(parent)
{
}
TreeJsonModel::~TreeJsonModel() {
submit();
delete(rootItem);
}
Qt::ItemFlags TreeJsonModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
return QAbstractItemModel::flags(index);
}
QVariant TreeJsonModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->data(roleNames().value(role));
}
QVariant TreeJsonModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return rootItem->data(roleNames().value(section));
return QVariant();
}
int TreeJsonModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0 || rootItem == Q_NULLPTR)
return 0;
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
return parentItem->childCount();
}
bool TreeJsonModel::hasChildren(const QModelIndex &parent) const
{
return rowCount(parent) > 0;
}
QHash<int, QByteArray> TreeJsonModel::roleNames() const
{
QHash<int, QByteArray> result = QAbstractItemModel::roleNames();
for (int i = 0; i < _columns.count(); i++) {
int id = Qt::UserRole + 1 + i;
QByteArray byte = _columns.at(i).toUtf8();
result.insert(id, byte);
}
return result;
}
QModelIndex TreeJsonModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeItem *parentItem;
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex TreeJsonModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
TreeItem *parentItem = childItem->parentItem();
if (parentItem == rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
void TreeJsonModel::registerColumn(const QString &name)
{
if (!_columns.contains(name))
_columns.append(name);
}
void TreeJsonModel::refresh()
{
QFile file(_fileUrl);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Can't open file" << _fileUrl;
return;
}
beginResetModel();
QJsonDocument jDoc = QJsonDocument::fromJson(file.readAll());
rootItem = new TreeItem(QJsonValue(), _childrenPath);
foreach (QJsonValue item, jDoc.array()) {
addNewItem(item, rootItem);
}
_hasChanges = false;
hasChangesChanged();
emit endResetModel();
emit dataReady();
file.close();
}
bool TreeJsonModel::submit()
{
QFile file(_fileUrl);
if (!file.open(QIODevice::WriteOnly)) {
qDebug() << "Can't open file";
return false;
}
QJsonValue jValue = rootItem->jsonValue();
QJsonDocument jDoc = QJsonDocument(jValue.toArray());
file.write(jDoc.toJson());
file.close();
_hasChanges = false;
hasChangesChanged();
emit dataReady();
return true;
}
void TreeJsonModel::addNewItem(const QJsonValue &data, TreeItem *parent)
{
addNewItem(data, parent->childCount(), parent);
}
void TreeJsonModel::addNewItem(const QJsonValue &data, int row, TreeItem *parent)
{
auto *item = new TreeItem(data, _childrenPath, parent);
parent->insertChild(row, item);
QJsonValue v = data.toObject().value(_childrenPath);
if (v != QJsonValue::Undefined && v.isArray()) {
foreach (QJsonValue val, v.toArray()) {
addNewItem(val, item);
}
}
}
如果需要插入,移除,移动功能,则必须实现此功能 具有可拖动行的Complite程序,您可以下载here。