QTreeView: maintaining mapping between QModelIndex and underlying data

帅比萌擦擦* 提交于 2019-12-11 08:56:12

问题


I have problems migrating from QTreeWidget to QtreeView. Things that were obvious and trivial with QTreeWidget seem to be impossible with view. Specifically: I have a main window with a treeview in it. TreeView uses the model I've implemented, but not directly – through QSortFilterProxyModel that is set as a tree's model. Now, the user activates an item in the tree and main windows receives a signal itemActivated(QModelIndex item). How can I tell which item of the underlying data was activated? Data is a vector, so with TreeWidget I could just store an item's vector index in the QTreeWidgetItem, but QModelIndex doesn’t even have setData API.


回答1:


You can define custom roles in your source model, returning the underlying data or an identifier (if there's one) as variant. This has the advantage it works with any number of proxy models in between, as the data will be passed through the models unaltered and now mapping of indexes is required.

Assuming a model listing contacts, with a value struct/class Contact holding the data. This requires Contact to be registered via 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;
        }
    }
    ...

And in the code receiving the index:

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

    ...
}

The index can be from the contact model itself, or any proxy on top of it - the code here doesn't have to care.




回答2:


How can I tell which item of the underlying data was activated?

By inverting the proxy model:

// supposing to connect this to your itemActivated signal
void onItemActivated(const QModelIndex &index)
{
    QModelIndex originalIndex = proxyModel->mapToSource(index);
    originalModel->doSomething(originalIndex);
}



回答3:


The model to stores your data. The data is no longer owned by items/QModelIndex in the view. QModelIndex is only a unique identifier passed between the view and the model (in this case via QSortFilterProxyModel). The model should inherit QAbstractItemModel which has some pure virtual functions that need to be defined (you can copy boilerplate from http://qt-project.org/doc/qt-4.8/itemviews-simpletreemodel.html). You will e.g. have to define QAbstractItemModel::data( const QModelIndex & index, int role = Qt::DisplayRole) which defines which data that corresponds to a particular QModelIndex.

The QSortFilterProxyModel sits between the view and the model, but does not change the principles for the model. See the other answer on this question for how to deal with the QModelIndex conversion.

To conclude: QAbstractItemModel::data( const QModelIndex & index) will give you the data for a particular QModelIndex once you have defined it.



来源:https://stackoverflow.com/questions/18941701/qtreeview-maintaining-mapping-between-qmodelindex-and-underlying-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!