Eine einfache RSS-Anzeigeanwendung
Eine Demonstration, wie man eine Netzwerkressource abruft und anzeigt.
Dieses Beispiel zeigt anhand einer RSS-Listing-Anwendung, wie eine vom Benutzer angeforderte Ressource abgerufen und die in der Antwort enthaltenen Daten angezeigt werden. (RDF Site Summary, auch bekannt als Really Simple Syndication, ist ein Standardformat zur Übermittlung von Aktualisierungen an Websites. Weitere Informationen finden Sie unter https://www.rssboard.org/rss-specification.) Die Benutzeroberfläche in der Abbildung ist einfach gehalten, da der Schwerpunkt dieses Beispiels auf der Nutzung von Netzwerkfunktionen liegt; für einen vollwertigen RSS-Reader wäre jedoch natürlich eine ausgefeiltere Benutzeroberfläche wünschenswert.
Das Beispiel veranschaulicht zudem, wie Daten beim Empfang asynchron geparst werden, wobei der Zustand in Member-Variablen beibehalten wird, sodass ein inkrementeller Parser Datenblöcke verarbeiten kann, sobald diese über das Netzwerk eintreffen. Bestandteile des geparsten Inhalts können in einem Datenblock beginnen, aber erst in einem späteren Datenblock vervollständigt werden, was erfordert, dass der Parser den Status zwischen den Aufrufen beibehält.

Das Hauptprogramm ist recht minimalistisch. Es instanziiert lediglich ein „ QApplication “-Objekt und das „ RSSListing “-Widget, zeigt Letzteres an und übergibt die Kontrolle an Ersteres. Zur Veranschaulichung wird dem Widget die URL des Qt-Blogs als Standardwert für die zu überprüfende Ressource übergeben.
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();
}Die Klasse `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;
};Das Widget selbst bietet eine einfache Benutzeroberfläche zur Angabe der abzurufenden URL und – sobald verfügbare Aktualisierungen angezeigt werden – zur Steuerung des Herunterladens aktualisierter Elemente. Ein „ QLineEdit “ dient zur Eingabe der URL, und ein „ QTreeWidget “ zur Anzeige der Ergebnisse nach dem Abruf.
Das Widget lädt den RSS-Feed (eine Form von XML) asynchron herunter und analysiert ihn, wobei die Daten bei ihrer Ankunft an einen XML-Reader weitergeleitet werden. Dies ermöglicht das Einlesen sehr umfangreicher Datenquellen. Da die Daten über den XML-Reader aus dem Netzwerk gestreamt werden, muss der vollständige Text des XML-Dokuments nicht im Speicher gehalten werden. In einem anderen Kontext kann ein ähnlicher Ansatz es dem Benutzer ermöglichen, ein solches inkrementelles Laden zu unterbrechen.
Aufbau
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);
}Der Konstruktor richtet die verschiedenen Komponenten des Widgets ein und verbindet deren Signale mit den Slots, die zur Verarbeitung dieser Signale verwendet werden sollen.
Die Benutzeroberfläche besteht aus einem Eingabefeld, einer Schaltfläche und einem Listenansichts-Widget. Das Eingabefeld dient zur Eingabe der abzurufenden URL; die Schaltfläche startet den Vorgang zum Abrufen von Aktualisierungen. Das Eingabefeld ist standardmäßig leer, aber der Aufrufer des Konstruktors kann dies überschreiben, wie es in unserer Klasse „ main() “ geschehen ist. In jedem Fall kann der Benutzer den Standardwert durch die URL eines anderen RSS-Feeds ersetzen.
Die Listenansicht zeigt die im RSS-Feed gemeldeten aktualisierten Einträge an. Ein Doppelklick auf einen dieser Einträge sendet dessen URL mithilfe von ` QDesktopServices::openUrl()` an den Browser des Benutzers oder einen anderen User-Agent.
Die Slots
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);
}Alle Slots werden einfach gehalten, indem alle aufwendigen Aufgaben an private Methoden delegiert werden.
Wenn der Benutzer die Eingabe einer URL abgeschlossen hat – entweder durch Klicken auf die Schaltfläche „Fetch“ oder durch Drücken der Eingabetaste im Eingabefeld –, deaktiviert der Slot „ fetch() “ die Schaltfläche „Fetch“ und verhindert weitere Bearbeitungen im Eingabefeld. Er löscht die Anzeige der verfügbaren Updates und delegiert die Auslösung einer HTTP-GET-Anfrage an „ get() “.
Wenn Daten empfangen werden, löst die Netzwerkantwort das Signal „ readyRead()“ aus, das von „ get() “ mit dem Slot „ consumeData() “ verbunden wird. Dieser prüft, ob die Antwort einen erfolgreichen Statuscode enthält, und ruft in diesem Fall „ parseXml() “ auf, um die Daten zu verarbeiten.
Wenn die Netzwerkantwort einen Fehler enthält, wird dieser an den Slot „ error() “ weitergeleitet, der den Fehler meldet, den XML-Stream-Reader löscht, anschließend die Verbindung zur Antwort trennt und diese löscht.
Nach Abschluss (ob erfolgreich oder nicht) einer Netzwerkantwort stellt der Slot „ finished() “ die Benutzeroberfläche wieder her, sodass sie bereit ist, eine neue URL zum Abrufen anzunehmen, indem das Eingabefeld und die Schaltfläche „Fetch“ wieder aktiviert werden.
Die get()-Methode
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.
}Die private Methode ` get() ` wird vom Slot ` fetch() ` verwendet, um eine HTTP-GET-Anfrage zu initiieren. Sie löscht zunächst den XML-Stream-Reader und trennt, falls gerade eine Antwort aktiv ist, die Verbindung und löscht diese. Ist die übergebene URL gültig, fordert sie den Netzwerkzugriffsmanager auf, diese per GET abzurufen. Sie verbindet ihre entsprechenden Slots mit den Signalen der resultierenden Antwort (sofern vorhanden) und richtet ihren XML-Stream-Reader so ein, dass er Daten aus der Antwort liest – ein Netzwerkantwortobjekt ist ebenfalls ein „ QIODevice “, aus dem Daten gelesen werden können.
Die Methode 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();
}Wenn Daten empfangen und somit dem XML-Stream-Reader zur Verfügung gestellt werden, liest „ parseXml() “ aus dem XML-Stream, sucht nach „ item “-Elementen und innerhalb dieser nach „ title “- und „ link “-Elementen. Als URL in der Spalte „Link“ der Baumansicht wird das Attribut „ rss:about “ eines „ item “-Elements verwendet; falls dieses fehlt, wird der Inhalt des Elements „ link “ herangezogen; und als Titel in der Spalte „Titel“ der Baumansicht wird der Inhalt des Elements „ title “ verwendet. Bei jedem schließenden „ item “-Element werden dessen Details in eine neue Zeile im Baum-Widget umgewandelt, wobei der extrahierte Titel und die URL in den Spalten „Titel“ und „Link“ erscheinen.
Die Variablen, die den Parsing-Status verfolgen – „ linkString “, „ titleString “ und „ currentTag “ – sind Member-Variablen der Klasse „ RSSListing “, auch wenn sie nur von dieser Methode aus aufgerufen werden, da diese Methode bei Eintreffen neuer Daten wiederholt aufgerufen werden kann und ein Datenblock möglicherweise ein Element einleitet, das erst mit dem Eintreffen eines späteren Datenblocks vervollständigt wird. Dadurch kann der Parser asynchron arbeiten, sobald Daten eintreffen, anstatt warten zu müssen, bis alle Daten vollständig vorliegen.
Siehe auch QNetworkReply und 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.