我对Qt很陌生,我正在尝试基于一个平面(或来自sqlite表)文件路径列表(而不是来自FS)来构建一个简单的树,如下所示:
C:\Parent1\Child1\Leaf1.jpg
C:\Parent1\Child1\Leaf2.jpg
C:\Parent1\Child1\Leaf3.jpg
C:\Parent1\Child2\Leaf1.jpg
C:\Parent1\Child2\Leaf2.jpg
C:\Parent2\Child1\Leaf1.jpg
C:\Parent2\Child1\Leaf2.jpg
...
D:\....
...我想将它显示为树视图(例如,文件资源管理器)。
我查看了QAbstractItemModel,但我在构建这棵树时遇到了一些困难。我的想法是使用'\'拆分每个路径,并在添加分支之前检查它们是否已经存在。如果分支存在,我必须找到好的父母来添加这个新的孩子。
我正在使用一个简单的树示例,但实现我的模型确实有困难。
void MyTreeModel::setupModelData(TreeItem *parent)
{
QList<TreeItem*> parents;
parents << parent;
int number = 0;
QString path = "mydb_path";
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
if(db.open())
{
QSqlQuery query("SELECT path FROM file");
int idPath = query.record().indexOf("path");
while (query.next())
{
QString name = query.value(idPath).toString();
int id_file = query.value(idIdx).toInt();
QStringList nodeString = name.split("\\", QString::SkipEmptyParts);
for(int node = 0; node < nodeString.count(); ++node)
{
// I don't know what to do now... Should I build a lookup table with a parent id for each node before to populate my TreeItems ?
}
}
}
//...
}有小费吗?
发布于 2016-04-01 10:15:26
使用QAbstractModelItem是不直观的。但是,看起来您最大的问题实际上是建模,,您的路径列表到一个元素树。有两项任务:
QAbstractItemModel实现下使用此数据结构。步骤1:实际的树实现
您需要首先实现一棵树。有点像
struct mytree
{
static std::shared_ptr<mytree> frompath(QString path);
static std::shared_ptr<mytree> merge(std::shared_ptr<mytree> t1, std::shared_ptr<mytree> t2);
//may need helpers : is leaf, etc, or just access to children
QString value;
std::list<std::shared_ptr<mytree> > childrens_;
mytree(); //construct empty tree
};其中值是文件名或文件夹名。
frompath从一个条目构建树。
C->父母2->儿童1->Leaf2.jpgmerge使用两棵现有的树并构造一棵树
C->父母2->儿童1->Leaf1.jpg C->父母2->儿童2->Leaf1.jpg
变成了
C->父母2->{Child2 1->Leaf1.jpg,Child2 2->Leaf1.jpg}步骤2:模型
一旦您有了该列表,您至少需要实现以下方法:
QModelIndex parent(const QModelIndex & index) const;
QModelIndex index(int row, int column, const QModelIndex & parent) const;
int columnCount(const QModelIndex & parent) const;
int rowCount(const QModelIndex & parent) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;一些小贴士:
QModelIndex()。顶级项具有QModelIndexQModelIndex分配给对象mytree。现在,要实现这些方法,需要向树中添加3个字段:
uint qHash(const QString & key)。这棵新树有田园
struct mytree
{
//removed methods;
QString path; eg C:\Parent1\Child1
QString value; eg Child1
unsigned int id; eg: qHash(path)
int pos; //my position in the parent list. this is the row in the model
std::shared_ptr<mytree> parent;
std::list<std::shared_ptr<mytree> > childrens;
};您需要能够快速获得mytree的id。这意味着模型中的内部数据结构将是
std::map<unsigned int, std::shared_pr<mytree> > items_by_id;
std::shared_pr<mytree> root_item;现在,您已经具备了实现上述方法所需的一切。这只是为了演示,所以不要认为这段代码是理所当然的
std::shared_pr<mytree> find_elt_helper(const QModelIndex & index) const
{
auto iter = items_by_id.find(index.internalId());
if(iter == items_by_id.end())
return std::shared_pr<mytree>();
return iter->second;
}
QModelIndex parent(const QModelIndex & index) const
{
if(!index.isValid())
return QModelIndex();
std::shared_pr<mytree> index_item = find_elt_helper(index);
return index_item ? create_index(index_item->parent->pos, 0, index_item->parent->id) : QModelIndex();
}
QModelIndex index(int row, int column, const QModelIndex & parent) const
{
std::shared_pr<mytree> parent_item = !parent.isValid() ? root_item : find_elt_helper(parent);
std::shared_pr<mytree> item;
if(row >= parent_item.children.size())
return QModelIndex();
item = parent_item.children[row];
return create_index(row, 0, item->id);
}发布于 2016-04-01 19:58:59
非常感谢UmNyobe让我头脑清醒.我有点糊涂。在这里,我的实施:
treeitem.h
#ifndef TREEITEM_H
#define TREEITEM_H
#include <QList>
#include <QVariant>
class TreeItem
{
public:
explicit TreeItem(const QList<QVariant> &data, TreeItem *parentItem = 0, unsigned int id = 0);
~TreeItem();
void appendChild(TreeItem *child);
TreeItem *child(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
int row() const;
unsigned int getIndex(){return _id;};
TreeItem *parentItem();
private:
QList<TreeItem*> m_childItems;
QList<QVariant> m_itemData;
TreeItem *m_parentItem;
unsigned int _id;
};
#endif // TREEITEM_Htreeitem.cpp
#include <QStringList>
#include "treeitem.h"
TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent, unsigned int id)
{
m_parentItem = parent;
m_itemData = data;
_id = id;
}
TreeItem::~TreeItem()
{
qDeleteAll(m_childItems);
}
void TreeItem::appendChild(TreeItem *item)
{
m_childItems.append(item);
}
TreeItem *TreeItem::child(int row)
{
return m_childItems.value(row);
}
int TreeItem::childCount() const
{
return m_childItems.count();
}
int TreeItem::columnCount() const
{
return m_itemData.count();
}
QVariant TreeItem::data(int column) const
{
return m_itemData.value(column);
}
TreeItem *TreeItem::parentItem()
{
return m_parentItem;
}
int TreeItem::row() const
{
if (m_parentItem)
return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this));
return 0;
}restoretreemodel.h
#ifndef RESTORETREEMODEL_H
#define RESTORETREEMODEL_H
#include "treeitem.h"
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
class RestoreTreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit RestoreTreeModel(QObject* parent=0);
~RestoreTreeModel();
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
private:
void setupModelData(TreeItem *parent);
int findNode(unsigned int& hash, const QList<TreeItem*>& tList);
TreeItem *rootItem;
};
#endif // RESTORETREEMODEL_Hrestoretreemodel.cpp
#include "restoretreemodel.h"
#include <QStringList>
#include <QtSql>
RestoreTreeModel::RestoreTreeModel(QObject *parent)
: QAbstractItemModel(parent)
{
QList<QVariant> rootData;
rootData << "Nom" << "Nombre d'éléments";
rootItem = new TreeItem(rootData);
setupModelData(rootItem);
}
RestoreTreeModel::~RestoreTreeModel()
{
delete rootItem;
}
int RestoreTreeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
else
return rootItem->columnCount();
}
QVariant RestoreTreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->data(index.column());
}
Qt::ItemFlags RestoreTreeModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
return QAbstractItemModel::flags(index);
}
QVariant RestoreTreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return rootItem->data(section);
return QVariant();
}
QModelIndex RestoreTreeModel::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 RestoreTreeModel::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);
}
int RestoreTreeModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
return parentItem->childCount();
}
int RestoreTreeModel::findNode(unsigned int& hash, const QList<TreeItem*>& tList)
{
for(int idx = 0; idx < tList.size(); ++idx)
{
unsigned int z = tList.at(idx)->getIndex();
if(z == hash)
return idx;
}
return -1;
}
void RestoreTreeModel::setupModelData(TreeItem *parent)
{
QList<TreeItem*> parents;
parents << parent;
QString path = "my_db_path";
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
if(db.open())
{
QSqlQuery query("SELECT path, id_file FROM file");
int idPath = query.record().indexOf("path");
int idIdx = query.record().indexOf("id_file");
while (query.next())
{
QString name = query.value(idPath).toString();
int id_file = query.value(idIdx).toInt();
QStringList nodeString = name.split("\\", QString::SkipEmptyParts);
QString temppath = "";
int lastidx = 0;
for(int node = 0; node < nodeString.count(); ++node)
{
temppath += nodeString.at(node);
if(node != nodeString.count() - 1)
temppath += "\\";
unsigned int hash = qHash(temppath);
QList<QVariant> columnData;
columnData << nodeString.at(node);
int idx = findNode(hash, parents);
if(idx != -1)
{
lastidx = idx;
}
else
{
QString sQuery = "";
if(node == nodeString.count() - 1)
{
sQuery += "SELECT count(*) FROM version WHERE id_file=";
sQuery += QString::number(id_file);
sQuery += ";";
}
else
{
sQuery += "SELECT count(*) FROM file WHERE path like '";
sQuery += temppath;
sQuery += "%';";
}
int nChild = 0;
QSqlQuery query2(sQuery);
if(query2.next())
nChild = query2.value(0).toInt();
columnData << nChild;
if(lastidx != -1)
{
parents.at(lastidx)->appendChild(new TreeItem(columnData, parents.at(lastidx), hash));
parents << parents.at(lastidx)->child( parents.at(lastidx)->childCount()-1);
lastidx = -1;
}
else
{
parents.last()->appendChild(new TreeItem(columnData, parents.last(), hash));
parents << parents.last()->child( parents.last()->childCount()-1);
}
}
}
}
}
}我认为它可以改进,但它做的工作。我在等待任何建议。
https://stackoverflow.com/questions/36351165
复制相似问题