首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在ListView中使用QAbstractListModel

在ListView中使用QAbstractListModel
EN

Stack Overflow用户
提问于 2014-12-10 19:35:33
回答 3查看 17.4K关注 0票数 10

我是Qt的新手,所以请容忍我。

我已经成功地从Object的StringList和QList填充了ListView *

我现在正在努力的是使用在C++中定义的派生QAbstractListModel的类来填充QML中的ListView。

下面是我的CPP类的原型:

代码语言:javascript
复制
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是一个简单的类,包含两个成员,一个QColor和一个QString (该类没有扩展QObject)。

我必须实现上面所有的函数,因为它们在底层类中是纯虚的(这正常吗?到目前为止,在教程/示例中,人们只提到了roleNames和数据)。

roleNames和data的实现如下:

代码语言:javascript
复制
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部分如下所示:

代码语言:javascript
复制
 ListView {
    id: quickMessageListdata
    model: quickListModel
    delegate: Rectangle {

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

到目前为止,这是我对如何在CPP和QML中实现的理解。为了将这两者联系起来,我使用了以下代码:

代码语言:javascript
复制
MessageListEntryModel* model =new MessageListEntryModel();
// Add various entries
...
// assign model in QML
m_pViewRef->rootContext()->setContextProperty("quickListModel",model);

使用上面的代码,当运行时,ListView中没有显示任何内容,并且我得到以下错误:

代码语言:javascript
复制
Unable to assign [undefined] to QString

Unable to assign [undefined] to QColor

我还注册了要导出到QML的模型类(不知道这是否有必要):

代码语言:javascript
复制
qmlRegisterType<MessageListEntryModel> ("dlti.exported",1,0,"MessageListEntryModel");

所以很明显,要么是我搞错了QAbstractListItem派生类的正确用法,要么就是我错过了一个简单的关键信息。

我非常感谢一些相关示例/教程的指导(其中还向您展示了如何在QML中正确地访问模型中的数据,因为我注意到在CPP中它从不通过data函数传递)。

另外请注意,我使用的是qt5,所以qt4.8示例不能解决这个问题。

编辑

在经历了长时间的沮丧之后,我终于解决了这个该死的东西的问题:

我的roleNames函数签名错误!重载的正确签名为:

代码语言:javascript
复制
protected :
      QHash<int,QByteArray> roleNames() const;

请注意protected和const修饰符。

在以正确的方式声明函数之后,一切都很正常。

需要进一步注意的是,实现data和rowCount就足够了:)。

谢谢你的帮助。我将接受BaCaRoZzo的答案,因为我只是在查看了示例中的代码后才弄清楚这一点。

顺便说一句,它在message和model.message上都能很好地工作。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-12-11 18:44:11

如何实现you方法?您应该使用类似于我的注释中提供的示例中的方法。

docs

insertRows()实现必须在将新行插入数据结构之前调用beginInsertRows(),并且它的必须在之后立即调用endInsertRows()。

你应该有类似这样的东西:

代码语言:javascript
复制
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
} 

使用

代码语言:javascript
复制
int MessageListEntryModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_vpMessages.count();
}

同样,@Jonathan Mee的评论是正确的:只使用委托中的角色名称,就像您在模型中定义它们一样。如果其他一切都是正确的,这就是访问数据的方式。

Model subclassing reference是理解C++模型实现和用法的最佳文档之一。在这篇文档中清楚地描述了哪些方法是子类化的最重要的方法,以及目的是什么。

至于实现的方法,则要视需要而定。根据模型上可能的操作,应该实现不同的方法(有关详细信息,请参阅上面的链接)。可以在其中添加/删除项的ListView模型可以继承自QAbstractListModel,并且只依赖于大多数函数的默认实现。您只需要data()roleNames()rowCount(),正如您在大多数示例中已经看到的那样。

如果您还需要编辑数据,而不仅仅是添加/删除数据,那么您还需要其他函数,特别是setData()。您也有责任通过信号dataChanged()通知附加视图在setData()中发生的任何模型修改。再次参考上面提供的子类化参考。

另请注意,如果使用Q_INVOKABLE修饰符修改add方法,即它被声明为

代码语言:javascript
复制
Q_INVOKABLE void add(params...);

在模型头中,您也可以从QML调用它(因为模型被设置为上下文属性),并且您可以这样写,例如:

代码语言:javascript
复制
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。对于您当前的需求,它是多余的。

票数 9
EN

Stack Overflow用户

发布于 2014-12-10 20:11:07

嗯..。我不太熟悉QML,但我相信这就是你的问题所在:http://qt-project.org/doc/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel

根据链接,您似乎需要将Text块更改为:

代码语言:javascript
复制
Text{
    text: message
    color: messagecolor
}

进一步阅读:http://qt-project.org/forums/viewthread/5491

票数 1
EN

Stack Overflow用户

发布于 2019-02-04 21:02:35

我以前也经历过用Qt C++创建自己的列表模型的艰难时期。为了避免C++模型的开发开销,我开始使用QSyncable ( Ben Lau的现有QAbstractListModel实现)。你可以在GitHub上找到它。

该项目最好的部分是JsonListModel QML类型。它可以将您在QML中创建或获取的任何变体JSON列表转换为全功能的QML ListModel。这为使用JSON或REST服务的应用程序节省了大量的时间和精力。你可以在here上找到它如何工作的详细指南。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27400025

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档