Russian Qt Forum
Октябрь 01, 2024, 10:28 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QAbstractItemModel - index и parent  (Прочитано 12574 раз)
spbcypher
Гость
« : Август 19, 2010, 15:18 »

пример из Johan Thelin - Foundations of QT Development[2007]

Код:
QModelIndex ObjectTreeModel::index(int row, int column, const QModelIndex &parent ) const
{
QObject *parentObject;
if( !parent.isValid() )
parentObject = m_root;
else
parentObject = static_cast<QObject*>( parent.internalPointer() );
if( row >= 0 && row < parentObject->children().count() )
return createIndex( row, column, parentObject->children().at( row ) );
else
return QModelIndex();
}

подскажите пожалуйста как организовать функцию index если данные разного уровня вложенности в древовидной модели имеют разные типы и нет единого родительского элемента?

т.е. структура данных приблизительно следующая

марка: [id title]
  модель: [id title]
    двигатель: [id kw year и пр.]
    двигатель
  модель
  ....
марка
  ....
« Последнее редактирование: Август 19, 2010, 15:20 от spbcypher » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Август 19, 2010, 15:43 »

единый родительский элемент есть всегда - узел дерева
Записан
spbcypher
Гость
« Ответ #2 : Август 19, 2010, 17:17 »

Код:
QVariant AutoModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || !(role == Qt::EditRole || role == Qt::DisplayRole)) return QVariant();

    int level = 0;
    QModelIndex temp_index = index;
    while (temp_index.parent().isValid()) {
        level++; temp_index = temp_index.parent();
    }

    // марки автомобилей
    if (level == 0) {
        if (index.row() >= brands->count()) {
            int start = brands->count(); // с какой строки подкачивать
            int count = index.row()-brands->count()+1; // сколько строк подкачивать
            brands->append(BrandsGetDB(start,count));
        }
        if (index.row() >= brands->count()) return QVariant();
        return QVariant::fromValue(brands->at(index.row()));
    } else

    // модели автомобилей
    if (level == 1) {
        int brand_id = brands->at(index.parent().row()).id;
        if (index.row() >= models->take(brand_id).count()) {
            int start = models->take(brand_id).count(); // с какой строки подкачивать
            int count = index.row()-models->take(brand_id).count()+1; // сколько строк подкачивать
            models->take(brand_id).append(ModelsGetDB(start,count,brand_id));
        }
        if (index.row() >= models->take(brand_id).count()) return QVariant();
        return QVariant::fromValue(models->take(brand_id).at(index.row()));
    }
}

Если наследовать класс AutoModel от QAbstractListModel, то выдаётся только первый уровень (марки), второй (модели) выдаёт false на index.isValid()

данные по логике приложения хранятся в следующих структурах


Код:
namespace AUTO
{
    struct Brand {
        int id;
        QString name;
    };
    struct Model {
        int id;
        QString name;
    };
    struct Engine {
        int id;
        QString name;
        int KW;
    };
}

typedef QList<AUTO::Model> QListModels;
typedef QList<AUTO::Engine> QListEngines;

brands = new QList<AUTO::Brand>;
models = new QMap<int,QListModels>;
engines = new QMap<int,QListEngines>;

подскажите пожалуйста где ошибка и как в данном случае с индексами оперировать?  Непонимающий

UPD: логика приложения подразумевает подкачку с базы при отсутсвии данных
« Последнее редактирование: Август 19, 2010, 17:30 от spbcypher » Записан
fuCtor
Гость
« Ответ #3 : Август 19, 2010, 19:34 »

Как вариант завести вспомогательную структуру, которая будет строить дерево, т.е. содержать массив потомков и указатель на родителя.
Так же узел содержит тип узла и идентификатор объекта этого узла.
Таким образом можно грузить разнородные данные в виде дерева.

При создании индекса проверяете тип родителя и принимаете решение потомков какого типа порождать.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Август 19, 2010, 20:29 »

в случае, если индексы на разных уровнях хранят разные данные напрямую, нужно как-то различать эти индексы. В голову приходит: метод level который поднимается по парентам и высчитывает глубину; хранение типа в каждой структуре и выцепление по оффсету/каст к интерфейсу общему для структур. Оба способа кривые, посему надо делать как сказал fuCtor:
struct Node { Node *parent, QList<Node*> children; int type; void *data; }
Собственно дерево модели строится из нодов, а данные нод содержит исходя из своего типа.
Записан
fuCtor
Гость
« Ответ #5 : Август 19, 2010, 20:47 »

Еще замечу, что если данные хранятся в БД, то строить все дерево сразу нет необходимости. На каждом этапе только достраивается тот участок, что требуется, таким образом экономия времени на запросах. Некоторые запросы можно кешировать в узлах (например количество потомков, которые могут быть потом загружены).
Записан
spbcypher
Гость
« Ответ #6 : Август 19, 2010, 22:36 »

Q_DECLARE_METATYPE не позволяет определять тип из структуры с конструктором Грустный
в итоге перед передачей в метод setData нужно засунуть в обычную с полем-типом, а внутри засовывать в структуру дерева с конструктором, чтобы инициализировать указатели на связанные объекты..матрёшка, блин
Записан
fuCtor
Гость
« Ответ #7 : Август 20, 2010, 06:45 »

а зачем регистрировать тип? вы его куда засовывать собираетесь?

Индекс строится методом createIndex(строка, столбец, int|void*) и ни надо никаких мета типов.
Потом просто получаете указатель index.innerPointer(), кастуете к своей структуре и будет вам счастье.
Записан
spbcypher
Гость
« Ответ #8 : Август 20, 2010, 10:22 »

а метод setData, внутри него уже будет QVariant который надо будет как-то распознать что это - в конкретной ситуации марка, модель или двигатель
Записан
Maquefel
Гость
« Ответ #9 : Август 20, 2010, 12:00 »

а метод setData, внутри него уже будет QVariant который надо будет как-то распознать что это - в конкретной ситуации марка, модель или двигатель

Полиморфизм тебе в помощь:
Код:
enum TreeItemTypes {
    Root, Mark, Model
};

class TreeItem : public QObject
{
    Q_OBJECT
public:
// LIFECYCLE
   /** Default constructor.
    */
   TreeItem(TreeItemTypes type, TreeItem* parent = 0);
   virtual ~EGTreeItem(void);
// OPERATORS
// OPERATIONS
// ACCESS
// INQUIRY
   virtual int subItemsCount() const {return 0;}
   virtual int childCount() const;
   virtual int columnCount() const;

   void appendChild(TreeItem* child);
   TreeItem* takeLast();

   virtual void deleteChildren();

   virtual TreeItemTypes getType() {return type;}

   TreeItem* child(int row);
   TreeItem* parent();
   virtual QVariant data(int column) const;
   int row() const;

   virtual bool setData(int column, const QVariant &value);
   virtual void expand(){;}
public slots:
protected:
   TreeItemTypes type;
   QList<TreeItem*> childItems;
   TreeItem* parentItem;
   QList<QVariant> itemData;
};

Наследуешь, от общего класса предка и переопределяешь методы, допустим для каждого своя реализация метода setData;
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #10 : Август 20, 2010, 12:54 »

ой, наследовать айтем от куобжекта, ужас...
Записан
Maquefel
Гость
« Ответ #11 : Август 20, 2010, 12:58 »

ой, наследовать айтем от куобжекта, ужас...

Почему это?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #12 : Август 20, 2010, 13:01 »

ваша модель будет весить килотонны и создаваться медленно (как минимум в 2раза медленней за счет new QObjectPrivate)
Записан
Maquefel
Гость
« Ответ #13 : Август 20, 2010, 13:07 »

ваша модель будет весить килотонны и создаваться медленно (как минимум в 2раза медленней за счет new QObjectPrivate)

а мне сигнал/слоты нужны, не нужны были бы не наследовал, это раз, во-вторых qobject_cast, который быстрее dynamic_cast.

Но в целом вы правы - в примере он не нужен.


Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #14 : Август 20, 2010, 13:14 »

а, я просто в вашем примере не увидел ни сигналов ни слотов, тогда да) + это имеет смысл если дерево маленькое а данных много и можно к ним прикрутить хитрый механизм обновления через сигналы. Однако мой опыд подсказывает что лучше всего маааленький TreeItem.
жаль в qt нет темплейт класса для деревьев
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.048 секунд. Запросов: 23.