qml tree view crashed with c++ model,when add big data or resize window
Unsolved
QML and Qt Quick
-
main.qml
import QtQuick 2.12 import QtQuick.Controls 2.0 import QtQuick.Controls 1.4 import QtQuick.Window 2.0 import QtQuick.Layouts 1.0 import CC 1.0 as CC import "qrc:/qml/" import QtGraphicalEffects 1.0 Window { id:root visible: true minimumWidth: 600; minimumHeight: 800 width: 600; height: 800 CC.OpenProjectManager{ id:openProject; } Button { x:0;y:0 width: 200;height: 100 text: "open" id:btn onClicked:openProject.open() } ResultTree{ id:treeView x:200;y:0 width:parent.width-200 height: parent.height } } code_text
ResultTree.qml
import QtQuick 2.7 import QtQuick.Controls 2.4 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.0 import QtGraphicalEffects 1.0 TreeView { model: treeModel TableViewColumn { role: "iconFile" title: "文件名" delegate: iconTextDelegate width: parent.width * 0.3 } TableViewColumn { role: "severityStr" title: "错误级别" width: parent.width * 0.1 } TableViewColumn { role: "line" title: "行号" width: parent.width * 0.1 } TableViewColumn { role: "id" title: "错误号" width: parent.width * 0.2 } TableViewColumn { role: "summary" title: "概要" width: parent.width * 0.3 } Component { id:iconTextDelegate Item { Image { id:image source: styleData.value["icon"] height:parent.height * 0.9; width: height asynchronous:true } Text { text: styleData.value["file"] anchors.left: image.right anchors.leftMargin: 10 } } } }
register treeModel
#define TREEMODEL_REGISTER \ { \ auto treeModel = CC::TreeModel::instance(); \ engine.rootContext()->setContextProperty("treeModel", treeModel); \ }
int works,but crashed when big data or resize window,
TreeItem.h#ifndef TREEITEM_H #define TREEITEM_H #include <QList> #include <QVariant> namespace CC{ //! [0] class TreeItem { public: explicit TreeItem(const QMap<QString,QVariant> &data,TreeItem *parentItem = nullptr); ~TreeItem(); TreeItem(const TreeItem& other); TreeItem& operator = (const TreeItem & other); void appendChild(TreeItem *child); TreeItem *child(int row); int childCount() const; int columnCount() const; QVariant data(QString key) const; int row() const; TreeItem *parentItem(); QList<TreeItem*> children(); private: QList<TreeItem*> m_childItems; QMap<QString,QVariant> m_itemData; TreeItem *m_parentItem; }; //! [0] } #endif // TREEITEM_H
TreeItem.cpp
#include <QStringList> #include "treeitem.h" using namespace CC; //! [0] TreeItem::TreeItem(const QMap<QString,QVariant> &data, TreeItem *parent) { m_parentItem = parent; m_itemData = data; } //! [0] //! [1] TreeItem::~TreeItem() { qDeleteAll(m_childItems); } TreeItem::TreeItem(const TreeItem &other) { this->m_childItems = other.m_childItems; this->m_itemData = other.m_itemData; this->m_parentItem = other.m_parentItem; } TreeItem &TreeItem::operator =(const TreeItem &other) { this->m_childItems = other.m_childItems; this->m_itemData = other.m_itemData; this->m_parentItem = other.m_parentItem; return *this; } //! [1] //! [2] void TreeItem::appendChild(TreeItem *item) { m_childItems.append(item); } //! [2] //! [3] TreeItem *TreeItem::child(int row) { return m_childItems.value(row); } //! [3] //! [4] int TreeItem::childCount() const { return m_childItems.count(); } //! [4] //! [5] int TreeItem::columnCount() const { return m_itemData.count(); } //! [5] //! [6] QVariant TreeItem::data(QString key) const { return m_itemData.value(key,QVariant()); } //! [6] //! [7] TreeItem *TreeItem::parentItem() { return m_parentItem; } QList<TreeItem *> TreeItem::children() { return m_childItems; } //! [7] //! [8] int TreeItem::row() const { if (m_parentItem) return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this)); return 0; } //! [8]
TreeModel.h
#ifndef TREEMODEL_H #define TREEMODEL_H #include <QAbstractItemModel> #include <QModelIndex> #include <QVariant> #define TREEMODEL_REGISTER \ { \ auto treeModel = CC::TreeModel::instance(); \ engine.rootContext()->setContextProperty("treeModel", treeModel); \ } const QString CONST_file("file"); const QString CONST_iconFile("iconFile"); const QString CONST_severity("severity"); const QString CONST_severityStr("severityStr"); const QString CONST_line("line"); const QString CONST_id("id"); const QString CONST_summary("summary"); const QString CONST_hide("hide"); const QString CONST_message("message"); const QString CONST_column("column"); const QString CONST_inconclusive("inconclusive"); const QString CONST_file0("file0"); const QString CONST_sinceDate("sinceDate"); const QString CONST_tags("tags"); class ErrorItem; namespace CC { class TreeItem; //! [0] class TreeModel : public QAbstractItemModel { Q_OBJECT Q_DISABLE_COPY(TreeModel) public: enum class TreeModelRoles : int { file = Qt::UserRole + 1, iconFile, severity, severityStr, line, id, summary, hide, message, column, inconclusive, file0, sinceDate, tags, }; enum class TreeModelColumn : int { iconFile, severityStr, line, id, summary, }; ~TreeModel() Q_DECL_OVERRIDE; /* QAbstractItemModel interface */ QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QHash<int, QByteArray> roleNames() const override; static TreeModel* instance(); private: explicit TreeModel(QObject *parent = nullptr); private: TreeItem *rootItem; QHash<int, QByteArray> m_roleNameMapping; public: void BeginResetModel(); void EndResetModel(); bool addErrorItem(const ErrorItem &item); private: bool addErrorItemExec(const ErrorItem &item); TreeItem * checkExistingItem(QList<TreeItem*> children, const QMap<QString,QVariant> &data); private: QStringList mHiddenMessageId; QString mFilter; bool mHasVisibleErrors = false; }; //! [0] } #endif // TREEMODEL_H
TreeModel.cpp
#include "treemodel.h" #include <QStringList> #include <QJsonObject> #include <QDir> #include <algorithm> #include "treeitem.h" #include "erroritem.h" #include "helper.h" using namespace CC; //! [0] TreeModel::TreeModel(QObject *parent) : QAbstractItemModel(parent) { m_roleNameMapping[static_cast<int>(TreeModelRoles::file)] = CONST_file.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::iconFile)] = CONST_iconFile.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::severity)] = CONST_severity.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::severityStr)] = CONST_severityStr.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::line)] = CONST_line.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::id)] = CONST_id.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::summary)] = CONST_summary.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::hide)] = CONST_hide.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::message)] = CONST_message.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::column)] = CONST_column.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::inconclusive)] = CONST_inconclusive.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::file0)] = CONST_file0.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::sinceDate)] = CONST_sinceDate.toUtf8(); m_roleNameMapping[static_cast<int>(TreeModelRoles::tags)] = CONST_tags.toUtf8(); QMap<QString,QVariant> rootData; rootData.insert(CONST_file,CONST_file); rootData[CONST_iconFile] = QJsonObject({{"file","file1.cpp"},{"icon","qrc:/images/language-cpp.png"}}); rootData.insert(CONST_severity,CONST_severity); rootData.insert(CONST_severityStr,CONST_severityStr); rootData.insert(CONST_line,CONST_line); rootData.insert(CONST_id,CONST_id); rootData.insert(CONST_summary,CONST_summary); rootData.insert(CONST_hide,CONST_hide); rootData.insert(CONST_message,CONST_message); rootData.insert(CONST_column,CONST_column); rootData.insert(CONST_inconclusive,CONST_inconclusive); rootData.insert(CONST_file0,CONST_file0); rootData.insert(CONST_sinceDate,CONST_sinceDate); rootData.insert(CONST_tags,CONST_tags); rootItem = new TreeItem(rootData); } void TreeModel::BeginResetModel() { this->beginResetModel(); } void TreeModel::EndResetModel() { this->endResetModel(); } //! [0] //! [1] TreeModel::~TreeModel() { delete rootItem; } //! [1] //! [2] int TreeModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return static_cast<TreeItem*>(parent.internalPointer())->columnCount(); else return rootItem->columnCount(); } //! [2] //! [3] QVariant TreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (!m_roleNameMapping.keys().contains(role)) { return QVariant(); } TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); return item->data(m_roleNameMapping.value(role)); } //! [3] //! [4] Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; return QAbstractItemModel::flags(index); } //! [4] //! [5] QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch (section) { case static_cast<int>(TreeModelColumn::iconFile): return rootItem->data(CONST_file); case static_cast<int>(TreeModelColumn::severityStr): return rootItem->data(CONST_severityStr); case static_cast<int>(TreeModelColumn::line): return rootItem->data(CONST_line); case static_cast<int>(TreeModelColumn::id): return rootItem->data(CONST_id); case static_cast<int>(TreeModelColumn::summary): return rootItem->data(CONST_summary); } } return QVariant(); } //! [5] //! [6] QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); 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(); } //! [6] //! [7] QModelIndex TreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer()); TreeItem *parentItem = childItem->parentItem(); if (parentItem == rootItem) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); } //! [7] //! [8] int TreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentItem; if (parent.column() > 0) return 0; if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast<TreeItem*>(parent.internalPointer()); return parentItem->childCount(); } //! [8] QHash<int, QByteArray> TreeModel::roleNames() const { return m_roleNameMapping; } TreeModel *TreeModel::instance() { static TreeModel model; return &model; } bool TreeModel::addErrorItem(const ErrorItem &item) { bool ret = addErrorItemExec(item); return ret; } bool TreeModel::addErrorItemExec(const ErrorItem &item) { if (item.errorPath.isEmpty()) { return false; } const QErrorPathItem &loc = item.errorId.startsWith("clang") ? item.errorPath.front() : item.errorPath.back(); QString relativeFile = Helper::GetStripPath(loc.file); if (relativeFile.isEmpty()) { relativeFile = tr("Undefined file"); } bool hide = false; if (mHiddenMessageId.contains(item.errorId)) { hide = true; } if (!hide && !mFilter.isEmpty()) { if (!item.summary.contains(mFilter, Qt::CaseInsensitive) && !item.message.contains(mFilter, Qt::CaseInsensitive) && !item.errorPath.back().file.contains(mFilter, Qt::CaseInsensitive) && !item.errorId.contains(mFilter, Qt::CaseInsensitive)) { hide = true; } } if (!hide) { mHasVisibleErrors = true; } TreeItem *fileItem = nullptr; for(const auto & child : rootItem->children()) { if(child->data(CONST_file) == relativeFile){ fileItem = child; } } if(!fileItem) { QMap<QString,QVariant> fileItemData; fileItemData.insert(CONST_iconFile, QJsonObject({{"file",relativeFile},{"icon","qrc:/images/language-cpp.png"}})); fileItemData.insert(CONST_severityStr,""); fileItemData.insert(CONST_line,""); fileItemData.insert(CONST_id,""); fileItemData.insert(CONST_summary,""); fileItem = new TreeItem(fileItemData,rootItem); rootItem->appendChild(fileItem); } QMap<QString,QVariant> errorItemData; errorItemData.insert(CONST_file, relativeFile); errorItemData.insert(CONST_severity, item.severity); errorItemData.insert(CONST_line, loc.line); errorItemData.insert(CONST_id, item.errorId); errorItemData.insert(CONST_summary, item.summary); errorItemData.insert(CONST_hide, hide); errorItemData.insert(CONST_message, item.message); errorItemData.insert(CONST_column, ""); errorItemData.insert(CONST_inconclusive, item.inconclusive); errorItemData.insert(CONST_file0, item.file0); errorItemData.insert(CONST_sinceDate, item.sinceDate); errorItemData.insert(CONST_tags, item.tags); QString icon; QString severityStr; Helper::Severity2Icon(item.severity,icon,severityStr); errorItemData.insert(CONST_iconFile,QJsonObject({{"file",relativeFile},{"icon",icon}})); errorItemData.insert(CONST_severityStr,severityStr); TreeItem *errorItem = checkExistingItem(fileItem->children(),errorItemData); if(!errorItem) { errorItem = new TreeItem(errorItemData, fileItem); fileItem->appendChild(errorItem); } if (item.errorPath.size() > 1) { for (int i = 0; i < item.errorPath.size(); i++) { const QErrorPathItem &e = item.errorPath[i]; QMap<QString,QVariant> pathItemData; pathItemData[CONST_file] = e.file; pathItemData[CONST_line] = e.line; pathItemData[CONST_column] = e.column; pathItemData[CONST_message] = e.info; pathItemData[CONST_summary] = e.info; pathItemData[CONST_severityStr] = "note"; pathItemData.insert(CONST_id,""); pathItemData.insert(CONST_iconFile,QJsonObject({{"file",e.file},{"icon","qrc:/old/go-down.png"}})); TreeItem *pathItem = checkExistingItem(errorItem->children(),pathItemData); if (!pathItem) { pathItem = new TreeItem(pathItemData,errorItem); errorItem->appendChild(pathItem); } } } return true; } TreeItem *TreeModel::checkExistingItem(QList<TreeItem *> children, const QMap<QString, QVariant> &data) { TreeItem *item = nullptr; // if(children.count()) { // std::for_each(children.begin(),children.end(),[&item,data](TreeItem *child) { // if((child->data(CONST_line) == data[CONST_line]) // && (child->data(CONST_severity) == data[CONST_severity]) // && (child->data(CONST_summary) == data[CONST_summary])) { // item = child; // } // }); // } for(const auto & child : children) { if((child->data(CONST_line) == data[CONST_line]) && (child->data(CONST_severity) == data[CONST_severity]) && (child->data(CONST_summary) == data[CONST_summary])) { item = child; } } return item; }
crash callstack