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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Модель на основе дерева. Странный крэш.  (Прочитано 9317 раз)
uriel
Гость
« : Октябрь 05, 2009, 18:38 »

Честно говоря, я не особо силён в MVC, так что вопрос на самом деле может оказаться крайне глупым. Поэтому заранее прощу прощения в случае чего. Улыбающийся
Пытаюсь вывести в QTreeView самопальное дерево, но программа уверенно крэшится при попытке зайти в любую дочернюю ветку. Причём, если поймать его отладчиком, то окажется, что крэшится оно в недрах самой Qt на событии отрисовки в разных местах.
В коде есть разного рода барахло, которое там только для того, чтобы "смоделировать" ситуацию максимально близко к реальным условиям.
Судя по выводу в консоль, само дерево строится нормально.
Код
C++ (Qt)
#include <QApplication>
#include <QDateTime>
#include <QAbstractItemModel>
#include <QTreeView>
#include <QDebug>
//
struct ItemInfo {
QString m_SomeStuff;
 
ItemInfo()
: m_SomeStuff("")
{
}
};
 
//
class Node;
typedef QList<Node*> QNodeList;
 
class Node {
public:
Node *m_Parent;
int m_Row;
QNodeList m_Children;
QString m_Name;
 
Node(Node *parent, int row, QString name): m_Parent(parent), m_Row(row), m_Name(name) {
}
 
void traverse(int level = 0) {
qDebug() << QString().fill(' ', level) << m_Name;
 
foreach (Node *child, m_Children)
child->traverse(level + 1);
}
};
 
class DirNode: public Node {
public:
DirNode(Node *parent, int row, QString name): Node(parent, row, name) {
}
};
 
class FileNode: public Node {
public:
ItemInfo m_Info;
 
FileNode(Node *parent, int row, QString name, ItemInfo info): Node(parent, row, name), m_Info(info) {
}
};
//
class IndexModel: public QAbstractItemModel {
private:
Node *m_RootNode;
 
inline Node* indexData(const QModelIndex &index) const {
return static_cast<Node*>(index.internalPointer());
}
 
public:
IndexModel(QObject *parent): QAbstractItemModel(parent) {
m_RootNode = new Node(0, -1, "");
Node *baseRootNode = m_RootNode;
 
m_RootNode->m_Children.append(new FileNode(m_RootNode, 0, "Bar", ItemInfo()));
 
m_RootNode->m_Children.append(new DirNode(m_RootNode, 1, "Foo"));
m_RootNode = m_RootNode->m_Children.last();
 
m_RootNode->m_Children.append(new FileNode(m_RootNode, 0, "FooBar", ItemInfo()));
 
m_RootNode->m_Children.append(new DirNode(m_RootNode, 1, "Baz"));
m_RootNode = m_RootNode->m_Children.last();
 
m_RootNode->m_Children.append(new FileNode(m_RootNode, 0, "FooBarBaz", ItemInfo()));
 
m_RootNode->m_Children.append(new DirNode(m_RootNode, 1, "Bazzz"));
 
m_RootNode = baseRootNode;
 
m_RootNode->traverse();
}
 
QModelIndex index(int row, int column, const QModelIndex &parent) const {
if (!parent.isValid())
return createIndex(row, column, m_RootNode->m_Children.at(row));
else
return createIndex(row, column, indexData(parent)->m_Children.at(row));
}
 
QModelIndex parent(const QModelIndex &index) const {
if (!indexData(index)->m_Parent)
return QModelIndex();
else
return createIndex(indexData(index)->m_Row, index.column(), indexData(index)->m_Parent);
}
 
int columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent)
return 4;
}
 
int rowCount(const QModelIndex &parent) const {
if (!parent.isValid())
return m_RootNode->m_Children.count();
else
return indexData(parent)->m_Children.count();
}
 
QVariant data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole)
return indexData(index)->m_Name;
else
return QVariant();
}
 
QVariant headerData(int section, Qt::Orientation orientation, int role) const {
Q_UNUSED(section)
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return "";
else
return QVariant();
}
};
//
class IndexViewer: public QTreeView {
public:
IndexViewer() {
setModel(new IndexModel(this));
 
for (int i = 0; i < model()->columnCount(QModelIndex()); ++i)
resizeColumnToContents(i);
}
};
//
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
 
IndexViewer iv;
iv.show();
 
return app.exec();
}
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Октябрь 06, 2009, 10:01 »

мне не нравится
Код:
	QModelIndex parent(const QModelIndex &index) const {
if (!indexData(index)->m_Parent)
return QModelIndex();
else
return createIndex(indexData(index)->m_Row, index.column(), indexData(index)->m_Parent);
}
что будет, если index.isValid() вернет false?.. хотя сходу не могу сказать, может и не важно это
Записан
uriel
Гость
« Ответ #2 : Октябрь 06, 2009, 19:00 »

Благодарю за ответ.
Нет, все эти граничные случаи с hasIndex и isValid я уже проверял - разницы никакой. Просто смущает то, что падает оно не на моём коде, а тот же valgrind выдаёт нереальную кучу различных ошибок. Некоторые совсем странные, вроде:
Код:
Conditional jump or move depends on uninitialised value(s)
at 0x804D94A: QList<Node*>::at(int) const (qlist.h:395)
by 0x804D37C: IndexModel::index(int, int, QModelIndex const&) const (main.cpp:86)
by 0x46DC7D6: QTreeView::drawRow(QPainter*, QStyleOptionViewItem const&, QModelIndex const&) const (in /usr/lib/libQtGui.so.4.5.2)
by 0x46E4C3B: QTreeView::drawTree(QPainter*, QRegion const&) const (in /usr/lib/libQtGui.so.4.5.2)
by 0x46E56BA: QTreeView::paintEvent(QPaintEvent*) (in /usr/lib/libQtGui.so.4.5.2)
by 0x41B0A13: QWidget::event(QEvent*) (in /usr/lib/libQtGui.so.4.5.2)
by 0x45570E2: QFrame::event(QEvent*) (in /usr/lib/libQtGui.so.4.5.2)
by 0x45F5873: QAbstractScrollArea::viewportEvent(QEvent*) (in /usr/lib/libQtGui.so.4.5.2)
by 0x46A8D76: QAbstractItemView::viewportEvent(QEvent*) (in /usr/lib/libQtGui.so.4.5.2)
by 0x46E3DE3: QTreeView::viewportEvent(QEvent*) (in /usr/lib/libQtGui.so.4.5.2)
by 0x45F7E64: ??? (in /usr/lib/libQtGui.so.4.5.2)
by 0x4D6A9F9: QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) (in /usr/lib/libQtCore.so.4.5.2)
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #3 : Октябрь 06, 2009, 19:42 »

чего странного?  все правильно. читать надо снизу вверх - главный цикл запускает отрисовку, которая обращается к вьюхе, та к модели, а та уже зовет
at 0x804D94A: QList<Node*>::at(int) const (qlist.h:395)
by 0x804D37C: IndexModel::index(int, int, QModelIndex const&) const (main.cpp:86)
краш в ф-ии IndexModel::index(int, int, QModelIndex const&) const - скорее всего нод битый
Записан
uriel
Гость
« Ответ #4 : Октябрь 06, 2009, 20:05 »

Меня просто смутило именно описание про неинициализированную переменную. Перепроверил всё на ещё один раз и попробовал прогнать traverse без поднятия интерфейса - ни одной утечки. Выходит, что они бьются где-то во вьюхе. Если добавить к узлам деструкторы, то окажется, что они ни разу не вызываются, то есть никто никого не удаляет, хотя glibc иногда ругается на повторное освобождение блока памяти или ещё что-нибудь в этом духе.
Ах да, иногда под valgrind'ом выбрасывается assert о выходе за границы QList'а где-то в подсистеме отрисовки.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #5 : Октябрь 06, 2009, 21:44 »

нашел там 3 ошибки, но так заставить работать до конца не смог:) крашится на 2м уровне вложенности
Записан
uriel
Гость
« Ответ #6 : Октябрь 07, 2009, 08:12 »

Эх...ладно, спасибо. Пожалуй, отвлекусь от этого на пару деньков, чтобы потом уже свежим взглядом посмотреть на код. Улыбающийся
Записан
KADABRA
Гость
« Ответ #7 : Октябрь 07, 2009, 10:37 »

Во первых ещё при установке модели вылетает ассерт
Цитировать
ASSERT failure in QAbstractItemView::setModel: "The parent of a top level index should be invalid", file itemviews\qabstractitemview.cpp, line 553
Неужели вы считаете что этот ассерт просто так вываливается и его можно игнорировать?
Код
C++ (Qt)
QModelIndex parent(const QModelIndex &index) const {
if (!index.isValid())
return QModelIndex();
 
Node* node = static_cast<Node*>(index.internalPointer());
Node* parent = node->m_Parent;
if(parent == m_RootNode)
return QModelIndex();
 
return createIndex(indexData(index)->m_Row, index.column(), indexData(index)->m_Parent);
}
« Последнее редактирование: Октябрь 07, 2009, 10:40 от KADABRA » Записан
uriel
Гость
« Ответ #8 : Октябрь 07, 2009, 12:19 »

Во первых ещё при установке модели вылетает ассерт
А какая у Вас версия Qt, если не секрет? Просто у меня ни на ArchLinux'овой 4.5.3-2, ни на самосборной 4.6.0-tp1 этого ассерта нет, хотя последняя точно собрана в отладочном варианте.
А вообще да, это всё проясняет, премного благодарен. Улыбающийся
Записан
KADABRA
Гость
« Ответ #9 : Октябрь 07, 2009, 12:37 »

А какая у Вас версия Qt, если не секрет?
Не секрет конечно-же, 4.5.2 Win32 самосборная под msvs9.0 sp1.
И врядли что в последующих версиях этот ассерт удалили. А если его нету, то это очень странно - может релиз сборка Qt?
Записан
uriel
Гость
« Ответ #10 : Октябрь 07, 2009, 13:10 »

Так в том-то и дело, что 4.6.0-tp1 собирал сам с ключами -debug-and-release и -separate-debug-info. Всю жизнь при таком раскладе ассерты были, а на 4.6 куда-то пропали. Хотя, может тут и в чём-то другом дело.
Записан
yonas
Гость
« Ответ #11 : Октябрь 08, 2009, 22:20 »

а корректно ли работает QModelIndex() ?
Записан
Joss
Гость
« Ответ #12 : Октябрь 08, 2009, 22:31 »

ИМХО, проще заглушки вставлять поэтапно, например:

Код:
	QVariant data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole)
return indexData(index)->m_Name;
else
return QVariant();
}

на

Код:
	QVariant data(const QModelIndex &index, int role) const {
return QVariant();
}

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

Сообщений: 3260


Просмотр профиля
« Ответ #13 : Октябрь 08, 2009, 23:25 »

что значит корректно ли? обычно пустой индекс ассоциируется с рутом дерева (судя из QtDemo и того, что к примеру у меня все работает в таком его понимании)
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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