QT Tree model

Qt 的确是一个好东西,开发起来非常方便,但是方便也带来很多问题,这些问题就不多说了,用到的人自然会有体会。

这几天在研究Qt的MVC,List和Table类型的都很简单,没有什么难度,但是它的TreeModel实在是让我晕了好几天。

一般用TreeModel都是用自己的类,于是,按着文档上说明的,关于继承QAbstractItemModel的时候,必须实现如下几个函数:index(), parent(), rowCount(), columnCount(), data(), 要让Model变成可以编辑的话,必须还要实现 setData(), flags() 这两个函数,让flags()返回值有ItemIsEditable。 同时,还可以实现headerData()和 setHeaderData() 来控制View中的标题。

接下来的问题就简单一些,实现它的数据结构,结构也很简单,就是简单的树形,一行,就是一个数据(当然,这一行也可以是很多数据),这里一行,就是一个item,每个里面的数据就是对应的column。在实现上,这个item可以有list,含有它的child, 也要有一个parent的指针。最Root,只有一个node(记得,我们说的是Tree!) , 简单吧? 如果要把这样的结构与其它scene graph一起用,基本上不用实现那个list和parent的指针,因为SG的node会给你这样的信息。

下面的问题,就是实现那几个必须的函数。
QModelIndex index ( int row, int column, const QModelIndex & parent ) const
这个函数对View来说,就是要你给它它所需要的行与列上的index.不管这个item有没有parent,view都会给你一个parent,当然,如果没有parent,那这个parent的index就是无效的。来看看怎么实现
[code]
CTreeItem *parentItem;

if(parent.isValid()==false)
parentItem=m_pRootItem;
else
parentItem=static_cast(parent.internalPointer());
CTreeItem *childItem = parentItem->child(row);
if(childItem)
return createIndex(row,column,childItem);
else
return QModelIndex();
[/code]
上面,[code]if(parent.isValid()==false)[/code]如果view给出的parent无效,那当前所指的item一定是第一层,也就是Root下面的。如果不是,那就用parentItem=static_cast(parent.internalPointer()) 得到这个node的指针,然后,看这个node里view需要的那一行上是否有node,如果没有,就返回无效的index( return QModelIndex())

QModelIndex parent ( const QModelIndex & index ) const
这个函数,是view向你要一个指定index的parent的index.来看看怎么实现
[code]
if(index.isValid()){
CTreeItem * childItem=static_cast(index.internalPointer());
CTreeItem * parentItem=childItem->parent();

 

if(parentItem==m_pRootItem)
return QModelIndex();
else
return createIndex(parentItem->row(),20,parentItem);
} else
return QModelIndex();
[/code]
如果view给我一个无效的index,那我当然告诉它,这个无效的index的parent也是无效的,无效的parent,在这里,就是明确说明这个index是顶层的node的index,无效的含义只有这一个。代码很简单,得到这个index所指node的指针,看它有没有parent,如果它的parent就是root,那就也返回一个无效的index,否则就create一个,返回给view.
5个必须实现的函数中,只有这两个是要返回index的,在createIndex中,parent函数的index中列的数量好象不重要,我把它随便设一个数,结果都是正确的,也可能是因为,我的结构就是这样,列上的东西,就是数据,而不是node,node都是行。在createIndex中,可以包含一个指针,或一个int,这里,我要它在每个index中,都直接有一个node的指针,这对于其它的函数,是非常方便的 int rowCount ( const QModelIndex & parent ) const
这个函数简单,每个index中都有一个指针,我拿到这个指针,看它指向的node有几个child,然后返回这个数,就OK了。如果index无效,那这个index就是root。看代码
[code]
CTreeItem *parentItem;
if(parent.isValid())
parentItem=static_cast(parent.internalPointer());
else
parentItem=m_pRootItem;

return parentItem->childCount();
[/code] int columnCount(const QModelIndex &parent ) const
一个node有几个数据,就反回就是了,没什么好说的。

QVariant data(const QModelIndex &index, int role ) const
看代码吧,没什么难度的
[code]
if(index.isValid()==false)
return QVariant();

if(role != Qt::DisplayRole)
return QVariant();

CTreeItem *item=static_cast(index.internalPointer());

return item->data(index.column());
[/code]
这个data,可不要什么role都返回一个数据,那样,就是全空,这个问题搞了我一天,最后才突然发现是这里有问题。

最后看一下CTreeItem的代码:
[code]
class CTreeItem
{
public:
CTreeItem(QStringList data,CTreeItem *parent=0);
~CTreeItem(void);
void appendChild(CTreeItem *child);
CTreeItem *child(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
int row() const;
CTreeItem * parent();

private:
QStringList m_StrData;
QList m_Children;
CTreeItem * m_pParent;

};

CTreeItem::CTreeItem(QStringList data,CTreeItem *parent)
:m_pParent(parent),m_StrData(data)
{
m_Children.clear();
}

CTreeItem::~CTreeItem(void)
{
qDeleteAll(m_Children);
}

void CTreeItem::appendChild(CTreeItem *child)
{
m_Children.append(child);
}

int CTreeItem::childCount() const
{
return m_Children.size();
}

int CTreeItem::columnCount() const
{
return m_StrData.size();
}

QVariant CTreeItem::data(int column) const
{
return m_StrData.value(column,”");
}
int CTreeItem::row() const
{
if(m_pParent)
return m_pParent->m_Children.indexOf(const_cast(this));
else
return 0;
}

CTreeItem * CTreeItem::parent()
{
return m_pParent;
}

CTreeItem * CTreeItem::child(int row)
{
return m_Children.value(row);
}
[/code]

哈哈,基本上是抄文档的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值