2014-12-10 8 views
3

Я новичок в Qt, поэтому, пожалуйста, несите меня.Использование QAbstractListModel в ListView

Я успешно удалось заполнить ListView из StringList и QList Объекта *

Что я теперь борется с, чтобы заполнить ListView в QML, используя класс, определенный в C++, производный QAbstractListModel.

Вот прототип моего класса CPP:

class MessageListEntryModel : public QAbstractListModel 
{ 

Q_OBJECT 
public: 

enum eMLERoleTypes 
{ 
    MLERT_MSG = Qt::UserRole+1, 
    MLERT_COLOR 
}; 

           MessageListEntryModel(QObject* parent=0); 
     virtual     ~MessageListEntryModel(); 

     void     AddEntry(QString aMessage, QColor aColor); 

     // pure virtuals implementations 
     QVariant    data(const QModelIndex &index, int role = Qt::DisplayRole) const; 
     int      rowCount(const QModelIndex &parent = QModelIndex()) const ; 
     int      columnCount(const QModelIndex &parent = QModelIndex()) const ; 
     QModelIndex    index(int row, int column, const QModelIndex &parent = QModelIndex()) const; 
     QModelIndex    parent(const QModelIndex &child) const ; 

     QHash<int,QByteArray> roleNames(); 
private: 
QList<MessageEntry*> m_vpMessages; 

MessageEntry простой класс, который содержит 2, а членов Ассоциации QColor и QString (класс не распространяется QObject).

Мне пришлось реализовать все вышеперечисленные функции, так как они являются чистыми виртуальными в базовом классе (это обычная до сих пор в учебниках/примерах люди упоминаются только о именах и данных о роли).

На пути осуществления roleNames и данных являются следующие:

QHash<int,QByteArray> MessageListEntryModel::roleNames() 
{ 
    QHash<int,QByteArray> rez; 
    rez[MLERT_MSG]="message"; 
    rez[MLERT_COLOR]="messagecolor"; 
    return rez; 
} 

QVariant MessageListEntryModel::data(const QModelIndex &index, int role) const 
{ 
    qDebug()<<" Data asked for "<<index.row()<<" and role "<<role; 
    if (index.row()<0 || index.row()>=m_vpMessages.size()) 
    { 
     return QVariant(); 
    } 
    MessageEntry* entry = m_vpMessages[index.row()]; 
    if (role == MLERT_MSG) 
    { 
     return QVariant::fromValue(entry->message); 
    } else if (role == MLERT_COLOR) 
    { 
     return QVariant::fromValue(entry->messageColor); 
    } 
    // should be unreachable code 
    return QVariant(); 
} 

Часть QML в виде списка что-то вроде этого:

ListView { 
    id: quickMessageListdata 
    model: quickListModel 
    delegate: Rectangle { 

     width: 400 
     height: 25 
     color:"#000000" 
     Text{ 
      text: model.message 
      color: model.messagecolor 
     } 
    } 

До сих пор это мое понимание о том, как реализовать вещи в CPP и QML. Для связывания этих двух, я использую следующий код:

MessageListEntryModel* model =new MessageListEntryModel(); 
// Add various entries 
... 
// assign model in QML 
m_pViewRef->rootContext()->setContextProperty("quickListModel",model); 

С кодом выше, когда не работает ничего не отображается в ListView, и я получаю следующие ошибки:

Unable to assign [undefined] to QString 

Unable to assign [undefined] to QColor 

I» м и регистрируя класс модели, которая будет экспортироваться в QML (не знаю, если это необходимо):

qmlRegisterType<MessageListEntryModel> ("dlti.exported",1,0,"MessageListEntryModel"); 

Так что вполне очевидно, что либо я missuderstood надлежащее использование производного класса QAbstractListItem ИЛИ Я пропустил простую жизненно важную ключевую информацию.

Я хотел бы поблагодарить некоторых указателей на некоторые соответствующие образцы/учебные пособия (которые также показывают, как правильно обращаться к данным из модели в QML, поскольку я заметил, что в CPP она никогда не проходит через функцию данных).

Также обратите внимание, что я использую qt5, поэтому образцы qt4.8 не будут делать трюк.

EDIT

После долгих часов разочарования, я наконец-то удалось, что было не так с проклятой вещи:

Моя функция roleNames подпись была неправильно! Правильная подпись для перегрузки является:

protected : 
     QHash<int,QByteArray> roleNames() const; 

Пожалуйста, обратите внимание на защиту и Конст модификаторов.

После объявления функции правильный путь, все это работало нормально.

Для дальнейшего уведомления, реализация данных и rowCount была достаточной :).

Спасибо за помощь. Я согласен с ответом BaCaRoZzo, так как я только сумел понять это, посмотрев код на примере.

Как примечание стороны, он хорошо работает как с сообщением, так и с моделью.message.

ответ

5

Как вы реализуете метод добавления? Вы должны использовать метод, как в примере, приведенном в моем комментарии.

От docs:

InsertRows() реализация должна вызвать beginInsertRows() перед вставкой новых строк в структуру данных, и должны вызвать endInsertRows() сразу же после этого.

Вы должны иметь что-то вроде:

void MessageListEntryModel::add(params...) 
{ 
    beginInsertRows(QModelIndex(), rowCount(), rowCount()); // kindly provided by superclass 
    // object creation based on params... 
    m_vpMessages << objectCreated; 
    endInsertRows();           // kindly provided by superclass 
} 

с

int MessageListEntryModel::rowCount(const QModelIndex & parent) const { 
    Q_UNUSED(parent); 
    return m_vpMessages.count(); 
} 

Кроме того, Mee комментарий @ Джонатан правильно: использовать только имена ролей внутри делегата, как вы определили их в модель. Если все остальное верно , то - это способ доступа к данным.


Один из лучшей документации части, чтобы понять, C++ реализации моделей и использование является Model subclassing reference. В этом документе четко изображены, которые являются наиболее важными методами для подкласса и для каких целей.

Что касается методов реализации, это действительно зависит от потребностей. В зависимости от возможных действий над моделью должны быть реализованы различные методы (подробнее см. Ссылку выше). Модель для ListView, в которой элементы могут быть добавлены/удалены, может наследовать от QAbstractListModel и просто полагаться на реализации по умолчанию для большинства функций. Вам просто нужны data(), roleNames() и rowCount(), как вы уже видели в большинстве примеров.

Если вам также необходимо изменить данные, не просто добавляя/удаляя их, тогда вам также нужны другие функции, в частности setData(). Также ваш обязан уведомить присоединенные виды с любой модификацией модели, произошедшей в setData(), по сигналу dataChanged(). Обратитесь к приведенному выше описанию подкласса.

Заметим также, что, если метод add модифицирован с модификатором Q_INVOKABLE, т.е. он объявлен как

Q_INVOKABLE void add(params...); 

в заголовке модели, вы можете также вызвать его из QML (так как модель устанавливается как контекст собственности), и вы можете написать, например:

ListView { 
    id: quickMessageListdata 
    model: quickListModel 
    delegate: Rectangle { 

     width: 400 
     height: 25 
     color:"#000000" 
     Text{ 
      text: model.message 
      color: model.messagecolor 
     } 
    } 

    Component.onCompleted: { 
     quickListModel.add(params) 
     quickListModel.add(params)  
    } 
} 

для вставки элементов в представлении, как только создается мнение. Очевидно, что такой же подход можно применять и к другим сигналам QML, чтобы вы могли реагировать на события QML и вызывать поведение при добавлении/удалении.

И, наконец, вам не нужно регистрировать модель с помощью qmlRegisterType. Для вашего текущего требования это лишнее.

+2

@BaCaRoZo Я чувствую, что я даже узнал из этого, спасибо! –

1

Хммм ... Я не супер знакомы с QML, но я считаю, что это ваша проблема: http://qt-project.org/doc/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel

По ссылке он выглядит, как вам нужно изменить Text блок:

Text{ 
    text: message 
    color: messagecolor 
} 

Дополнительная информация: http://qt-project.org/forums/viewthread/5491

+0

Выполнение того, что вы предложили, дает мне ReferenceError «message» не определен (То же самое для цвета сообщения). Я знаю, какой учебник вы связали (это на самом деле моя отправная точка). Проблема в том, что учебник неполный/код из учебника не работает (например: вам нужно реализовать больше, чем просто функцию rolemodels). – MichaelCMS

+2

В этом же примере находится пример 'Примеры \ \ quick \ models \ abstractitemmodel' внутри папки установки Qt. Просто откройте соответствующий '.pro' и осмотритесь. – BaCaRoZzo

Смежные вопросы