Russian Qt Forum

Qt => Базы данных => Тема начата: -=QT=- от Март 30, 2007, 08:33



Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Март 30, 2007, 08:33
QSqlTreeViewModel всем миром. (или покажем торллям что нам нужно...)
Выкладываю начало своих размышлений о полете над гранатом или тому подобным изделием за минуту до взрыва..... :)

Код:
#ifndef QSQLTREEVIEWMODEL_H
#define QSQLTREEVIEWMODEL_H
//
#include <QStandartItemModel>
#include <QSqlQuery>

//
class QSqlTreeViewModel : public QStandartItemModel
{
Q_OBJECT

public:
QSqlTreeViewModel( QString tableName, QString primaryFieldName, QString parentFieldName, int id = 0, QObject *parent = 0 );    
virtual ~QSqlTreeViewModel();
   
    void init( int id, QModelIndex parent = QModelIndex() );
       
private:  
    QString  primaryFieldName;
    QString  parentFieldName;
    QString  tableName;
    int primaryFieldNo;
};
#endif
#include "qsqltreeviewmodel.h"

//
QSqlTreeViewModel::QSqlTreeViewModel(QString tableName, QString primaryFieldName, QString parentFieldName, int id, QObject *parent)
        : QStandartItemModel()
{
    QSqlTreeViewModel::primaryFieldName.clear();
    QSqlTreeViewModel::primaryFieldName.append(primaryFieldName);

    QSqlTreeViewModel::parentFieldName.clear();
    QSqlTreeViewModel::parentFieldName.append(parentFieldName);

    QSqlTreeViewModel::tableName.clear();
    QSqlTreeViewModel::tableName.append(tableName);
   
    QModelIndex item=index(0,0);
    //
    QSqlQuery query;
    query.prepare( QString("SELECT %1 FROM %2 WHERE %3 = %4")
                   .arg(QSqlTreeViewModel::primaryFieldName)
                   .arg(QSqlTreeViewModel::tableName)
                   .arg(QSqlTreeViewModel::parentFieldName)
                   .arg(id) );
    query.exec();

    QSqlTreeViewModel::primaryFieldNo = query.record().indexOf(QSqlTreeViewModel::primaryFieldName);

    if (query.next())
        QSqlTreeViewModel::init(query.value(QSqlTreeViewModel::primaryFieldNo).toInt(), item);
    //
}
//
QSqlTreeViewModel::~QSqlTreeViewModel()
{}
//
void QSqlTreeViewModel::init(int id, QModelIndex parent)
{
    QSqlQuery query(QString("SELECT * FROM %1 WHERE %2 = %3")
                    .arg(QSqlTreeViewModel::tableName)
                    .arg(QSqlTreeViewModel::primaryFieldName)
                    .arg(id));
    query.exec();

    int fieldNo = query.record().indexOf(QSqlTreeViewModel::primaryFieldName);

    QModelIndex item;
    if (query.next())
    {


Сейчас пишу далее Все Ваши мнения будут очень полезны, не только мне но и сообществу QT тоже, заранее всем спасибо.


Название: QSqlTreeViewModel всем миром.
Отправлено: SABROG от Март 30, 2007, 08:41
А в чем задача такой модели ? Как должна выглядеть структура таблицы/таблиц, чтобы выстроить дерево ?


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Март 30, 2007, 08:53
ИТОГО
Таблица с данными имеющими древовидную структуру описывается следующей закономерностью:
ID- он же первичный ключ
P_ID - ключ указатель на родителя(если родитель отсутствует то это первичная ветвь в нашем случае по умолчанию id=0)
Все остальные поля таблицы произвольного типа и размера.

Этот класс (то есть модель) не должна иметь привязку к какойто определенной таблице а использоваться универсально.

добавлено спустя 2 минуты:

 Задача модели:
1. Предоставлять реализацию отображения данных
2. Возможность редактирования данных


Название: QSqlTreeViewModel всем миром.
Отправлено: SABROG от Март 30, 2007, 09:05
Это некий аналог QSqlRelationalTableModel ? Только вместо комбобоксиков с данными из другой таблицы будут дочерние узлы ?


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Март 30, 2007, 12:31
Цитата: "SABROG"
Это некий аналог QSqlRelationalTableModel ? Только вместо комбобоксиков с данными из другой таблицы будут дочерние узлы ?
Ну типа да, только не QSqlRelationalTableModel а QSqlTableModel

добавлено спустя 1 час 8 минут:

 Добавляю код, полученный в результате спаривания клеток головного мозга вашего покорного слуги....

qsqltreeviewmodel.h
Код:
#ifndef QSQLTREEVIEWMODEL_H
#define QSQLTREEVIEWMODEL_H
//
#include <QStandartItemModel>
#include <QSqlQuery>

//
class QSqlTreeViewModel : public QStandartItemModel
{
Q_OBJECT

public:
QSqlTreeViewModel( QString tableName, QString primaryFieldName, QString parentFieldName, int id = 0, QObject *parent = 0 );    
virtual ~QSqlTreeViewModel();
   
    void init( int id, QModelIndex parent = QModelIndex() );
       
private:  
    QString  primaryFieldName;
    QString  parentFieldName;
    QString  tableName;
    int primaryFieldNo;
};
#endif

qsqltreeviewmodel.cpp
Код:
#include "qsqltreeviewmodel.h"

#define START_FIELD_SETDATA          2
#define NO_USED_SYSTEM_FIELD       2
//
QSqlTreeViewModel::QSqlTreeViewModel(QString tableName, QString primaryFieldName, QString parentFieldName, int id, QObject *parent)
        : QStandartItemModel()
{
    QSqlTreeViewModel::primaryFieldName.clear();
    QSqlTreeViewModel::primaryFieldName.append(primaryFieldName);

    QSqlTreeViewModel::parentFieldName.clear();
    QSqlTreeViewModel::parentFieldName.append(parentFieldName);

    QSqlTreeViewModel::tableName.clear();
    QSqlTreeViewModel::tableName.append(tableName);

    QModelIndex item=index(0,0);
    //
    QSqlQuery query;
    query.prepare( QString("SELECT %1 FROM %2 WHERE %3 = %4")
                   .arg(QSqlTreeViewModel::primaryFieldName)
                   .arg(QSqlTreeViewModel::tableName)
                   .arg(QSqlTreeViewModel::parentFieldName)
                   .arg(id) );
    query.exec();

    QSqlTreeViewModel::primaryFieldNo = query.record().indexOf(QSqlTreeViewModel::primaryFieldName);

    if (query.next())
        QSqlTreeViewModel::init(query.value(QSqlTreeViewModel::primaryFieldNo).toInt(), item);
    //
}
//
QSqlTreeViewModel::~QSqlTreeViewModel()
{}
//
void QSqlTreeViewModel::init(int id, QModelIndex parent)
{
    QSqlQuery query(QString("SELECT * FROM %1 WHERE %2 = %3")
                    .arg(QSqlTreeViewModel::tableName)
                    .arg(QSqlTreeViewModel::primaryFieldName)
                    .arg(id));
    query.exec();

    int fieldNo = query.record().indexOf(QSqlTreeViewModel::primaryFieldName);
    int countField = query.count();

    QSqlTreeViewModel::insertColumns(0, (countField-NO_USED_SYSTEM_FIELD), parent);

    QModelIndex item;
    if (query.next())
    {

        QSqlTreeViewModel::insertRow(QSqlTreeViewModel::rowCount(parent), parent);

        int fieldNoSetData = START_FIELD_SETDATA;
        while (fieldNoSetData <= countField)
        {
            item=index(rowCount(parent)-1, fieldNoSetData, parent);
            setData(item, query.value(fieldNoSetData-1));
            fieldNoSetData += 1;
        }
        QSqlQuery query;
        query.prepare( QString("SELECT %1 FROM %2 WHERE %3 = %4")
                       .arg(QSqlTreeViewModel::primaryFieldName)
                       .arg(QSqlTreeViewModel::tableName)
                       .arg(QSqlTreeViewModel::parentFieldName)
                       .arg(id) );
        query.exec();
        if (query.next())
        {
            QSqlTreeViewModel::insertColumns(0, (countField-NO_USED_SYSTEM_FIELD), item);
            do
            {
                init(query.value(QSqlTreeViewModel::primaryFieldNo).toInt(), item);
            }
            while (query.next());
        }
    }
}
//

Господа Товарищи и просто Друзья пробуйте пишите звоните бейте ногами начинается самое интересное доработка наполнение и прочие прелести программирования.
Если что не так пишите не стесняйтесь. Постараюсь всем уделить время.[/code]

добавлено спустя 2 часа 2 минуты:

 Кое что изменил скоро протестирую и выложу. Потому как предидущие версии не тестировались а сразу из текстового редактора...
НЕВИЖУОЖИВЛЕНИЯ (ведь тема на мой взгляд интересная)


Название: QSqlTreeViewModel всем миром.
Отправлено: Tonal от Март 30, 2007, 16:27
Я вообще против примитивных дата-биндингов.
Нахлебался в delphi по самое нихочу!
ORM-ы рулят!
А по ним модельки лепятся на раз. ;-)


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Март 31, 2007, 10:29
Цитата: "Tonal"
Я вообще против примитивных дата-биндингов.
Нахлебался в delphi по самое нихочу!
ORM-ы рулят!
А по ним модельки лепятся на раз. ;-)

Вот я и не хочу примитивизма, хочу универсальности и расширяемости и если Вы имеете собственный взгляд на эту проблему с конкретным направлением решени то я с большим удовольствием выслушаю Ваше мнение, мои познания в QT на сегодняшний день небольшие, а С++ изучал еще в институте, а после этого ним не пользовался до последнего времени.

добавлено спустя 5 минут:

 Кстати, вчера попытался ЭТО запустить, после некоторого шуршания напильником и уборку багов :mrgreen: получил работоспособную версию с небольшими недоделками, сегодня выложу файлы на www::webfile->ru.

добавлено спустя 3 минуты:

 В догонку (Tonal):
ORM — (англ. Object-relational mapping) технология в программировании, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая (как результат) «виртуальную объектную базу данных». Существуют как коммерческие, так и бесплатные реализации этой технологии.
А чем наша идея отличается от вышенаписанного?


Название: QSqlTreeViewModel всем миром.
Отправлено: SABROG от Март 31, 2007, 11:01
А почему бы просто не унаследоваться от QSqlRelationalDelegate или модифицировать его для троллей, чтобы поддерживал представление treeview ?


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Март 31, 2007, 11:17
Исхдный текст:
The QSqlRelationalDelegate class provides a delegate that is used to display and edit data from a QSqlRelationalTableModel.
Перевод:
Класс QSqlRelationalDelegate обеспечивает делегата, который используется, чтобы показать и редактировать данные из QSqlRelationalTableModel.
А в итоге нуден класс подобный QSqlTableModel, но только для древовидной структуры отображения. 8)

добавлено спустя 2 минуты:

 Хотя я могу ошибаться,  :D .
Разрешением наших проблем может стать только работающий пример в данной области.


Название: QSqlTreeViewModel всем миром.
Отправлено: SABROG от Март 31, 2007, 11:18
А можно скрины как это вообще выглядит ?


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Март 31, 2007, 11:42
Скрины в студию:
Тут что загрузки файлов нет класно да понимаеш....

http://slil.ru/24163349
(http://slil.ru/24163349)


Название: QSqlTreeViewModel всем миром.
Отправлено: SABROG от Март 31, 2007, 11:56
О,  так будет поинтереснее ;)

А как выглядит таблица для такого дерева ?
(http://img177.imageshack.us/img177/6441/image1xr6.gif)


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Март 31, 2007, 13:14
Таблица типа так:

ID      P_ID         NAMEJOB                  NUMJOB       TIMEJOB
1         0          Переноска воды              1                0,03
2         1          Взять емкость...               1                0,01
3         1          Принести.....                    1                0,02
4         0          Утрамбовка воздуха       10               456,00

ID       - первичны индекс (автоинкремент)
P_ID   - ссылка на родительсский индекс у начальных ветвей он - 0


Название: QSqlTreeViewModel всем миром.
Отправлено: SABROG от Март 31, 2007, 14:58
А так будет выглядить дерево из 3 веток ?

Код:

1 0 Parent
2 1 Child
3 2 Child of child


Соответственно, чтобы найти корневой элемент ребенка в базе надо будет сделать запрос по каждому предыдущему элементу выцепляя родительские индексы, пока он не станет 0 ?


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Март 31, 2007, 15:10
Ну да. Так и есть.


Название: QSqlTreeViewModel всем миром.
Отправлено: crossly от Март 31, 2007, 18:19
ну рабяты.... вещь интересная... но для для своих целей я уже её реализовал...


Название: QSqlTreeViewModel всем миром.
Отправлено: Tonal от Март 31, 2007, 19:51
Цитата: "-=QT=-"
ORM — (англ. Object-relational mapping) технология в программировании, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая (как результат) «виртуальную объектную базу данных». Существуют как коммерческие, так и бесплатные реализации этой технологии.
А чем наша идея отличается от вышенаписанного?

Тем, с чем ты при написании кода оперируешь.
В случае ОРМ-а в коде ты оперируешь с объектами предметной области и их множествами (списками, деревьями, графами...).
В случае с SQL-моделями, оперируешь SQL-запросами, а объекты как бы и не появляются вовсе.

С объектами и их множествами какие надо модели пишутся легко.
Код явно можно разделить на собственно бизнес процессы, работу с сохранением/восстановлением, отображение.
И т.д. и т.п. Берём любую агитку по ООП и проникаемся. ;-)


Название: QSqlTreeViewModel всем миром.
Отправлено: SABROG от Апрель 01, 2007, 23:50
И все-таки модель выходит зависимой от структуры таблицы. А раз так я предлагаю добавить еще одну колонку - Type, и сделать ее varcharом. Тогда можно будет отличать ветки и способ их обработки через тип. Например следующая таблица:

Код:

1       0       "TypeRoot"        "Магазин"     "Кристалл"
2       1       "TypeGoods"       "Товары"      ""
3       2       "TypeBeer"        "Пиво"        ""
4       3       "TypeMark"        "Балтика№9"   "22рубля"
5       3       "TypeMark"        "Балтика№3"   "20рублей"


Берем название каждого типа и регестрируем его в программе:

Код:

qRegisterMetaType<MyTypeClassOrStructure>(QLatin1String("MyTypeFromBase").latin1());


Присваиваем каждой ячейке свой тип:

Код:

                            MyTypeStruc *mt = new MyTypeStruc;
                                                mt->id = BeerBarcode;
                                                mt->str = "Note";
                                                QStandardItem *item = new QStandardItem();
                                                item->setData(Text,Qt::DisplayRole);
                                                QVariant gh;
                                                gh.setValue(*mt);
                                                item->setData(gh,Qt::UserRole);
                                                model->setData(index, gh );



Можно проделегировать каждую ячейку под свой тип:

Код:

QWidget *TypeDelegate::createEditor(QWidget *parent,
    const QStyleOptionViewItem & option ,
    const QModelIndex & index ) const
{
        QVariant originalValue = index.model()->data(index, Qt::UserRole);
            else if ( originalValue.canConvert<MyTypeStruc>() )
            {
            QPushButton *button = new QPushButton(parent);
            button->setMaximumWidth(16);
            button->setText("...");
            connect(button, SIGNAL(activated(int)), this, SLOT(emitCommitData()));
            return button;
            }
}


В итоге мы будем точно знать какие данные в каких ячейках, как их обрабатывать какой интерфейс к каким данным предоставлять. Например если это BLOB поле с определенным типом, скажем Video, Audio, Picture, то мы сможем к каждому из таких типов привязать свою кнопочку с интерфейсом, который будет это обрабатывать.

добавлено спустя 6 минут:

 Только что-то мне подсказывает, что мы в итоге придем к Value Browserу
http://www.qt-apps.org/content/show.php/Value+Browser?content=50717


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Апрель 02, 2007, 08:45
Изучаю все вышесказанное, курю маны. Спасибо за ссылку, очень интересный материал.


Название: QSqlTreeViewModel всем миром.
Отправлено: Вячеслав от Апрель 02, 2007, 15:45
2 -=QT=- вопросец однако
Код:

        query.prepare( QString("SELECT %1 FROM %2 WHERE %3 = %4")
                       .arg(QSqlTreeViewModel::primaryFieldName)
                       .arg(QSqlTreeViewModel::tableName)
                       .arg(QSqlTreeViewModel::parentFieldName)
                       .arg(id) );

А нафига каждый раз-то prepare дергать ? при прямом форматировании проще в exec сразу все сунуть ....


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Апрель 03, 2007, 07:44
Цитата: "Вячеслав"
2 -=QT=- вопросец однако
Код:

        query.prepare( QString("SELECT %1 FROM %2 WHERE %3 = %4")
                       .arg(QSqlTreeViewModel::primaryFieldName)
                       .arg(QSqlTreeViewModel::tableName)
                       .arg(QSqlTreeViewModel::parentFieldName)
                       .arg(id) );

А нафига каждый раз-то prepare дергать ? при прямом форматировании проще в exec сразу все сунуть ....


Привычка...

добавлено спустя 6 минут:

 Непонимаю я ничего в этом тривью .... А-а-а-а-а-а-а-а-а-а-а-.......
Ну бросте какой нить пример хоть кусок а.??????
А то я когонибуть невинного порву на кучу медвежат уууууууюююююю.....
Ну не может быть в это ничего сложного но меня переклинило.....
HELP HELP


Название: QSqlTreeViewModel всем миром.
Отправлено: Georgest от Апрель 08, 2007, 21:28
Цитировать
Непонимаю я ничего в этом тривью .... А-а-а-а-а-а-а-а-а-а-а-.......
Ну бросте какой нить пример хоть кусок а.??????
А то я когонибуть невинного порву на кучу медвежат уууууууюююююю.....
Ну не может быть в это ничего сложного но меня переклинило.....
HELP HELP


В Qt есть модель QDirModel, которая стыкуется с QTreeView.
Надо понимать, что хороший QSqlTreeModel можно слизать с этого самого QDirModel (файл src/gui/itemviews/qdirmodel.h и .cpp).
Ключевые методы: rowCount, columnCount, data, setData, headerData,
hasChildren, flags.


Название: QSqlTreeViewModel всем миром.
Отправлено: Вячеслав от Апрель 08, 2007, 22:37
Цитата: "-=QT=-"
Цитата: "Вячеслав"
2 -=QT=- вопросец однако
Код:

        query.prepare( QString("SELECT %1 FROM %2 WHERE %3 = %4")
                       .arg(QSqlTreeViewModel::primaryFieldName)
                       .arg(QSqlTreeViewModel::tableName)
                       .arg(QSqlTreeViewModel::parentFieldName)
                       .arg(id) );

А нафига каждый раз-то prepare дергать ? при прямом форматировании проще в exec сразу все сунуть ....


Привычка...

Несколько фиговая привычка - если сделан prepare - то правильнее и быстрее прокинуть параметры через bind .... А какие грабли с treeview-то ?


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Апрель 09, 2007, 11:25
Цитировать
Несколько фиговая привычка - если сделан prepare - то правильнее и быстрее прокинуть параметры через bind .... А какие грабли с treeview-то ?

Возможно что и плохая я с SQL серверами раньше не работал. Только изучаю, спасибо за подсказку. А с тривью проблема - не понимаю что нужно наследовать и какие методы и свойства необходимо наследовать для правильного использования. Спасибо (Georgest) поизучаю его подсказку.


Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Апрель 12, 2007, 13:07
В общем поматырился я неделю, а может и более и перепрыгнул с QTreeView на QTreeWidget & QTreeWidgetItem.
Все рисуется как нужно, вот только как будет работать с большими обьемами не знаю еще. По крайней мере буду вводить ограничения по каким то условиям. Смотрел код, который в QT по sqlmodel  sqltablemodel там такого понапихано в ообщем еще осталось желание, но нет пока времени, так что все еще в переди.
Модель которую я получил выводила итемы в тривью но без иерархии, а потом еще вопросы связывания с БД и т.п. все в сыром виде, как закончу или получу промежуточную рабочую версию обязательно опубликую.


Название: QSqlTreeViewModel всем миром.
Отправлено: SABROG от Апрель 13, 2007, 17:22
А че ты матырился ? Вот так работать с modelью можно:

Код:

        QStandardItemModel *model = new QStandardItemModel;
        model->setColumnCount(2);

        model->setHeaderData(0, Qt::Horizontal, tr("Key"));
        model->setHeaderData(1, Qt::Horizontal, tr("Value"));

        TreeView1->setModel(model);

        QStandardItem *Root1 = new QStandardItem("Root1");
        QVariant itemData = 1; // для теста присвоим значение 1
        Root1->setData(itemData, Qt::UserRole); // и установим его в итем
        model->setItem(0,0,Root1); // первая строка, первая колонка

        QStandardItem *ChdRoot1 = new QStandardItem("Child of Root1"); // создадим дочерний элемент
        itemData = 2;
        ChdRoot1->setData(itemData, Qt::UserRole);
        Root1->setChild(0,0,ChdRoot1); // установим ребенка в первую строку, первую колонку родительского элемента (не глобальной модели!)

        QStandardItem *ChdValue1 = new QStandardItem("Value of Child");
        itemData = 3;
        ChdValue1->setData(itemData, Qt::UserRole);
        Root1->setChild(0,1,ChdValue1); // установим ребенка во вторую колонку, первой строки для родителя



Название: QSqlTreeViewModel всем миром.
Отправлено: -=QT=- от Апрель 16, 2007, 14:15
Для отображения вот ....
Код:
void SqlTreeModel::refreshAllString(int id, QStandardItem *parent)
{
    QSqlQuery q;
    if (id==-1)
        id = 0;
    q.exec(QString("SELECT * FROM %1 WHERE %2=%3").arg(tableName).arg(parentFieldName).arg(id));

    while ( q.next())
    {
        QStandardItem *item = new QStandardItem(q.value(2).toString());
        QList<QStandardItem *> itemColumn;
        itemColumn << item;
        if (q.record().count()>2)
        {
            for (int i=3; i<q.record().count(); ++i)
            {
                QStandardItem *columnItem = new QStandardItem(q.value(i).toString());
                itemColumn << columnItem;
            }
        }
        parent->appendRow(itemColumn);
        refreshAllString(q.value(q.record().indexOf(primaryFieldName)).toInt(), item);
    }
}
Потом нужно еще реализовывать редактирование и все такое ....

добавлено спустя 4 минуты:

 Но хочется сделать от абстрактной модели данных.
-------------------
Код
C++ (Qt)
#ifndef TREEMODEL_H
#define TREEMODEL_H
 
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
 
class TreeItem;
 
class TreeModel : public QAbstractItemModel
{
   Q_OBJECT
 
public:
   TreeModel(const QString &table, QObject *parent = 0);
   ~TreeModel();
 
   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;
 
   QString  primaryFieldName;
   QString  parentFieldName;
   QString  tableName;
 
private:
   //void setupModelData();
   void init(int id = 0,  TreeItem *parent = 0);
   void setupFieldName(const QString &table, const QString  primaryFieldName = "ID", const QString  parentFieldName = "P_ID");
 
 
   TreeItem *rootItem;
};
 
#endif
-------------------
#include <QtGui>
#include <QtSql>
 
#include "treeitem.h"
#include "treemodel.h"
 
#define DEFAULT_PRIMARY_FIELD_NAME    "ID"
#define DEFAULT_PARENT_FIELD_NAME    "P_ID"
 
TreeModel::TreeModel(const QString &table, QObject *parent)
       : QAbstractItemModel(parent)
{
   setupFieldName(table);
  // setupModelData();
}
//
TreeModel::~TreeModel()
{
   delete rootItem;
}
//
int TreeModel::columnCount(const QModelIndex &parent) const
{
   if (parent.isValid())
       return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
   else
       return rootItem->columnCount();
}
//
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
   if (!index.isValid())
       return QVariant();
 
   if (role != Qt::DisplayRole)
       return QVariant();
 
   TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
 
   return item->data(index.column());
}
//
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
   if (!index.isValid())
       return Qt::ItemIsEnabled;
 
   return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
//
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
                              int role) const
{
   if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
       return rootItem->data(section);
 
   return QVariant();
}
//
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
const
{
   TreeItem *parentItem;
 
   if (!parent.isValid())
       parentItem = rootItem;
   else
       parentItem = static_cast<TreeItem*>(parent.internalPointer());
 
   TreeItem *childItem = parentItem->child(row);
   if (childItem)
       return createIndex(row, column, childItem);
   else
       return QModelIndex();
}
//
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
   if (!index.isValid())
       return QModelIndex();
 
   TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
   TreeItem *parentItem = childItem->parent();
 
   if (parentItem == rootItem)
       return QModelIndex();
 
   return createIndex(parentItem->row(), 0, parentItem);
}
//
int TreeModel::rowCount(const QModelIndex &parent) const
{
   TreeItem *parentItem;
 
   if (!parent.isValid())
       parentItem = rootItem;
   else
       parentItem = static_cast<TreeItem*>(parent.internalPointer());
 
   return parentItem->childCount();
}
// Это матырства моего мозга
//----------------------------------------------------------------------
/*void TreeModel::setupModelData()
{
   QList<QVariant> rootData;
   rootData << "Field 1"<< "Field 2"<< "Field 3"<< "Field 4";
   rootItem = new TreeItem(rootData);
   init(0, rootItem);
 
}
//
void init(int id, TreeItem *parent)
{
   QList<TreeItem*> parents;
   parents << parent;
 
   QSqlQuery q;
   q.exec(QString("SELECT * FROM %1 WHERE %2=%3").arg(tableName).arg(parentFieldName).arg(id));
   while ( q.next())
   {
       QList<QVariant> columnData;
       if (q.record().count()>0)
       {
           for (int column=2; column<q.record().count(); column++)
           {
               columnData << q.value(column);
           }
       }
       parents.last()->appendChild(new TreeItem(columnData, parents.last()));
       init(q.value(q.record().indexOf(primaryFieldName)).toInt(), parents);
   }
}*/

//
void TreeModel::setupFieldName(const QString &table, const QString  primaryFieldN, const QString  parentFieldN )
{
   tableName.clear();
   primaryFieldName.clear();
   parentFieldName.clear();
 
   tableName.append(table);
   primaryFieldName.append(primaryFieldN);
   parentFieldName.append(parentFieldN);
 
}
//
-----------------------------------------------------
Ну в общем что-то такое наверно...


Название: Re: QSqlTreeViewModel всем миром.
Отправлено: CroCIV от Июль 23, 2009, 15:04
прикольно... щас покурю...
Задумал себе сделать тривью в которую можно было бы, например, БД КЛАДР (разумеется с соответствующей доработкой таблиц в данном случае) забадяжить, чтоб вложенность была потенциально не ограничена, чтоб дерево формировалось "на лету", т.е. по запросу пользователя (юзер ткнул на сущность "Россия", поформировался запрос по регионам россии первого уровня, обработался, результаты на ходу добавились/обновились к ветке "Россия", ветвь раскрылась, ткнул по Кировской области, ... то же самое ... , открылись субъекты Кировской области и т.д.).
Согласитесь такая компонента актуальна и применибельна много где...
Жаль что на работе мало времени этим заниматься, придется фантазии реализовывать в выходные дни.
Кто заинтересован в такой штуке поднимите руки, т.к. тут кроме коддинга есть нюанс. Коли это универсальная компонента необходимо разработать формат команды, разобрав которую наш тривью понел: 1. каки таблицы участвуют в построении дерева, в какой зависимости они находятся 2. какие поля таблиц необходимо использовать как связь с родительским эл.том, а какие поля необходимо отображать .. ну и еще че нибудь.


Название: Re: QSqlTreeViewModel всем миром.
Отправлено: oxotnik от Июль 23, 2009, 15:29
составлял TreeWiget таким образом:
из БД делал запрос:

Код
C++ (Qt)
void CDataBase::GetData(map<int, pair<int, QString> > &nodesData)
{
if (!database->isOpen())
return ;
QSqlQueryModel model;
model.setQuery("SELECT * FROM [nodes] ORDER BY node_id");
// ВАЖНО: обязательна сортировка по ID - узла, т.к. после будет один линейный проход
// и для каждого последующего узла выше в таблице должен существовать родитель
for (long i = 0; i < model.rowCount(); i++)
nodesData[model.data(model.index(i, 0)).toInt()] =
make_pair(model.data(model.index(i, 1)).toInt(), model.data(model.index(i, 2)).toString());
}

прорисовка узлов:

Код
C++ (Qt)
void MainWindow::CreateTreeView (void)
{
map<int, pair<int, QString> >nodesData;
base->GetData(nodesData);
treeView = ui->treeWidget;
map <int, pair<int, QString> >::iterator iIter;
map<int, QTreeWidgetItem* >treeItems;
treeView->blockSignals(true);
for (iIter = nodesData.begin(); iIter != nodesData.end(); iIter++)
{
int k = iIter->first;
QTreeWidgetItem *item;
if (iIter->second.first == 0) // root node
{
item = new QTreeWidgetItem(treeView);
item->setText(0, iIter->second.second);
}
else
{
item = new QTreeWidgetItem(treeItems[iIter->second.first]);
item->setText(0, iIter->second.second);
}
item->setData(1, 1, iIter->first);
treeItems[k] = item;
}
treeView->blockSignals(false);
}
скорость очень зависит от драйвера БД
Через ADO в VCL 100 000 узлов рисуются ~2.5 минуты
тот же самый алгоритм в дотнете рисует < 30 сек те же 100 000 узлов
Скорость в QT не проверял, но думаю будет сравнима с VCL

Под QTreeView его можно переписать подобным образом, но с учетом модели, где узлы заменятся на Q*ItemModel для которого есть все возможности указывать родителя и детей.


Название: Re: QSqlTreeViewModel всем миром.
Отправлено: miha-ha от Август 07, 2009, 08:16
Нет необходимости загружать все данные сразу!
Их необходимо загружать по мере надобности!
При разворачивании ветки получить из БД всех потомков и показать и т.д. тогда не нужно будут ждать и 30 сек.


Название: Re: QSqlTreeViewModel всем миром.
Отправлено: FantasyOR от Январь 23, 2012, 16:40
а где можно скачать это чудо?


Название: Re: QSqlTreeViewModel всем миром.
Отправлено: alexpux от Июнь 18, 2012, 22:15
Смотрю в теме уже давно никто не пишет, но все-таки попробую внести свою лепту в общее дело.
Я новичок в Qt, поэтому не судите строго. Сейчас пишу SqlTreeModel для работы с базой Firebird. В аттаче архивчик с тестовой программкой. Она еще сырая. Если есть у кого какие мысли по написанной модели не стесняйтесь :D


Название: Re: QSqlTreeViewModel всем миром.
Отправлено: RVZ от Июнь 20, 2012, 16:07
Всем доброго времени суток.
Разместил свои труды здесь - http://www.prog.org.ru/topic_21981_0.html
Очень хочется для методов data и columnCount тянуть необходимые значения прям из базы по мере необходимости но вивка очень часто их опрашивает  ??? (даже просто при подведении курсора).
может кто подскажит пример или способ как снизить колличество вызовов этих методов.
Заранее всем спасибо.


Название: Re: QSqlTreeViewModel всем миром.
Отправлено: Bepec от Июнь 20, 2012, 16:22
Кешировать.


Название: Re: QSqlTreeViewModel всем миром.
Отправлено: panAlexey от Июнь 20, 2012, 16:44
А в чем задача такой модели ? Как должна выглядеть структура таблицы/таблиц, чтобы выстроить дерево ?
Помоему пофигу как должна она выглядеть.
При создании можели можно параметризовать типа:
setIdentFielsd(QString& idCol, QString& idParentCol, QString& idNull);
И все.
Первым параметром задается поле идентификатора,
Вторым поле типа парентИд.
Третим представление пустого парента.
И хватит с головой думаю.