У меня проблемы с переходом с QTreeWidget
на QtreeView
. Вещи, которые были очевидны и тривиальны с QTreeWidget
, кажутся невозможными с view. В частности: у меня есть главное окно с древовидной структурой. TreeView использует реализованную мной модель, но не напрямую, а через QSortFilterProxyModel
, заданный как модель дерева. Теперь пользователь активирует элемент в дереве, и главные окна получают сигнал itemActivated(QModelIndex item)
. Как узнать, какой элемент базовых данных был активирован? Данные — это вектор, поэтому с помощью TreeWidget я мог просто сохранить векторный индекс элемента в QTreeWidgetItem
, но QModelIndex
даже не имеет setData
API.
QTreeView: поддержание сопоставления между QModelIndex и базовыми данными
Ответы (3)
Вы можете определить пользовательские роли в исходной модели, возвращая базовые данные или идентификатор (если он есть) в качестве варианта. Это имеет то преимущество, что работает с любым количеством прокси-моделей между ними, поскольку данные будут передаваться через модели без изменений, и теперь требуется сопоставление индексов.
Предположим, что модель содержит список контактов со значением struct/class Contact
, содержащим данные. Для этого требуется, чтобы Contact
был зарегистрирован через Q_DECLARE_METATYPE
.
class ContactModel ... {
...
enum Role {
ContactRole=Qt::UserRole,
ContactIdRole
};
QVariant data(...) const {
...
const Contact& contact = ...get from datastructure...
...
switch (role) {
...
case ContactRole:
return QVariant::fromValue( contact );
case ContactIdRole:
return contact.id;
}
}
...
И в коде, получающем индекс:
void SomeWidget::indexSelected(const QModelIndex& index)
{
const int id = index.data(ContactModel::ContactIdRole).toInt();
// look up Contact, do something with it
//or:
const Contact contact = index.data(ContactModel::ContactRole).value<Contact>();
// do something with the contact
...
}
Индекс может быть из самой контактной модели или любого прокси поверх нее — код здесь не должен заботиться.
Как узнать, какой элемент базовых данных был активирован?
Инвертируя прокси-модель:
// supposing to connect this to your itemActivated signal
void onItemActivated(const QModelIndex &index)
{
QModelIndex originalIndex = proxyModel->mapToSource(index);
originalModel->doSomething(originalIndex);
}
Модель для хранения ваших данных. Данные больше не принадлежат элементам/QModelIndex
в представлении. QModelIndex
— это всего лишь уникальный идентификатор, передаваемый между представлением и моделью (в данном случае через QSortFilterProxyModel
). Модель должна наследовать QAbstractItemModel
, в которой есть несколько чистых виртуальных функций, которые необходимо определить (вы можете скопировать шаблон из http://qt-project.org/doc/qt-4.8/itemviews-simpletreemodel.html). Вы будете, например. должны определить QAbstractItemModel::data( const QModelIndex & index, int role = Qt::DisplayRole)
, который определяет, какие данные соответствуют конкретному QModelIndex
.
QSortFilterProxyModel находится между представлением и моделью, но не меняет принципов модели. См. другой ответ на этот вопрос о том, как справиться с конверсией QModelIndex
.
В заключение: QAbstractItemModel::data( const QModelIndex & index)
предоставит вам данные для конкретного QModelIndex
после того, как вы его определили.