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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [Qt 4.4.0, VS2005] Падение в QTreeView при отображении дерева из БД  (Прочитано 13390 раз)
Sergeich
Гость
« : Июнь 19, 2008, 13:26 »

Создаю SQLite базу из одной таблицы вида:
Id  | ParentId | Name
1   | 0 | Item1
2   | 1 | Item11
3   | 1 | Item12
4   | 0 | Item2

Код:
#include <QtGui>
#include <QtSql>

#include "sqltreemodel.h"

void doBranches( int id, const QString& name, int depth )
{
int d = depth - 1;
int n = qrand() % 10;
QSqlQuery query;
for ( int i = 0; i < n; i++ ) {
QString str = name + QString('1' + i);
query.exec( QString("INSERT INTO Object(ParentId, Name) VALUES(%1,'%2')").arg(id).arg(str) );
query.exec( "SELECT last_insert_rowid()" );
if ( query.first() && d ) {
int ni = query.value(0).toInt();
doBranches( ni, str, d );
}
}
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
    if (!db.open()) {
qFatal("Can't open database");
    }
QSqlQuery query;
query.exec("CREATE TABLE Object (Id integer primary key autoincrement, ParentId integer, Name varchar)");
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
doBranches( 0, "Item", 3 );
query.exec("CREATE INDEX ParentIdx ON Object(ParentId)");

SqlTreeModel model(db);
    QTreeView view;
    view.setModel(&model);
    view.setWindowTitle(QObject::tr("SQL Tree Model"));
    view.show();
    return app.exec();
}
Создаю к ней read-only модель (за основу взят пример itemviews/simpletreemodel):
Код:
#include <QtGui>
#include <QtSql>

#include "sqltreemodel.h"

// Database access functions

QVariant SqlTreeModel::getData( int id, int column ) const
{
if ( column != 0 )
return QVariant();
QSqlQuery query(db);
query.exec( QString("SELECT Name FROM Object WHERE Id = %1").arg(id) );
if ( !query.next() )
return QVariant();
return query.value(0);
}

int SqlTreeModel::getParent( int id ) const
{
QSqlQuery query(db);
query.exec( QString("SELECT ParentId FROM Object WHERE Id = %1").arg(id) );
if ( !query.next() )
return -1;
return query.value(0).toInt();
}

int SqlTreeModel::getChildCount( int parent ) const
{
QSqlQuery query(db);
query.exec( QString("SELECT count(*) FROM Object WHERE ParentId = %1").arg(parent) );
if ( !query.next() )
return 0;
int cnt = query.value(0).toInt();
return cnt;
}

int SqlTreeModel::getChild( int parent, int index ) const
{
QSqlQuery query(db);
if ( !query.exec( QString("SELECT Id FROM Object WHERE ParentId = %1 ORDER BY Id").arg(parent) ) )
return 0;
int i = 0;
while ( query.next() ) {
if ( i == index ) {
int id = query.value(0).toInt();
return id;
}
++i;
}
return 0;
}

int SqlTreeModel::getChildIndex( int parent, int child ) const
{
QSqlQuery query(db);
if ( !query.exec( QString("SELECT Id FROM Object WHERE ParentId = %1 ORDER BY Id").arg(parent) )  )
return -1;
int index = 0;
while ( query.next() ) {
int id = query.value(0).toInt();
if ( id == child )
return index;
++index;
}
return -1;
}

//---------------------------------------------------

SqlTreeModel::SqlTreeModel(QSqlDatabase database, QObject *parent)
    : db(database), QAbstractItemModel(parent)
{
}


SqlTreeModel::~SqlTreeModel()
{
}


int SqlTreeModel::columnCount(const QModelIndex &parent) const
{
return 1;
}


QVariant SqlTreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

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

return getData( index.internalId(), index.column() );
}


Qt::ItemFlags SqlTreeModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return 0;

    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

QVariant SqlTreeModel::headerData(int section, Qt::Orientation orientation,
                               int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
        return QString("Name");

    return QVariant();
}

QModelIndex SqlTreeModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    int parentId;

    if (!parent.isValid())
        parentId = 0;
    else
        parentId = parent.internalId();

    int childId = getChild(parentId, row);
    if (childId > 0)
        return createIndex(row, column, childId);
    else
        return QModelIndex();
}

QModelIndex SqlTreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    int childId = index.internalId();
    int parentId = getParent(childId);

    if (parentId <= 0)
        return QModelIndex();

int row = getChildIndex(parentId, childId);
    return createIndex(row, 0, parentId);
}

int SqlTreeModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0)
        return 0;

int parentId;
    if (!parent.isValid())
        parentId = 0;
    else
        parentId = parent.internalId();

    return getChildCount(parentId);
}
При раскрытии некоторых узлов дерева падает с ошибкой

Где я накосячил? Проект в аттаче.
« Последнее редактирование: Июнь 19, 2008, 13:28 от Sergeich » Записан
ритт
Гость
« Ответ #1 : Июнь 19, 2008, 13:34 »

SqlTreeModel::getChildIndex и SqlTreeModel::getParent могут вернуть -1
мне кажется, проблема из-за нехватки проверки возвращённого значения, например, в SqlTreeModel::parent
Код:
int row = getChildIndex(parentId, childId);
return createIndex(row, 0, parentId);
Записан
Sergeich
Гость
« Ответ #2 : Июнь 19, 2008, 18:09 »

SqlTreeModel::getChildIndex и SqlTreeModel::getParent могут вернуть -1
мне кажется, проблема из-за нехватки проверки возвращённого значения, например, в SqlTreeModel::parent
Код:
int row = getChildIndex(parentId, childId);
return createIndex(row, 0, parentId);
Да пробовал уже, не помогает. В отладчике точки прерывания на все исключительные ситуации ставил - не попадает он туда!
Записан
ритт
Гость
« Ответ #3 : Июнь 19, 2008, 18:40 »

у тебя валится в QTreeViewPrivate::layout (судя по ассерту), у меня в 4.4.0 - в QTreeView::sizeHintForColumn (и только при раскрытии дочернего списка )
собрал под 4.3.4 - полный порядок
могу посоветовать навестить трэкер Улыбающийся
Записан
Sergeich
Гость
« Ответ #4 : Июнь 19, 2008, 20:05 »

собрал под 4.3.4 - полный порядок
Неа... тоже валится, только намного реже
могу посоветовать навестить трэкер Улыбающийся
В трекере вроде такого нет. Придется писать в техподдержку.
Записан
Sergeich
Гость
« Ответ #5 : Июнь 20, 2008, 18:42 »

Письмо в техподдержку отменяется Веселый Разобрался, в чем косяк: в методе SqlTreeModel::parent неправильно вычислялся номер строки. Исправил на
Код:
QModelIndex SqlTreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();

int childId = index.internalId();
int parentId = getParent(childId);

if (!parentId)
return QModelIndex();

int row = getChildIndex(getParent(parentId), parentId);
return createIndex(row, 0, parentId );
}
и все заработало как надо Веселый
Если кому надо, прилепил исправленный код.
Записан
Sergeich
Гость
« Ответ #6 : Июнь 20, 2008, 21:27 »

Пока искал ошибку обнаружил два неприятных момента:
1. QSqlQuery::seek() не перемещается на последнюю запись запроса. Отписался троллям.
2. QTreeView все время обращается к модели, даже в paintEvent! Полный пиздец производительности!
Записан
Alex03
Гость
« Ответ #7 : Июнь 23, 2008, 06:58 »

...
2. QTreeView все время обращается к модели, даже в paintEvent! Полный пиздец производительности!
Так в этом и весь смыст что во вьюхе данных нет, все данные в модели, поэтому при паинте идёт обращение за данными к модели, тут всё нормально, а вот если модель при этом, например, лезет в БД за данными, то это уже другой вопрос.
Записан
Sergeich
Гость
« Ответ #8 : Июнь 23, 2008, 11:47 »

...
2. QTreeView все время обращается к модели, даже в paintEvent! Полный пиздец производительности!
Так в этом и весь смыст что во вьюхе данных нет, все данные в модели, поэтому при паинте идёт обращение за данными к модели, тут всё нормально, а вот если модель при этом, например, лезет в БД за данными, то это уже другой вопрос.
Вьюха может кэшировать данные, которые в данный момент отображаются, чтобы при каждой перерисовке не лезть за ними в модель. А при сигнале об изменении данных от модели можно тупо сбрасывать кэш.
Насчет того что модель каждый раз лезет в БД за данными: это просто тестовый пример, в нормальной реализации я использую кэш.
Записан
Alex03
Гость
« Ответ #9 : Июнь 23, 2008, 12:15 »

Вьюха может кэшировать данные, которые в данный момент отображаются, чтобы при каждой перерисовке не лезть за ними в модель. А при сигнале об изменении данных от модели можно тупо сбрасывать кэш.
Насчет того что модель каждый раз лезет в БД за данными: это просто тестовый пример, в нормальной реализации я использую кэш.
Почему вьюха то? Она тока отображает, на то и вьюха.
А вот модель может и кэшировать. В том числе промежуточная порождённая от QxxxxxxProxyModel.

P.S. Кстати, а чёб тролям не написать какойнить QAbstractCacheProxyModel/QStandardItemCacheProxyModel? Улыбающийся
Записан
DarkPhoenix
Гость
« Ответ #10 : Август 26, 2008, 09:07 »

Подтверждаю написанное trdm, не получается скачать, 404 ошибка.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #11 : Август 26, 2008, 10:38 »

BW, trdm попросите Sergeich в личке выложить снова
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Admin
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1988



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

после перезда ченить отвалилось - гляну
Записан
Admin
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1988



Просмотр профиля
« Ответ #13 : Август 29, 2008, 17:10 »

атачи грузятся теперь
как оказалось SMF форум не так просто в администрировании - фиг найдешь где есть что
Записан
CroCIV
Гость
« Ответ #14 : Июль 23, 2009, 15:37 »

Ням, Ням!!!  Смеющийся
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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