Я тож долго соображал (до сих пор соображаю еще).
Вот, может пригодится это обсуждение:
http://www.prog.org.ru/topic_15908_0.htmlСамым простым решением (что я надумал), является создание базового класса Итем, от которого будут наследоваться уже реальные итемы источника данных, которые идентифицируются по типу.
т.е. мысленно делим итемы нашей структуры данных на типы, например:
корневой итем
rootItem,
итем 1-го уровня вложенности
oneLevelItem,
итем 2-го уровня вложенности
twoLevelItem,
....
итем n-го уровня вложенности
nLevelItem,
т.е. базовый класс имеет вид:
class BaseNode
{
public:
enum NodeType {
RootNodeType,
OneLevelType,
TwoLevelType,
};
BaseNode(BaseNode *parent = 0);
virtual ~BaseNode();
// Control Interface
void appendChild(BaseNode *child);
void removeChild(BaseNode *child);
void removeAllChild();
//
BaseNode *child(int row);
int childCount() const;
virtual int columnCount() const = 0;
virtual QVariant data(int column) const = 0;
int row() const;
BaseNode *parent();
NodeType type() const;
protected:
QList<BaseNode *> childNodes;
NodeType nodeType;
private:
BaseNode *parentNode;
};
т.е. всё аналогично тому, что в примерах с TreeItem, но! с одним условием, что добавили
enum NodeType (тип итема/узла),
плюс сделали методы:
virtual int columnCount() const = 0;
virtual QVariant data(int column) const = 0;
чисто абстрактными (т.е. реализовывать их будем в других классах-наследниках от базового),
плюс убрали список QList<QVariant> с данными итема, т.к. каждый тип итема будет содержать разные типы/кол-во данных (столбцов).
Теперь реализуем те классы-итемы, типы которых у нас будут в нашей структуре данных, пример:
корневой узел.
class RootNode : public BaseNode
{
public:
class RootData
{
public:
QString title;
QString summary;
};
RootNode(BaseNode *parent = 0);
void setRootData(const RootData &data);
// From BaseNode
int columnCount() const;
QVariant data(int column) const;
private:
RootData data;
};
------------------------------------------------
RootNode::RootNode(BaseNode *parent)
: BaseNode(parent)
{
this->nodeType = BaseNode::RootNodeType;
RootNode::RootData rd;
rd.title = "Title";
rd.summary = "Summary";
this->setRootData(rd);
}
void RootNode::setRootData(const RootData &data)
{
this->data= data;
}
// From BaseNode
int RootNode::columnCount() const
{
return 2;
}
QVariant RootNode::data(int column) const
{
switch (column) {
case 0: return QVariant(this->data.title);
case 1: return QVariant(this->data.summary);
default:;
}
return QVariant();
}
Видим, что корневой узел имеет данные типа RootData, которые содержат всего два столбца
title и
summary, т.е. это то что будет отображено в TreeView как заголовки (header).
При этом, знаем, что сам корневой узел не отображается в TreeView !!!Далее, реализуем другой итем 1-го уровня:
class OneLevelNode : public BaseNode
{
public:
class OneLevelData
{
public:
int id;
QString name;
QString description;
};
OneLevelNode (const QString &name, BaseNode *parent = 0);
void setOneLevelData(const OneLevelData &data);
// From BaseNode
int columnCount() const;
QVariant data(int column) const;
private:
OneLevelData data;
};
------------------------------
OneLevelNode::OneLevelNode(const QString &name, BaseNode *parent)
: BaseNode(parent)
{
this->nodeType = BaseNode::OneLevelNodeType;
this->data.name = name;
}
void OneLevelNode::setOneLevelDataData(const OneLevelData &data)
{
this->options = data;
}
// From BaseNode
int OneLevelNode::columnCount() const
{
return 3;
}
QVariant OneLevelNode::data(int column) const
{
switch (column) {
case 0: return QVariant(this->data.id);
case 1: return QVariant(this->data.name);
case 2: return QVariant(this->data.description);
default:;
}
return QVariant();
}
Как видим, этот класс содержит данные
OneLevelData из трёх полей.
Далее, реализуем все остальные классы-итемы, которые у нас будут в дереве.
Теперь, в модели делаем так:
class CoreTreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
CoreTreeModel(RootNode *rootNode, QObject *parent = 0);
~CoreTreeModel();
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
private:
RootNode *rootNode;
};
При этом, считаем, что дерево данных
rootNode полученное в модель уже существует (создано и заполнено данными/итемами заранее).
(Считаем так для простоты).
Теперь, нужно переопределить виртуальные методы модели так, чтобы она "рисовала" нам итемы данных так как мы хотим:
....
QVariant CoreTreeModel::data(const QModelIndex &index, int role) const
{
if (this->rootNode && index.isValid() && (Qt::DisplayRole == role)) {
const BaseNode *node = static_cast<BaseNode *>(index.internalPointer());
if (node) {
int column = 0;
switch (node->type()) {
case BaseNode::ProjectNodeType:
column = index.column();
if (0 == column)
return node->data(++column);
default:;
}
}
}
return QVariant();
}
....
т.е. вся фишка в
const BaseNode *node = static_cast<BaseNode *>(index.internalPointer());
...
switch (node->type()) {
...
}
...
т.е. мы для рисования данных сначала определяем : "а что, собственно, щас у нас за текущий тип итема?" и в зависимости от типа итема мы можем выбирать, какие данные (столбцы) этого итема нам отображать, а какие нафик не нужны для отображения (но они есть)!!!
И по аналогии переопределяем другие методы модели!
Надеюсь, суть ясна?
ЗЫ: старался донести как мог идею (один из вариантов решения проблем похожего рода).