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

ksm*_*ing 5 xml treeview qt model filter

我创建了一个自定义 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

这是崩溃发生时的调用堆栈:

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
Run Code Online (Sandbox Code Playgroud)

我对 Qt 模型/视图编程还很陌生,这个错误确实令人畏惧,让我摸不着头脑好几天。我希望有人能在我失去所有头发之前帮助我!谢谢!

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

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

主窗口:

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


...

}
Run Code Online (Sandbox Code Playgroud)

子窗口:

class CGHXMLParameterDialog : public QDialog
{
    Q_OBJECT
...

private:
    void setupProxyModel();

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

...

}
Run Code Online (Sandbox Code Playgroud)

在 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);
Run Code Online (Sandbox Code Playgroud)

然后调用 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);
}
Run Code Online (Sandbox Code Playgroud)

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

这是我的删除行代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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.
Run Code Online (Sandbox Code Playgroud)

更新:发出layoutChanged()而不发出layoutAboutToBeChanged()是错误的吗?

ksm*_*ing 2

我通过为我的 insertRows、removeRows 方法注释“emit layoutChanged()”行解决了这个问题。最初的代码没有这一行,但 QTreeView 的更新问题迫使我包含它,而不包含“emit layoutAboutToChanged()”。似乎更新问题由于某种原因消失了。

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