Вроде бы внимательно изучил документацию, примеры simple и edit tree model. Начал сам делать и совсем запутался... Помогите распутаться плиз... Хочу сделать 3-х уровневую модель дерева. В примерах есть класс TreeItem который содержит указатель на родителя и список чайлдов. Но этот родитель и элементы списка сами являются TreeItem. С этим вроде бы ясно... А как развернуть эту структуру? Чтобы данные как бы отделить друг от друга?
Например превратить ее в 4 класса:
1. Класс самой модели.
2. Класс с данными верхенго уровня (содержит список данных и список чайлдов 3)
3. Класс с данными среднего уровня (содержит список данных и список чайлдов 4 и указатель на парента 2)
4. Класс с данными нижнего уровня (содержит список данных и указатель на парента 3)
А как при таком раскладе написать тела виртуальных функций QAbstractItemModel (index и parent и rowCount)?
3-й день сижу и ниче не получается (
Или этот подход неверен?
Сама задача такая. Есть список имен. Каждому элементу из этого списка соответсвует список других имен. Каждому элементу из последнего списка соответсвует набор данных. Как это все представить для модели? ((
Спасибо если кто-нибудь что-нибудь подскажет...
Rocky, на форуме много раз упоминалось про борьбу с деревом - попробуй начать с поиска
Нашел пару тем
http://www.forum.crossplatform.ru/index.php?showtopic=975&st=0&p=6407&#entry6407
http://www.forum.crossplatform.ru/index.php?showtopic=5436&hl=
Т.е. что, получается что не нужно наследоваться от QAbstractItemModel а тупо заполнять дерево вручную?
Так а если нужно обрабатывать нажатие мыши то как тогда с таким подходом?... Получается, что не годится... Имхо проще через QTreeWidget сделать.. но тогда тормоза будут если много данных ((
И если нужна отрисовка элементов своя...
//ResultTableItem.h
class CResultTableChild
{
QString m_sName1;
QString m_sName2;
QString m_sIntAn;
QString m_sIntCm;
QString m_sIntRel;
QString m_sConc;
public:
QVariant data(int nColumn) const;
bool setData(int nColumn, const QVariant &oData);
};
class CResultTableParent
{
QList<CResultTableChild*> childItems;
public:
CResultTableChild *child(int number);
int childCount() const;
bool insertChild(int position);
};
class CResultTableItem
{
QList<CResultTableParent*> childItems;
CResultTableParent *parentItem;
public:
CResultTableItem(CResultTableParent *parent = 0);
~CResultTableItem();
CResultTableParent *child(int number);
int childCount() const;
bool insertChild(int position);
CResultTableParent *parent();
int childNumber() const;
};
//ResultTableModel.h
class CResultTableItem;
class CResultTableParent;
class CResultTableModel : public QAbstractItemModel
{
Q_OBJECT
//CResultTableItem *getItem(const QModelIndex &index) const;
CResultTableParent *rootItem;
public:
CResultTableModel(QObject *parent = 0);
virtual ~CResultTableModel();
virtual QVariant data(const QModelIndex &index, int role) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
virtual QModelIndex parent(const QModelIndex &index) const;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
virtual bool insertRows(int position, int rows, const QModelIndex &parent = QModelIndex());
};
//ResultTableModel.cpp
#include <QtGui>
#include "./ResultTableItem.h"
#include "./ResultTableModel.h"
//---------------------------------------------------------------------------------------------------------//
CResultTableModel::CResultTableModel(QObject *parent) : QAbstractItemModel(parent)
{
rootItem = new CResultTableParent();
rootItem->insertChild(0);
rootItem->child(0)->setData(0, "Ni1_Fe1");
rootItem->child(0)->setData(1, "");
rootItem->child(0)->setData(2, "");
// CResultTableChild *pChild1 = rootItem->child(0);
// pChild1->insertChild(0);
// pChild1->child(0)->setData(1, "bvdr");
// pChild1->child(0)->setData(2, "");
// pChild1->child(0)->setData(3, "");
// CResultTableChild *pChild2 = pChild1->child(0);
// pChild2->insertChild(0);
// pChild2->child(0)->setData(2, "10");
// pChild2->child(0)->setData(3, "20");
}
//---------------------------------------------------------------------------------------------------------//
CResultTableModel::~CResultTableModel()
{
delete rootItem;
}
//---------------------------------------------------------------------------------------------------------//
int CResultTableModel::columnCount(const QModelIndex & /* parent */) const
{
return 6;
}
//---------------------------------------------------------------------------------------------------------//
QVariant CResultTableModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || role != Qt::DisplayRole) return QVariant();
CResultTableItem *item = getItem(index);
return item->data(index.column());
}
//---------------------------------------------------------------------------------------------------------//
Qt::ItemFlags CResultTableModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
//---------------------------------------------------------------------------------------------------------//
//CResultTableItem *CResultTableModel::getItem(const QModelIndex &index) const
//{
/// if (index.isValid())
// {
// CResultTableItem *item = static_cast<CResultTableItem*>(index.internalPointer());
// if (item) return item;
// }
// return rootItem;
//}
//---------------------------------------------------------------------------------------------------------//
QVariant CResultTableModel::headerData(int nSection, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch (nSection)
{
case 0: return "Analitical pair";
case 1: return "Spectr name";
case 2: return "Int A";
case 3: return "Int C";
case 4: return "Int rel";
case 5: return "C, %";;
}
}
return QVariant();
}
//---------------------------------------------------------------------------------------------------------//
bool CResultTableModel::insertRows(int position, int /*rows*/, const QModelIndex &parent)
{
// CResultTableItem *parentItem = getItem(parent);
// bool success;
// beginInsertRows(parent, position, position);
// success = parentItem->insertChild(position);
// endInsertRows();
// return success;
}
//---------------------------------------------------------------------------------------------------------//
QModelIndex CResultTableModel::index(int row, int column, const QModelIndex &parent) const
{
// if (parent.isValid() && parent.column() != 0) return QModelIndex();
// CResultTableParent *parentItem = getItem(parent);
//CResultTableChild *childItem = parentItem->child(row);
//if (childItem) return createIndex(row, column, childItem);
//return QModelIndex();
}
//---------------------------------------------------------------------------------------------------------//
QModelIndex CResultTableModel::parent(const QModelIndex &index) const
{
// if (!index.isValid()) return QModelIndex();
// CResultTableItem *childItem = getItem(index);
// CResultTableParent *parentItem = childItem->parent();
// if (parentItem == rootItem) return QModelIndex();
// return createIndex(parentItem->childNumber(), 0, parentItem);
}
//---------------------------------------------------------------------------------------------------------//
int CResultTableModel::rowCount(const QModelIndex &parent) const
{
//CResultTableItem *parentItem = getItem(parent);
// return parentItem->childCount();
}
//---------------------------------------------------------------------------------------------------------//
bool CResultTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
//if (role != Qt::DisplayRole) return false;
//CResultTableItem *item = getItem(index);
//return item->setData(index.column(), value);
}
//---------------------------------------------------------------------------------------------------------//
Я тож долго соображал (до сих пор соображаю еще).
Вот, может пригодится это обсуждение: 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;
};
virtual int columnCount() const = 0;
virtual QVariant data(int column) const = 0;
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();
}
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();
}
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;
};
....
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()) {
...
}
...
по поводу рисования смотри в сторону QItemDelegate
kuzulis, все, идею понял, супер!... Только не мог бы ты подсказать насчет кода функций index/parent/rowCount плиз?)
QModelIndex CoreTreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (this->rootNode && this->hasIndex(row, column, parent)) {
BaseNode *parentNode = (parent.isValid()) ?
(static_cast<BaseNode *>(parent.internalPointer())) : (this->rootNode);
if (parentNode) {
BaseNode *childNode = parentNode->child(row);
if (childNode)
return createIndex(row, column, childNode);
}
}
return QModelIndex();
}
QModelIndex CoreTreeModel::parent(const QModelIndex &index) const
{
if (this->rootNode && index.isValid()) {
BaseNode *childNode = static_cast<BaseNode *>(index.internalPointer());
if (childNode) {
BaseNode *parentNode = childNode->parent();
if (parentNode != this->rootNode)
return this->createIndex(parentNode->row(), 0, parentNode);
}
}
return QModelIndex();
}
int CoreTreeModel::rowCount(const QModelIndex &parent) const
{
if (this->rootNode && (parent.column() <= 0)) {
BaseNode *parentNode = (parent.isValid()) ?
(static_cast<BaseNode *>(parent.internalPointer())) : (this->rootNode);
return parentNode->childCount();
}
return 0;
}
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)