QTreeView和QAbstractItemModel [英] QTreeView and QAbstractItemModel
问题描述
我是Qt的新手,我正在尝试基于平面(或来自sqlite表)文件路径列表(而不是来自FS)制作一棵简单的树,如下所示:
I'm new to Qt and I'm trying to make a simple tree based on a flat (or from a sqlite table) file paths list (not from FS) like this:
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:\....
...
我想将其显示为树状视图(例如文件浏览器).
I'd like to display this as a tree view (e.g. a file explorer).
我研究了QAbstractItemModel,但是在构建树时遇到了一些困难.
我的想法是使用'\'
拆分每个路径,并在添加分支之前检查分支是否已经存在.如果分支存在,我必须找到好父母来添加这个新孩子.
I looked into QAbstractItemModel but I have some difficulties to build the tree.
My idea is to split each of the path using '\'
and check if the branches already exist before adding them. If the branches exist, I have to find the good parent to add this new child.
我正在使用一个简单的树示例但是我在实施模型方面确实有困难.
I'm using a simple tree example but I have real difficulties to implement my model.
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 ?
}
}
}
//...
}
有什么建议吗?
推荐答案
使用QAbstractModelItem
并不直观.但是看来您最大的问题实际上是 建模 到树元素的路径的列表.有两个任务:
Using a QAbstractModelItem
is not intuitive. But it looks like your biggest problem is actually modeling your list of paths into a tree of elements. There are two tasks :
- 处理您的输入数据以获得一个数据结构,以紧密地对数据进行概念性解释(您知道它们是路径).
- 在您的
QAbstractItemModel
实现下使用此数据结构.
- Process your input data to obtain a data structure close your conceptual interpretation of the data (you know they are path.)
- Use this data structure under your
QAbstractItemModel
implementation.
第1步:实际的树实现
您需要首先实现一棵树.像
Step 1: An actual tree implementation
You need to implement a tree first. Something like
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
};
值是文件名或文件夹名.
Where the value is a file name or folder name.
-
frompath
从单个条目构建树.C:\Parent2\Child1\Leaf2.jpg
变为
frompath
builds the tree from a single entry.C:\Parent2\Child1\Leaf2.jpg
becomes
C->Parent2->Child1->Leaf2.jpg
merge
采取两棵现有树并构建一棵树
merge
take two existing trees and construct a single one
C->Parent2->Child1->Leaf1.jpg
C->Parent2->Child2->Leaf1.jpg
成为
C->Parent2->{Child1->Leaf1.jpg, Child2->Leaf1.jpg}
拥有该列表后,您至少需要实现以下方法:
Once you have that list, you need to implement at least the following methods:
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()
.顶级项目具有QModelIndex
- 您必须将一个或多个
QModelIndex
分配给对象mytree
- 对于任何父项,您只有一列,因为只有一个数据(文件名).
- 行数是子项数.
- QModelIndex是使用 createIndex 创建的
- An invalid model index is
QModelIndex()
. A top level item hasQModelIndex
- You have to assign one or more
QModelIndex
to an objectmytree
- You have only one column for any parent, because there is only one data (the filename).
- The number of rows is the number of children.
- QModelIndex are created using createIndex
现在要实现这些方法,您需要在树中添加3个字段:
Now to be able to implement those method you need to add 3 fields to the tree :
- 对父项的引用
- 当前元素在父列表中的位置
- 一个id字段,用于唯一地标识一个节点.您可以在路径上使用
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.这意味着您模型中的内部数据结构将是
You need to be able to quickly get a mytree
given its id. Which means your internal data structure in the model will be
std::map<unsigned int, std::shared_pr<mytree> > items_by_id;
std::shared_pr<mytree> root_item;
现在,您拥有实现上述方法所需的全部条件.这只是用于演示,因此不要认为此代码是理所当然的
Now you have all you need to implement the methods above. This is just for demo so don't take this code for granted
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);
}
这篇关于QTreeView和QAbstractItemModel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!