階層構造を持ち、ツリービューで表示する必要があるQtクラスを使用してアプリケーションを作成しています(QTreeViewウィジェットを使用しています)。データ自体は次のようになります。
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;
}
QAbstractItemModelを実装するStatisticsModelというクラスがあります。これを使用して、StatisticsEntryツリーに格納されているデータを操作および表示します。このクラスには、StatisticsEntryレコードをモデルにプッシュするために使用するaddStatisticsDataというメソッドがあります。メソッドは大まかに次のようになります。
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メソッドは次のとおりです。
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メソッドは次のとおりです。
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メソッドです。
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の並べ替え機能を提供します。モデルをツリービューウィジェットに接続する次のコードがあります。
メインウィンドウのヘッダー:
...
StatisticsModel* _statisticsModel;
StatisticsProxyModel* _statisticsProxyModel;
...
メインの未亡人のコンストラクターで
...
_statisticsModel = new StatisticsModel(ths);
_statisticsProxyModel = new StatisticsProxyModel(htis);
...
_statisticsProxyModel->setSourceModel(_statisticsModel);
ui->statisticsTreeView->setModel(_statisticsProxyModel);
...
アプリケーションには、選択したアイテムをモデルから削除できるボタンもあります。現在、QTreeView :: selectionModel()-> currentIndexでのみテストしており、当面は複数選択は行いません。
StatisticsModel::removeRowsメソッドの次のコードがあります
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;
}
問題は、QAbstractItemModel :: removeRowメソッドを使用してアイテムを削除すると、例外が発生し、スタックトレースが次のようになる場合があることです。
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メソッドは次のとおりです。
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変数に関連付けられた値が無効に見えます。ポインタ自体がアクセスできないメモリを指しているか、メンバーのQListにエントリがないか、エントリによってメモリアクセス違反が発生します。親メソッドが正しくない可能性がありますが、親インデックスをフェッチする方法-qabstractItemModelドキュメントでは、そのメソッドでQModelIndex :: parentを使用しないと、無限再帰が作成されます。
どんな助けもいただければ幸いです、