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

listviewitem showing no data in QML application

本文关键字:显示 数据 QML 应用程序 listviewitem      更新时间:2023-10-16

我有一个类。

  • dataitem
  • datamodel
  • 界面
  • 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);
};

现在一切正常。在调试器中,我看到模型中的数据是正确的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 }
            }
        }
    }
}

当我将调试器断点设置到我的moddata类和应该返回数据的函数中时,调试器不会停止在那里。看起来程序永远不会进入这个函数。

也许问题是我如何设置模型?功能getmodel()只返回指针。main.cpp:

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

minterface.cpp:

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

有mdatmodel .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;
}

你的主要问题是:

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

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

  • 您没有通知模型(因此视图/QML)您更改了数据。当底层数据发生变化时,你必须通过成对调用函数来告诉模型,这取决于变化是什么:beginResetModel()/endResetModel(), beginInsertRows()/endInsertRows(), beginRemoveRows()/endRemoveRows()等。还有2个非配对信号:dataChanged()modelReset()。请注意,您可以通过始终调用modelReset()来解决问题,但这不是一个好的做法,您应该倾向于使用最特定的函数对。

你也应该阅读Qt文档:

  • 使用c++模型与Qt快速视图> QAbstractItemModel子类
  • QAbstractItemModel Class>受保护的函数

这是你的固定模型。我删除了columnCount()headerData(),因为你不需要它们来使它工作。

MDataModel.h

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);
};

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();
    }

    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;
}

QML修复

delegate: Component
    {
        Rectangle
        {
            width: 250
            height: textItem.height
            Text {
                id: textItem 
                text: host + ' ' + status + ' (' + displayRole +')'
            }
        }
    }

此时,我的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;
}