Sur cette page

Une application minimale de liste RSS

Une démonstration de la manière de récupérer et d'afficher une ressource réseau.

Cet exemple montre comment récupérer une ressource demandée par l'utilisateur et afficher les données contenues dans la réponse, illustrée par une application de liste RSS. (RDF Site Summary, ou Really Simple Syndication, est un format standard de communication des mises à jour des sites web. Voir https://www.rssboard.org/rss-specification pour plus de détails). L'interface utilisateur de l'illustration est simple, car l'objectif de cet exemple est de montrer comment utiliser le réseau, mais il va de soi qu'une interface plus sophistiquée serait nécessaire pour un lecteur RSS sérieux.

L'exemple montre également comment procéder à une analyse asynchrone des données au fur et à mesure de leur réception, en préservant l'état des variables membres de sorte qu'une analyse incrémentale puisse consommer des morceaux de données au fur et à mesure de leur arrivée sur le réseau. Les constituants du contenu analysé peuvent commencer dans un morceau de données mais ne pas être terminés avant un morceau ultérieur, ce qui oblige l'analyseur à conserver l'état entre les appels.

L'application récupère des informations à partir de l'URL spécifiée, dans ce cas, Qt XML, puis analyse les données XML disponibles.

Le programme principal est assez minimal. Il instancie simplement un widget QApplication et un widget RSSListing, affiche ce dernier et transfère le contrôle au premier. Pour les besoins de l'illustration, il donne au widget l'URL du blog Qt comme valeur par défaut pour la ressource à vérifier.

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    RSSListing rsslisting(u"https://www.qt.io/blog/rss.xml"_s);
    rsslisting.show();
    return app.exec();
}

La classe RSSListing

class RSSListing : public QWidget
{
    Q_OBJECT
public:
    explicit RSSListing(const QString &url = QString(), QWidget *widget = nullptr);

public slots:
    void fetch();
    void finished(QNetworkReply *reply);
    void consumeData();
    void error(QNetworkReply::NetworkError);

private:
    void parseXml();
    void get(const QUrl &url);

    // Parser state:
    QXmlStreamReader xml;
    QString currentTag;
    QString linkString;
    QString titleString;

    // Network state:
    QNetworkAccessManager manager;
    QNetworkReply *currentReply;

    // UI elements:
    QLineEdit *lineEdit;
    QTreeWidget *treeWidget;
    QPushButton *fetchButton;
};

Le widget lui-même fournit une interface utilisateur simple permettant de spécifier l'URL à récupérer et, une fois les mises à jour disponibles affichées, de contrôler le téléchargement des éléments mis à jour. Une page QLineEdit permet de saisir l'URL et une page QTreeWidget d'afficher les résultats une fois qu'ils ont été récupérés.

Le widget télécharge et analyse le RSS (une forme de XML) de manière asynchrone, en transmettant les données à un lecteur XML au fur et à mesure de leur arrivée. Cela permet de lire des sources de données très importantes. Comme les données sont transmises en continu depuis le réseau via le lecteur XML, il n'est pas nécessaire de conserver le texte intégral du XML en mémoire. Dans un autre contexte, une approche similaire peut permettre à l'utilisateur d'interrompre ce chargement incrémental.

Construction
RSSListing::RSSListing(const QString &url, QWidget *parent)
    : QWidget(parent), currentReply(0)
{
    connect(&manager, &QNetworkAccessManager::finished, this, &RSSListing::finished);

    lineEdit = new QLineEdit(this);
    lineEdit->setText(url);
    connect(lineEdit, &QLineEdit::returnPressed, this, &RSSListing::fetch);

    fetchButton = new QPushButton(tr("Fetch"), this);
    connect(fetchButton, &QPushButton::clicked, this, &RSSListing::fetch);

    treeWidget = new QTreeWidget(this);
    connect(treeWidget, &QTreeWidget::itemActivated,
            // Open the link in the browser:
            this, [](QTreeWidgetItem *item) { QDesktopServices::openUrl(QUrl(item->text(1))); });
    treeWidget->setHeaderLabels(QStringList { tr("Title"), tr("Link") });
    treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);

    QHBoxLayout *hboxLayout = new QHBoxLayout;
    hboxLayout->addWidget(lineEdit);
    hboxLayout->addWidget(fetchButton);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addLayout(hboxLayout);
    layout->addWidget(treeWidget);

    setWindowTitle(tr("RSS listing example"));
    resize(640, 480);
}

Le constructeur met en place les différents composants du widget et connecte leurs différents signaux aux slots qu'il doit utiliser pour les gérer.

L'interface utilisateur se compose d'un éditeur de ligne, d'un bouton poussoir et d'un widget d'affichage de liste. La ligne d'édition est utilisée pour saisir l'URL à récupérer ; le bouton poussoir lance le processus de récupération des mises à jour. La ligne d'édition est vide par défaut, mais l'appelant du constructeur peut la remplacer, comme l'a fait notre main(). Dans tous les cas, l'utilisateur peut remplacer la valeur par défaut par l'URL d'un autre flux RSS.

La vue en liste affiche les éléments mis à jour signalés dans le flux RSS. Un double-clic sur l'un d'entre eux envoie son URL au navigateur de l'utilisateur ou à un autre agent utilisateur à l'aide de QDesktopServices::openUrl().

Les emplacements
void RSSListing::fetch() {  lineEdit->setReadOnly(true) ;  fetchButton->setEnabled(false) ;  treeWidget->clear() ; get(QUrl(lineEdit->text())) ; }void RSSListing::consumeData() { int statusCode =  currentReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() ; if (statusCode >= 200 && statusCode < 300) parseXml() ; }void RSSListing::error(QNetworkReply::NetworkError){
    qWarning("error retrieving RSS feed");
    xml.clear() ;  currentReply->disconnect(this) ;  currentReply->deleteLater() ; currentReply = nullptr ; }void RSSListing::finished(QNetworkReply *reply) { Q_UNUSED(reply) ;  lineEdit->setReadOnly(false) ;  fetchButton->setEnabled(true) ; }

Tous les slots sont maintenus simples en déléguant le travail difficile à des méthodes privées.

Lorsque l'utilisateur termine la saisie d'un URL, soit en cliquant sur le bouton "Fetch", soit en appuyant sur la touche retour dans l'édition de ligne, le slot fetch() désactive le bouton "Fetch" et désactive toute modification ultérieure de l'édition de ligne. Il efface l'affichage des mises à jour disponibles et délègue à get() le lancement d'une requête HTTP GET.

Lorsque les données sont reçues, la réponse du réseau déclenche son signal readyRead(), que get() connecte à l'emplacement consumeData(). Ce dernier vérifie que la réponse a obtenu un code d'état correct et, si c'est le cas, appelle parseXml() pour consommer les données.

Si la réponse du réseau reçoit une erreur, celle-ci est transmise à l'emplacement error(), qui signale l'erreur, efface le lecteur de flux XML, se déconnecte de la réponse et la supprime.

À l'issue (réussie ou non) d'une réponse réseau, le slot finished() restaure l'interface utilisateur pour qu'elle soit prête à accepter un nouvel URL à récupérer en réactivant l'édition de ligne et le bouton "Fetch" (Récupérer).

La méthode get()
void RSSListing::get(const QUrl &url)
{
    if (currentReply) {
        currentReply->disconnect(this);
        currentReply->deleteLater();
    }
    currentReply = url.isValid() ? manager.get(QNetworkRequest(url)) : nullptr;
    if (currentReply) {
        connect(currentReply, &QNetworkReply::readyRead, this, &RSSListing::consumeData);
        connect(currentReply, &QNetworkReply::errorOccurred, this, &RSSListing::error);

    }
    xml.setDevice(currentReply); // Equivalent to clear() if currentReply is null.
}

La méthode privée get() est utilisée par l'emplacement fetch() pour lancer une requête HTTP GET. Elle efface d'abord le lecteur de flux XML et, si une réponse est actuellement active, la déconnecte et la supprime. Si l'URL qui lui a été transmise est valide, il demande au gestionnaire d'accès au réseau de l'obtenir. Il connecte ses emplacements pertinents aux signaux de la réponse résultante (le cas échéant) et configure son lecteur de flux XML pour lire les données de la réponse - un objet de réponse de réseau est également un QIODevice, à partir duquel les données peuvent être lues.

La méthode parseXml()
void RSSListing::parseXml() { while (!xml.atEnd()) { xml.readNext() ; if (xml.isStartElement()) { if (xml.name() == u"item") { linkString = xml.attributes().value("rss:about").toString() ; titleString.clear() ; } currentTag = xml.name().toString() ; } else if (xml.isEndElement()) { if (xml.name() == u"item") { QTreeWidgetItem *item = new QTreeWidgetItem;  item->setText(0, titleString) ;  item->setText(1, linkString) ;  treeWidget->addTopLevelItem(item) ; } } else if (xml.isCharacters() && !xml.isWhitespace()) { if (currentTag == "title") titleString += xml.text() ; else if (currentTag == "link") linkString += xml.text() ; } } if (xml.error() && xml.error() ! = QXmlStreamReader::PrematureEndOfDocumentError)        qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
}

Lorsque les données sont reçues, et donc mises à la disposition du lecteur de flux XML, parseXml() lit le flux XML, vérifiant la présence d'éléments item et, à l'intérieur de ceux-ci, d'éléments title et link. Il utilise l'attribut rss:about d'un élément item comme URL dans la colonne Lien de la vue arborescente, à défaut du contenu de son élément link; et il utilise le contenu de l'élément title dans la colonne Titre de la vue arborescente. À la fermeture de chaque élément item, ses détails sont transformés en une nouvelle ligne dans le widget de l'arbre, avec le titre et l'URL extraits dans les colonnes Titre et Lien.

Les variables qui suivent l'état de l'analyse syntaxique - linkString, titleString et currentTag - sont des variables membres de la classe RSSListing, même si elles ne sont accessibles qu'à partir de cette méthode, parce que cette méthode peut être appelée à plusieurs reprises, à mesure que de nouvelles données arrivent, et qu'un morceau de données reçues peut commencer un élément qui n'est pas terminé jusqu'à ce qu'un morceau ultérieur arrive. Cela permet à l'analyseur de fonctionner de manière asynchrone au fur et à mesure que les données arrivent, au lieu d'avoir à attendre que toutes les données soient arrivées.

Exemple de projet @ code.qt.io

Voir aussi QNetworkReply et QXmlStreamReader.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.