listviewitem在QML应用程序中显示无数据

时间:2016-09-12 07:09:36

标签: c++ qt model qml

我有课。

  • 的DataItem
  • 数据模型
  • 接口
  • networkconnector

在dataitem中指定了项目属性。

class MDataItem : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString host READ host WRITE setHost NOTIFY hostChanged)
    Q_PROPERTY(QString service READ service WRITE setService NOTIFY serviceChanged)
    Q_PROPERTY(QString status READ status WRITE setStatus NOTIFY statusChanged)
    Q_PROPERTY(QString lastchck READ lastchck WRITE setLastChck NOTIFY lastchckChanged)
    Q_PROPERTY(QString duration READ duration WRITE setDuration NOTIFY durationChanged)
    Q_PROPERTY(QString info READ info WRITE setInfo NOTIFY infoChanged)

public:
    explicit MDataItem(QObject *parent = 0);

    QString host() const;
    void setHost(const QString &newhost);

    QString service() const;
    void setService(const QString &newservice);

    QString status() const;
    void setStatus(const QString &newstatus);

    QString lastchck() const;
    void setLastChck(const QString &newlastchck);

    QString duration() const;
    void setDuration(const QString &newduration);

    QString info() const;
    void setInfo(const QString &newinfo);

signals:
    void hostChanged();
    void serviceChanged();
    void statusChanged();
    void lastchckChanged();
    void durationChanged();
    void infoChanged();

private:
    QString m_host;
    QString m_service;
    QString m_status;
    QString m_lastchck;
    QString m_duration;
    QString m_info;
};

在模型中是模型规范

class MDataModel : public QAbstractTableModel
{

public:
    enum Columns{
            Host = Qt::UserRole,
            Service = Qt::UserRole + 1,
            Status = Qt::UserRole + 2,
            Duration = Qt::UserRole + 3,
            Info = Qt::UserRole + 4
        };
    MDataModel(QObject *parent = 0);
    QHash<int, QByteArray> roleNames() const;
    void fillData(QNetworkReply *r);
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;

private:
    QString dataAt(int offset) const;
    QList<MDataItem*> items_;

public:
    void prepareDataFinished(QNetworkReply *r);

};

网络从网络上获取一些数据。

class MNetworkConnector : public QObject
{
    Q_OBJECT

public:
    MNetworkConnector(QObject *parent=0);


private:
    QNetworkAccessManager *manager;
    void getData();

private slots:
    void replyFinished(QNetworkReply *r);
    void requireAuth(QNetworkReply *r, QAuthenticator *a);

signals:
    void dataWasChanged(QNetworkReply *r);
};

并在界面中填写模型中的网络数据:

class MInterface : public QObject
{
    Q_OBJECT

public:
    MInterface();
    MDataModel *mainModel;
    MNetworkConnector *newConnection;
    MDataModel* getModel();

public slots:
    void dataWasPrepared(QNetworkReply *r);
};

此时一切都很好。在debuger中,我看到数据在模型中,采用正确的MDataItem格式。

但是当我将模型添加到QML listView时 - 应用程序什么也没显示。 问题出在哪儿?你能用正确的方式推我吗?

Main.cpp看起来:

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    MInterface *myIface = new MInterface();

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("MainModel", myIface->getModel());
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

主qml文件:

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQml 2.0


Window {
    visible: true
    width:  Screen.width / 2
    height: Screen.height / 2

    title: qsTr("webinfo")

    ListView
    {
        id: myList
        visible: true

        header: Header{}
        model: MainModel
        delegate: Item
        {
            Rectangle
            {
                Text { text: host }
            }
        }
    }
}

当我将debuger断点设置到我的modedata类和应该返回数据的函数中时,debuger不会停在那里。它看起来程序永远不会进入这个功能。

也许问题是我如何设置模型?函数getmodel()仅返回指针。 main.cpp中:

engine.rootContext()->setContextProperty("MainModel", myIface->getModel());

minterface.cpp:

MDataModel* MInterface::getModel()
{
    return this->mainModel;
}

有MDataModel.cpp

MDataModel::MDataModel(QObject *parent) : QAbstractTableModel(parent)
{
}

int MDataModel::rowCount(const QModelIndex & /* parent */) const
{
    return items_.count();
}

int MDataModel::columnCount(const QModelIndex & /* parent */) const
{
    return 5;
}

QVariant MDataModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
    {
        return QVariant();
    }

    if (role == Qt::DisplayRole)
    {
        switch(index.column()){
            case Columns::Host:
                return items_.value(index.row())->host();

            case Columns::Service:
                return items_.value(index.row())->service();

            case Columns::Status:
                return items_.value(index.row())->status();

            case Columns::Duration:
                return items_.value(index.row())->duration();

            case Columns::Info:
                return items_.value(index.row())->info();
        }
    }
    return QVariant();
}

QVariant MDataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();

    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
    {
        switch(section){
            case Columns::Host:
                return tr("Host");
            case Columns::Service:
                return tr("Service");
            case Columns::Status:
                return tr("Status");
            case Columns::Duration:
                return tr("Duration");
            case Columns::Info:
                return tr("Info");
        }
    }
    return QVariant();
}


void MDataModel::prepareDataFinished(QNetworkReply *r)
{
    QList<MDataItem*> newItems;
    MDataItem *item = new MDataItem();

    QString data;

    while(r->canReadLine())
    {
        data = r->readLine();

            item = new MDataItem();

            if(data.contains("warning", Qt::CaseInsensitive))
            {
                item->setStatus("WARNING");
            }
            else if(data.contains("critical", Qt::CaseInsensitive))
            {
                item->setStatus("CRITICAL");
            }
            else if(data.contains("unknown", Qt::CaseInsensitive))
            {
                item->setStatus("UNKNOWN");
            }
            item->setHost(reg.cap(0).replace("host=","").toUpper());
        ...
        ...
        }
    }
    items_ = newItems;
    qDebug() << items_;

}

QHash<int, QByteArray> MDataModel::roleNames() const
{
    QHash<int, QByteArray> roles;

    roles[Columns::Host] = "host";
    roles[Columns::Service] = "service";
    roles[Columns::Status] = "status";
    roles[Columns::Duration] = "duration";
    roles[Columns::Info] = "info";

    return roles;
}

2 个答案:

答案 0 :(得分:2)

您的主要问题是:

  • MDataModel继承QAbstractTableModel而不是QAbstractListModel。这不是绝对的问题,因为您可以使用QAbstractTableModel,但由于您在QML中使用ListView,因此您应该更喜欢使用QAbstractListModel

  • 您正在混合角色和列。这是第一点的结果,因为QAbstractListModel隐藏了列的概念。

  • 您没有发信号通知模型(因此视图/ QML)您更改了数据。每当基础数据发生变化时,您必须通过按对方调用函数来告知模型,具体取决于更改的内容:beginResetModel() / endResetModel()beginInsertRows() / endInsertRows(),{ {1}} / beginRemoveRows()等。此目的还有2个不成对的信号:endRemoveRows()dataChanged()。请注意,您可以通过始终调用modelReset()来逃避,但这不是一个好习惯,您应该赞成使用最特殊的功能。

您还应该阅读Qt文档:

这是你修复模型。我删除了modelReset()columnCount(),因为您不需要它们来使其正常工作。

<强> MDataModel.h

headerData()

<强> MDataModel.cpp

class MDataModel : public QAbstractListModel
{

public:
    enum Role{
            Host = Qt::UserRole,
            Service,
            Status,
            Duration,
            Info
        };
    MDataModel(QObject *parent = 0);
    QHash<int, QByteArray> roleNames() const;
    void fillData(QNetworkReply *r);
    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;

private:
    QString dataAt(int offset) const;
    QList<MDataItem*> items_;

public:
    void prepareDataFinished(QNetworkReply *r);

};

QML修复

MDataModel::MDataModel(QObject *parent) : QAbstractListModel(parent)
{
}

int MDataModel::rowCount(const QModelIndex & /* parent */) const
{
    return items_.count();
}


QVariant MDataModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
    {
        return QVariant();
    }


    switch(role){
        // For C++ views
        case Qt::DisplayRole:
            return items_.value(index.row())->host();


        // For QML views
        case Host:
            return items_.value(index.row())->host();

        case Service:
            return items_.value(index.row())->service();

        case Status:
            return items_.value(index.row())->status();

        case Duration:
            return items_.value(index.row())->duration();

        case Info:
            return items_.value(index.row())->info();

    }
    return QVariant();
}



void MDataModel::prepareDataFinished(QNetworkReply *r)
{
    QList<MDataItem*> newItems;
    MDataItem *item = new MDataItem();

    QString data;

    while(r->canReadLine())
    {
        data = r->readLine();

            item = new MDataItem();

            if(data.contains("warning", Qt::CaseInsensitive))
            {
                item->setStatus("WARNING");
            }
            else if(data.contains("critical", Qt::CaseInsensitive))
            {
                item->setStatus("CRITICAL");
            }
            else if(data.contains("unknown", Qt::CaseInsensitive))
            {
                item->setStatus("UNKNOWN");
            }
            item->setHost(reg.cap(0).replace("host=","").toUpper());
        ...
        ...
        }
    }

    // Call beginResetModel() and endResetModel() to tell the model
    // and the view the data changed.
    beginResetModel();
    items_ = newItems;
    endResetModel();
    qDebug() << items_;

}

QHash<int, QByteArray> MDataModel::roleNames() const
{
    QHash<int, QByteArray> roles;

    roles[Host] = "host";
    roles[Service] = "service";
    roles[Status] = "status";
    roles[Duration] = "duration";
    roles[Info] = "info";

    // Add displayRole so that you can get what C++ views displays in QML
    // e.g Text { text: host + ' ' + status + ' (' + displayRole +')' }
    roles[Qt::DisplayRole] = "displayRole";

    return roles;

}

答案 1 :(得分:0)

此时,我的MDataModel.h和MDataModel.cpp如下所示:

MDataModel.h

class MDataModel : public QAbstractListModel
{

public:
    enum icingaRoles{
            host,
            service,
            status,
            duration,
            info
        };
    MDataModel(QObject *parent = 0);
    QHash<int, QByteArray> roleNames() const;
    void fillData(QNetworkReply *r);
    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;

private:
    QString dataAt(int offset) const;
    QList<MDataItem*> items_;

public:
    void prepareDataFinished(QNetworkReply *r);

};

MDataModel.cpp

MDataModel::MDataModel(QObject *parent) : QAbstractListModel(parent)
{
}

int MDataModel::rowCount(const QModelIndex & /* parent */) const
{
    return items_.count();
}


QVariant MDataModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
    {
        return QVariant();
    }

    if (role == Qt::DisplayRole)
    {
        switch(index.column()){
            case host:
                return items_.value(index.row())->host();

            case service:
                return items_.value(index.row())->service();

            case status:
                return items_.value(index.row())->status();

            case duration:
                return items_.value(index.row())->duration();

            case info:
                return items_.value(index.row())->info();

        }
    }

    return QVariant();
}


void MDataModel::prepareDataFinished(QNetworkReply *r)
{
    QList<MDataItem*> newItems;
    MDataItem *item = new MDataItem();

    QString data;

    while(r->canReadLine())
    {
        data = r->readLine();

        QRegExp reg;
        if(data.contains("statusbgwarning'><a href", Qt::CaseInsensitive) || data.contains("statusbgcritical'><a href", Qt::CaseInsensitive) || data.contains("statusbgunknown'><a href", Qt::CaseInsensitive))
        {
            item = new MDataItem();
            newItems.append(item);

            if(data.contains("warning", Qt::CaseInsensitive))
            {
                item->setStatus("WARNING");
            }
            else if(data.contains("critical", Qt::CaseInsensitive))
            {
                item->setStatus("CRITICAL");
            }
            else if(data.contains("unknown", Qt::CaseInsensitive))
            {
                item->setStatus("UNKNOWN");
            }
        ...
        ...
    }
    // Call beginResetModel() and endResetModel() to tell the model
    // and the view the data changed.
    beginResetModel();
    items_ = newItems;
    endResetModel();
}


QHash<int, QByteArray> MDataModel::roleNames() const
{
    QHash<int, QByteArray> roles;

    roles[host] = "host";
    roles[service] = "service";
    roles[status] = "status";
    roles[duration] = "duration";
    roles[info] = "info";

    return roles;
}