gpt4 book ai didi

c++ - 用qml ListView显示Json数据

转载 作者:行者123 更新时间:2023-11-30 05:03:38 30 4
gpt4 key购买 nike

我目前正在开发一个自动收报机客户端,它从网络 api 轮询数据,将其交给 ListModel,然后用于在 qml ListView 中显示数据。

class TickerClient : public QObject
{
Q_OBJECT

public:
explicit TickerClient(QObject *parent = nullptr);

QList<QVariantMap> items() const;

protected:
void registerErrorHandlers(QNetworkReply *reply);

signals:
void statusChanged(QNetworkAccessManager::NetworkAccessibility acc);
void dataChanged();

void preItemRefresh();
void postItemRefresh();

public slots:
void fetch(int start = 0, int limit = 100);

protected slots:
void onReceive(QNetworkReply *reply);

protected:
QSharedPointer<QNetworkAccessManager> mNetMan;
QList<QVariantMap> mItems;
};

class TickerModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(TickerClient *client READ client WRITE setClient)

public:
explicit TickerModel(QObject *parent = nullptr);

enum {
IdRole = Qt::UserRole + 1,
NameRole,
SymbolRole,
...
};

// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

QHash<int, QByteArray> roleNames() const override;

TickerClient *client() const;
void setClient(TickerClient *client);

private:
TickerClient *mClient;
};

ticker 客户端不仅获取数据,还处理获取的数据并将其作为 QVariantMap 列表公开给周围的 ListModel。

void TickerClient::onReceive(QNetworkReply *reply)
{
if (!reply)
return;

if(reply->error()) {
qCritical() << "Error: "
<< reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString();
return;
}

// Read all data as json document.
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());

if(!jsonDoc.isArray()) {
qCritical() << "Error: Expected array";
return;
}

emit preItemRefresh();

mItems.clear();

QJsonArray currencies = jsonDoc.array();
for(int i = 0; i < currencies.count(); i++) {
QJsonObject currency = currencies[i].toObject();
mItems.append(currency.toVariantMap());
}

emit postItemRefresh();

reply->deleteLater();
}

TickerClient 和 TickerModel 都暴露给 qml:

qmlRegisterType<TickerModel>("Ticker", 1, 0, "TickerModel");
qmlRegisterUncreatableType<TickerClient>("Ticker", 1, 0, "TickerClient",
QStringLiteral("MarketCapProvider should not be created in QML"));

TickerClient tickerClient;

QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("tickerClient", &tickerClient);

然后将暴露的客户端交给模型并每 5 秒刷新一次:

ListView {
id: page

Timer {
interval: 5000
running: true
repeat: true
triggeredOnStart: true
onTriggered: {
var pos = scrollBar.position
tickerClient.fetch()
scrollBar.position = pos
}
}

ScrollBar.vertical: ScrollBar {
id: scrollBar
}

model: TickerModel {
client: tickerClient
}

delegate: RowLayout {
width: parent.width
spacing: 10

Label {
text: "#" + model.rank
padding: 5
}

Label {
text: model.name
padding: 5
}
}
}

但是,由于返回了错误的数据,数据的获取似乎效果不佳。因此,如果我请求 model.name,我可能会以 model.rank 结束。以下代码用于获取给定的 indexrole 对的条目。

QVariant TickerModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || !mClient)
return QVariant();

auto it = roleNames().find(role);
if(it != roleNames().end())
return mClient->items().at(index.row())[it.value()];
else
qDebug() << "Didn't match a role";

return QVariant();
}

QHash<int, QByteArray> TickerModel::roleNames() const
{
static const QHash<int, QByteArray> names{
{ IdRole, "id" },
{ NameRole, "name" },
...
};

return names;
}

TickerClient *TickerModel::client() const
{
return mClient;
}

void TickerModel::setClient(TickerClient *client)
{
beginResetModel();

if(mClient) {
mClient->disconnect(this);
}

mClient = client;
if(mClient) {
connect(mClient, &TickerClient::preItemRefresh, this, [=]() {
beginResetModel();
});

connect(mClient, &TickerClient::postItemRefresh, this, [=]() {
endResetModel();
});
}

endResetModel();
}

什么,我做错了吗?我如何为更复杂的 Json 对象扩展这个解决方案?

最佳答案

您正在清除 mItems,然后在 onReceive 方法中将新项目附加到它。您没有显示模型是否正在收听 postItemRefresh 信号。无论如何,您应该调用 beginResetModelendResetModel

例如将以下插槽添加到您的 TickerModel 并将其连接到 postItemRefresh 信号以使您的模型与新数据同步:

void TickerModel::reset()
{
beginResetModel();
endResetModel();
}

编辑:

当事情搞砸时,您应该添加打印或通过调试器使用您的模型 data() 调用的参数。此外,请确保在更新项目时调用 beginResetModel 和 endResetModel。

您的 rowCount 是否返回 mClient->items().count()

要处理更复杂的 json 对象,而不是:

QJsonArray currencies = jsonDoc.array();
for(int i = 0; i < currencies.count(); i++) {
QJsonObject currency = currencies[i].toObject();
mItems.append(currency.toVariantMap());
}

您不处理 QVariantMap,而是将更复杂的 json 对象解析为您自己的类,该类为数据提供 getter:

QJsonArray currencies = jsonDoc.array();
for(int i = 0; i < currencies.count(); i++) {
QJsonObject currency = currencies[i].toObject();
ComplexCurrency c;
c.read(currency);
mItems.append(c);
}

你的类(class):

class ComplexCurrency
{
public:
int id() const;
QString name() const;
bool enabled() const;
QList<QVariantMap> items();

void read(const QJsonObject &json);

private:
int m_id;
QString m_name;
bool m_enabled;
QList<QVariantMap> m_items;
...
};

void ComplexCurrency::read(const QJsonObject &json)
{
m_id = json["id"].toInt();
m_name = json["name"].toString();
m_enabled = json["enabled"].toBool();
// parse items array here
}

然后在模型数据()中:

QVariant TickerModel::data(const QModelIndex &index, int role) const
{
if ((index.row() < 0 || index.row() >= mClient->items().count()) || !mClient)
return QVariant();

const ComplexCurrency &c = mClient->items().at(index.row());
if (role == NameRole)
return c.name();
else if (role == SomethingRole)
return c.something();

return QVariant();
}

关于c++ - 用qml ListView显示Json数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49341739/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com