Help implementing a qlist model



  • Hi all,
    I'm trying to implement a list model so that the GUI can display in a list a set of EventCategory (a custom class of mine). However I've a few problems understanding how to implement it:

    @

    QVariant EventCategoryModel::data(const QModelIndex &index, int role) const{

    if( ! index.isValid() || index.row() > _categories.size() )
        return QVariant();
    
    if( role == Qt::DisplayRole )
        return _categories.at( index );
    else
        return QVariant();
    

    }

    bool EventCategoryModel::addCategory(EventCategory category){
    _categories.append( category );
    emit dataChanged( QModelIndex(), QModelIndex() );
    }

    bool EventCategoryModel::removeCategory(EventCategory category){
    _categories.removeOne( category );
    emit dataChanged( QModelIndex(), QModelIndex() );
    }

    QList<EventCategory> EventCategoryModel::categories(){
    return *_categories;
    }
    @

    Having the following definition for _categories:

    @QList<EventCategory>* _categories@

    Now, the first problem is with the data method, that gives me a compilation error while returning an element of the list, since it is not a qvariant. My knolwegde of qvariant is weak, so how can I convert a custom object into a qvariant?
    Second, is the implementation of the addCategory and removeCategory methods correct? Because I cannot understand very well the use of QModelIndex.

    Thanks



  • First, please read "this comment":http://developer.qt.nokia.com/doc/qt-4.7/model-view-programming.html#note-13 in the docs: it would probably be a good idea not to manage the actual list of EventCategories in your model itself (if it is not trivial to do so). However, your case looks fairly trivial so far, so perhaps it is ok in your case.

    What you need to return from data(), is something that matches the role requested. In the case of Qt::DisplayData, that means a string, like the name of the EventCategory. You can also return data for roles such as the tooltip (another string) and an icon (a QPixmap), data on if the item is checked (A Qt::CheckState), etc. Even if a EventCategory could be put in a QVariant (that is possible, if you want), returning it for one of the standard roles is probably not a good idea. See for the complete list of what is expected for each role the documentation of Qt::ItemDataRole.

    Note that you are using the way you insert data incorrectly as well. You should use beginInsertRows(), then do the actual insertion, and then call endInsertRows(). The same goes for removing; there is a similar pair of methods to call for those.

    Is there a reason you choose to use a pointer to a QList instead of just a QList?



  • Hi,

    first of all, I think you should avoid naming your identifiers with a beginning '_'. If I remember correctly, those kind of identifiers are reserved by the standard.

    Let's now examine your code :

    @
    QList<EventCategory>* _categories
    @

    I don't think you want a pointer to a QList here. You surely simply want :

    @QList<EventCategory> categories@

    So the code is not compiling because you've got some syntax errors here (you've got to use -> with a pointer).

    @
    if( role == Qt::DisplayRole )
    return _categories.at( index );
    @

    QList doesn't know how to get a data on a QModelIndex. Instead, your should write :

    @
    return categories.at( index.row() );
    @

    However, as you pointed out, QVariant doesn't know how to handle an EventCategory object. So, if you really want to return such an object encapsulated into a QVariant, you will have to declare it with "Q_DECLARE_METATYPE":http://doc.qt.nokia.com/4.7-snapshot/qmetatype.html#Q_DECLARE_METATYPE

    But if you do this, the default delegate won't really know how to render correctly your EventCategory. So, you could directly format it like :

    @
    if( role == Qt::DisplayRole ) {
    const EventCategory &cat = categories.at( index.row() );

        return cat.name();
    

    }
    @

    Assuming your EventCategory has a name property.

    Now :

    @
    bool EventCategoryModel::addCategory(EventCategory category){
    _categories.append( category );
    emit dataChanged( QModelIndex(), QModelIndex() );
    }

    bool EventCategoryModel::removeCategory(EventCategory category){
    _categories.removeOne( category );
    emit dataChanged( QModelIndex(), QModelIndex() );
    }
    @

    This is also wrong. Instead of emitting dataChanged, you have to call respectively "beginInsertRows":http://doc.qt.nokia.com/latest/qabstractitemmodel.html#beginInsertRows "endInsertRows":http://doc.qt.nokia.com/latest/qabstractitemmodel.html#endInsertRows "beginRemoveRows":http://doc.qt.nokia.com/latest/qabstractitemmodel.html#beginRemoveRows and finally "endRemoveRows":http://doc.qt.nokia.com/latest/qabstractitemmodel.html#endRemoveRows



  • Thanks for the answers, now it is more clear.
    Since my model is really simple and linear, I converted the QListView in a QListWidget and operate on it adding and removing items. At least until I know better the view/model architecture behind Qt.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.