Qt QAbstractItemModel - 项目删除崩溃 [英] Qt QAbstractItemModel - item removal crashes

查看:2354
本文介绍了Qt QAbstractItemModel - 项目删除崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用Qt类编写一个应用程序,我有一个层次结构,我需要在树视图中显示它(我使用的QTreeView小部件)。数据本身如下所示:

I'm writing an application using Qt classes where I have a hierarchical structure and I need to display it in a tree view (I'm using a QTreeView widget). The data itself look like this:

class StatisticsEntry
{
 // additional data management methods
 ...

bool setData(int column, const QVariant &value)
{
    if (column < 0 || column >= _data.size())
        return false;

    _data[column] = value;
    return true;
}

private:
    // each item has a parent item except the top-most one
    StatisticsEntry *_parent;
    // each item may have child items which are accessible through the following member
    QList<StatisticsEntry*> _children;
    // each item is defined by a set of vallues stored in the following vector
    QVector<QVariant> _data;
}



我有一个叫StatModel的类实现QAbstractItemModel-使用它来操纵和呈现存储在StatisticsEntry树中的数据。
类有一个名为addStatisticsData的方法,我用它将StatisticsEntry记录推入模型。方法大致如下:

I have a class called it StatisticsModel that implements QAbstractItemModel - use it to manipulate and present the data stored in the StatisticsEntry tree. The class has a method called addStatisticsData which I use to push StatisticsEntry records into the model. The method roughly looks like this:

QModelIndex StatisticsModel::addStatisticsData(const QString &title, const QString &description, const QModelIndex &parent)
{
    int row = rowCount(parent);
    if (!insertRow(row, parent))
        return QModelIndex();

    // Get new item index
    QModelIndex child = index(row, 0, parent);

    // set item data
    setTitle(child, title);
    setDescription(child, description);

    return child;
}

SetTitle和setDescription方法是相同的 - 这里是setTitle:

SetTitle and setDescription methods are identical - here's the setTitle one:

void StatisticsModel::setTitle(const QModelIndex &index, const QString& title)
{
    QModelIndex columnIndex = this->index(index.row(), StatColumn::Title, index.parent());
    this->setData(columnIndex, title, Qt::EditRole);
}

setData方法如下:

The setData method is as follows:

bool StatisticsModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (role != Qt::EditRole)
        return false;

    int column = index.column();

    StatisticsEntry *item = getItem(index);
    if (!item->setData(column, value))
        return false;

    emit dataChanged(index, index);

    return true;
}

剩下的是getItem方法:

What is left is the getItem method:

StatisticsEntry *StatisticsModel::getItem(const QModelIndex &index) const
{
    if (index.isValid())
    {
        StatisticsEntry *item = static_cast<StatisticsEntry*>(index.internalPointer());
        if (item)
            return item;
    }

    return _rootItem;
}

这是关于添加新的和修改现有条目。在我的应用程序中,我已经实现了QSortFilterProxyModel,没有什么特别的,只是lessThan方法。我使用代理模型在QTreeView中提供一个显示数据的排序功能。有以下代码将模型连接到树视图窗口小部件:

That is about all there is when speaking of adding new and modifying existing entries. In my application I have implemented QSortFilterProxyModel as well - nothing special, just the lessThan method. I use the proxy model to provide a sort feature in the QTreeView that displays the data. There is the following code that connects the models to the treeview widget:

在主窗口的标题:

...
StatisticsModel* _statisticsModel;
StatisticsProxyModel* _statisticsProxyModel;
...

在主窗口的构造函数中

...
_statisticsModel = new StatisticsModel(ths);
_statisticsProxyModel = new StatisticsProxyModel(htis);
...
_statisticsProxyModel->setSourceModel(_statisticsModel);
ui->statisticsTreeView->setModel(_statisticsProxyModel);
...

应用程序还有一个按钮,从模型 - 我目前只测试与QTreeView :: selectionModel() - > currentIndex,暂时没有多重选择。

The application also has a button that allows me to remove the selected item from the model - I'm currently only testing with the QTreeView::selectionModel()->currentIndex, no multi-selections for the time being.

我有以下代码的StatisticsModel :: removeRows方法

I have the following code for the StatisticsModel::removeRows method

bool StatisticsModel::removeRows(int position, int rows, const QModelIndex &parent)
{
    StatisticsEntry *parentItem = getItem(parent);

    bool success1 = true;
    bool success2 = true;
    beginRemoveRows(parent, position, position + rows - 1);
    for (int i = position + rows - 1; i >= position; i--)
    {
        QModelIndex child = index(i, 0, parent);
        QString title = this->title(child); // the title method is the getter method that matches the setTitle one 
        success1 = success1 && removeRows(0, rowCount(child), child); //rowCount is implemented to return the number of items stored in StatisticsEntry::_children list for the specified parent index
        success2 = success2 && parentItem->removeChild(i); // deletes an entry from the StatisticsEntry::_children list
    }
    endRemoveRows();
    return success1 && success2;
}


$ b <我得到一个异常,堆栈跟踪看起来像:

The problem is that sometimes when I remove an item using QAbstractItemModel::removeRow method I get an exception and the stack trace looks like:

StatisticsModel::parent StatisticsModel.cpp 307 0x13e7bf8   
QModelIndex::parent qabstractitemmodel.h    393 0x72e57265  
QSortFilterProxyModelPrivate::source_to_proxy   qsortfilterproxymodel.cpp   386 0x711963e2  
QSortFilterProxyModel::mapFromSource    qsortfilterproxymodel.cpp   2514    0x7119d28b  
QSortFilterProxyModel::parent   qsortfilterproxymodel.cpp   1660    0x7119a32c  
QModelIndex::parent qabstractitemmodel.h    393 0x72e57265  
QPersistentModelIndex::parent   qabstractitemmodel.cpp  347 0x72e58b86  
QItemSelectionRange::isValid    qitemselectionmodel.h   132 0x70e3f62b  
QItemSelection::merge   qitemselectionmodel.cpp 466 0x711503d1  
QItemSelectionModelPrivate::finalize    qitemselectionmodel_p.h 92  0x7115809a  
QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved qitemselectionmodel.cpp 623 0x71151132  
QItemSelectionModel::qt_static_metacall moc_qitemselectionmodel.cpp 113 0x711561c2  
QMetaObject::activate   qobject.cpp 3547    0x72e8d9a4  
QAbstractItemModel::rowsAboutToBeRemoved    moc_qabstractitemmodel.cpp  204 0x72f08a76  
QAbstractItemModel::beginRemoveRows qabstractitemmodel.cpp  2471    0x72e5c53f  
QSortFilterProxyModelPrivate::remove_proxy_interval qsortfilterproxymodel.cpp   558 0x71196ce7  
QSortFilterProxyModelPrivate::remove_source_items   qsortfilterproxymodel.cpp   540 0x71196c7f  
QSortFilterProxyModelPrivate::source_items_about_to_be_removed  qsortfilterproxymodel.cpp   841 0x71197c77  
QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved qsortfilterproxymodel.cpp   1291    0x711995cc  
QSortFilterProxyModel::qt_static_metacall   moc_qsortfilterproxymodel.cpp   115 0x7119d506  
QMetaCallEvent::placeMetaCall   qobject.cpp 525 0x72e883fd  
QObject::event  qobject.cpp 1195    0x72e894ba  
QApplicationPrivate::notify_helper  qapplication.cpp    4550    0x709d710e  
QApplication::notify    qapplication.cpp    3932    0x709d4d87  
QCoreApplication::notifyInternal    qcoreapplication.cpp    876 0x72e6b091

奇怪的是,这似乎与本项目有关的所有拆除立即方法调用发生后,已经结束了。看起来代理模型正在寻找不应该出现的模型索引(或者我认为)。 StatisticsModel :: parent方法如下:

Oddly enough this seems to happen after all immediate method calls concerning the item removal are already over. It seems that the proxy model is looking for model indices that should not be present anymore (or so I think). The StatisticsModel::parent method is as follows:

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

    StatisticsEntry *childItem = getItem(index);
    StatisticsEntry *parentItem = childItem->parent();

    if (NULL != parentItem)
        return createIndex(parentItem->childNumber(), 0, parentItem);
    return QModelIndex();
}

当发生异常时,与childItem和parentItem变量方法似乎无效 - 指针本身指向不可访问的内存,或者成员QLists没有条目或者它们的条目给出内存访问冲突。
这可能是父类的方法不正确,但随后如何获取父指数 - 该文件化QAbstractItemModel阻碍QModelIndex在该方法的使用::母公司为它会创建一个无限递归

When the exception happens the values associated with the childItem and parentItem variables from the above method seem invalid - either the pointers themselves point to non-accessible memory or the member QLists either have no entries or their entries give Memory access violation. It may be that the parent method is not correct, but then how to fetch the parent index - the qabstractItemModel documentation discourages the usage of QModelIndex::parent in that method for it will create an infinite recursion.

任何帮助都会感激,

推荐答案

> StatisticsModel :: removeRows ,你是嵌套 begingRemoveRows / endRemoveRows ,其中,AFAIK,不工作。你应该这样做:

When doing your StatisticsModel::removeRows, You are nesting begingRemoveRows/endRemoveRows, which, AFAIK, does not work. You should do:

bool StatisticsModel::removeRows(int position, int rows, const QModelIndex &parent)
{
    StatisticsEntry *parentItem = getItem(parent);

    bool success1 = true;
    bool success2 = true;
    for (int i = position + rows - 1; i >= position; i--)
    {
        QModelIndex child = index(i, 0, parent);
        QString title = this->title(child); // the title method is the getter method that matches the setTitle one 
        success1 = success1 && removeRows(0, rowCount(child), child); //rowCount is implemented to return the number of items stored in StatisticsEntry::_children list for the specified parent index
        beginRemoveRows(parent, i, i);
        success2 = success2 && parentItem->removeChild(i); // deletes an entry from the StatisticsEntry::_children list
        endRemoveRows();
    }
    return success1 && success2;
}

这篇关于Qt QAbstractItemModel - 项目删除崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆