通过源模型函数从源模型中删除行时,QSortFilterProxyModel崩溃

时间:2011-08-31 06:15:46

标签: xml qt model filter treeview

我创建了一个自定义的QAbstractItemModel派生模型,它包含一组树形分层方式的XML数据,将显示在QTreeView中,如下图所示:

http://imageshack.us/photo/my-images/840/xmltreeview.png

此模型已成功通过ModelTest和一些基本的编辑测试。但是,在尝试对此模型进行一些过滤时遇到了一些问题,因此我可以将模型拆分为几个不同的视图。我尝试过QSortFilterProxyModel并且它崩溃了很多。经过一些修复后,尝试从模型中删除一行后仍然会崩溃。

控制台应用程序在发生崩溃时显示以下消息:

ratbr QModelIndex(0,0,0xd162000,CGHXmlModel(0xb197e68))0 0

rr QModelIndex(0,0,0xd162000,CGHXmlModel(0xb197e68))0 0

这是崩溃发生时的callstack:

0   QSortFilterProxyModelPrivate::index_to_iterator qsortfilterproxymodel.cpp   193 0x0134714b  
1   QSortFilterProxyModel::parent   qsortfilterproxymodel.cpp   1654    0x0111a677  
2   QModelIndex::parent qabstractitemmodel.h    389 0x6a2ad95e  
3   QPersistentModelIndex::parent   qabstractitemmodel.cpp  347 0x6a1f7320  
4   QItemSelectionRange::isValid    qitemselectionmodel.h   108 0x01341ea4  
5   QItemSelectionModel::isSelected qitemselectionmodel.cpp 1187    0x010f0b58  
6   QTreeView::drawRow  qtreeview.cpp   1602    0x010db133  
7   QTreeView::drawTree qtreeview.cpp   1441    0x010da4f4  
8   QTreeView::paintEvent   qtreeview.cpp   1274    0x010d9bed  
9   QWidget::event  qwidget.cpp 8333    0x00c1492d  
10  QFrame::event   qframe.cpp  557 0x00f8e6bc  
11  QAbstractScrollArea::viewportEvent  qabstractscrollarea.cpp 1043    0x0101bf0f  
12  QAbstractItemView::viewportEvent    qabstractitemview.cpp   1619    0x010a5785  
13  QTreeView::viewportEvent    qtreeview.cpp   1256    0x010d9aa3  
14  QAbstractScrollAreaPrivate::viewportEvent   qabstractscrollarea_p.h 100 0x01276a13  
15  QAbstractScrollAreaFilter::eventFilter  qabstractscrollarea_p.h 116 0x0127506c  
16  QCoreApplicationPrivate::sendThroughObjectEventFilters  qcoreapplication.cpp    847 0x6a1ffc73  
17  QApplicationPrivate::notify_helper  qapplication.cpp    4392    0x00bc96e5  
18  QApplication::notify    qapplication.cpp    4361    0x00bc9586  
19  QCoreApplication::notifyInternal    qcoreapplication.cpp    732 0x6a1ff9dc  
20  QCoreApplication::sendSpontaneousEvent  qcoreapplication.h  218 0x0123d53e

我对Qt Model / View编程还很陌生,这个错误实在令人生畏,让我头疼了好几天。我希望有人在我失去所有头发之前可以帮助我。谢谢!

编辑:更新以包含一些源代码

我的测试项目有两个对话窗口,每个窗口都有一个QTreeView。一个是包含QAbstractItemModel派生类成员的主窗口,另一个是包含QSortFilterProxyModel派生类成员的子窗口。子窗口还有一个指向实际模型的QAbstractItemModel指针。

主窗口:

class CGHXMLModelDialog : public QDialog
{
    Q_OBJECT
...
private:
    Ui::CGHXMLModelDialog *ui;
    CGHXmlModel*            m_mainModel;
    CGHXMLParameterDialog*  m_ParamDialog;


...

}

子窗口:

class CGHXMLParameterDialog : public QDialog
{
    Q_OBJECT
...

private:
    void setupProxyModel();

    Ui::CGHXMLParameterDialog*      ui;
    QAbstractItemModel*             m_coreModel;//A CGHXMLModel
    CGHXMLSortFilterProxyModel*     m_ParamModel;

...

}

在CGHXMLModelDialog构造函数中:

m_mainModel = new CGHXmlModel(theDomDocument, this);
ui->CGHXMLTreeView->setModel(m_mainModel);

//Create sub-dialog window containing proxy filter model
m_ParamDialog = new CGHXMLParameterDialog(m_mainModel, this);

然后调用setupProxyModel()方法:

CGHXMLParameterDialog::CGHXMLParameterDialog(QAbstractItemModel* coreModel, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::CGHXMLParameterDialog),
    m_coreModel(coreModel)
{
    ui->setupUi(this);
    setupProxyModel();
}

void CGHXMLParameterDialog::setupProxyModel()
{
    m_ParamModel = new CGHXMLSortFilterProxyModel(this);
    m_ParamModel->setSourceModel(m_coreModel);

    m_ParamModel->setFilterRegExp(QRegExp("Parameter"));
    m_ParamModel->setFilterKeyColumn(0);
    m_ParamModel->setDynamicSortFilter(true);

    ui->CGHXMLParamView->setModel(m_ParamModel);
}

我已经测试了插入行,编辑行内容,通过列编辑插入XML属性(自定义列操作;我不会详细说明)等直接在源模型上进行测试,并且无论是否存在Sort-Filter都可以使用它模型。当我尝试删除“行”时,会出现问题,该行是附加了排序过滤器模型的模型的XML元素。

这是我的removeRows代码:

bool CGHXmlModel::removeRows(int rowposition, int rows, const QModelIndex &parent)
{
    CGHXMLTreeItem *parentItem = getItem(parent);
    bool success = false;

    beginRemoveRows(parent, rowposition, rowposition + rows - 1);
    success = parentItem->removeChildren(rowposition, rows);
    endRemoveRows();

    if(success)//Works!
    {
        emit layoutChanged();
    }

    return success;
}

由主窗口中的按钮事件处理程序调用:

void CGHXMLModelDialog::on_deleteRowButton_clicked()
{
    QModelIndex currIndex = ui->CGHXMLTreeView->selectionModel()->currentIndex();

    if(!m_mainModel->removeRow(currIndex.row(), currIndex.parent()))
    {
        qDebug() << "Fail to remove row from Model.";
        return;
    }
}
//Program crashes after this function returns.

更新:在不发出layoutAboutToBeChanged()的情况下发出layoutChanged()是错误的吗?

2 个答案:

答案 0 :(得分:1)

您是否知道QAbstractItemModel和QSortFilterProxyModel中的索引无法混合使用?

如果您的filterProxy模型中有QModelIndex,则需要使用QAbstractProxyModel :: mapToSource()从项目模型将其转换为QModelIndex。

答案 1 :(得分:1)

我通过评论线来解决了这个问题&#34; emit layoutChanged()&#34;对于我的insertRows,removeRows方法。最初代码没有这一行,但QTreeView的更新问题迫使我包含它,而不包括&#34; emit layoutAboutToChanged()&#34;。由于某种原因,似乎更新问题已经消失。

无论如何,感谢那些试图提供帮助的人。在不久的将来我肯定需要更多。