我创建了一个自定义的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()是错误的吗?
答案 0 :(得分:1)
您是否知道QAbstractItemModel和QSortFilterProxyModel中的索引无法混合使用?
如果您的filterProxy模型中有QModelIndex,则需要使用QAbstractProxyModel :: mapToSource()从项目模型将其转换为QModelIndex。
答案 1 :(得分:1)
我通过评论线来解决了这个问题&#34; emit layoutChanged()&#34;对于我的insertRows,removeRows方法。最初代码没有这一行,但QTreeView的更新问题迫使我包含它,而不包括&#34; emit layoutAboutToChanged()&#34;。由于某种原因,似乎更新问题已经消失。
无论如何,感谢那些试图提供帮助的人。在不久的将来我肯定需要更多。