2011-08-31 47 views
3

我已經創建了一個定製的QAbstractItemModel派生模型,該模型包含一系列樹狀分層結構的XML數據,並將顯示在QTreeView中,如圖所示:當通過源模型函數從源模型中刪除一行時,QSortFilterProxyModel崩潰

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 

我還是很新的Qt的模型/視圖編程和這個錯誤真的有令人望而生畏,讓我撓了腦袋好幾天。我希望在這裏有人能夠幫我在這裏失去我的頭髮!謝謝!

編輯:更新,包括一些源代碼

我的測試項目有兩個對話框窗口,每一個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元素時,會附加一個Sort-Filter模型。

這裏是我的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. 

更新:這是錯誤的發出layoutChanged()沒有發佈layoutAboutToBeChanged()?

+0

你可以發佈代碼的一部分(加上相關的周邊線)你刪除行嗎? –

+0

我已添加相關代碼。 – ksming

+0

查看QSortFilterProxyModel和QAbstractItemModel和文檔的實現代碼後,我只是意識到在發佈layoutChanged()之前,我沒有在removeRows/removeColumns中發佈layoutAboutToBeChanged()。我想知道這是否是問題?但是再一次,我從來沒有見過任何例子在removeRows函數中發出任何信號,並且仍然完美地工作。 :( – ksming

回答

1

我已經通過爲我的insertRows,removeRows方法註釋行「emit layoutChanged()」來解決此問題。最初的代碼沒有這條線,但QTreeView的更新問題迫使我包括它,而不包括「emit layoutAboutToChanged()」。由於某種原因,更新問題似乎已經消失。

無論如何感謝那些試圖幫助。在不久的將來我肯定會需要更多。

+0

你是否在插入代碼周圍調用了begin/endInsertRows()? – mlvljr

+0

layoutAboutToChanged應該是layoutAboutToBeChanged –

1

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

如果您的filterProxy模型中有QModelIndex,則需要使用QAbstractProxyModel :: mapToSource()將其轉換爲項目模型中的QModelIndex。

+0

我知道它們不能混用,但在我的測試項目中,我直接使用包含源模型的QTreeView的選擇模型來編輯,添加,刪除行。QSortFilterProxyModel子類的QTreeView位於另一個窗口(現在就是這樣),無論如何,我一定會注意到你後面的編碼技巧 – ksming

相關問題