Qt Quick Demo – RSS-Nachrichten
Ein QML-RSS-Newsreader, der die benutzerdefinierten QML-Typen XmlListModel und XmlListModelRole zum Herunterladen von XML-Daten, ListModel und ListElement zum Erstellen einer Kategorieliste sowie ListView zur Anzeige der Daten verwendet.

RSS News demonstriert die folgenden Qt Quick Funktionen:
- Verwendung benutzerdefinierter QML-Typen.
- Verwendung von Listenmodellen und Listenelementen zur Darstellung von Daten.
- Verwendung von XML-Listenmodellen zum Herunterladen von XML-Daten.
- Verwendung von Listenansichten zur Anzeige von Daten.
- Verwendung des Typs „ Component “ zum Erstellen einer Fußzeile für die Listenansicht der Nachrichten.
- Verwendung des Typs „ Image “ zum Erstellen einer Schaltfläche zum Schließen der App.
Ausführen des Beispiels
Sie können das Beispiel wie folgt ausführen:
- Qt Creator
Öffnen Sie den Modus „ Welcome “ und wählen Sie das Beispiel unter „ Examples “ aus. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
- Qt Extension for Visual Studio Code
Führen Sie den Befehl „ Qt: Open Qt examples “ über „ Command Palette “ aus und wählen Sie das Beispiel aus der Liste aus. Weitere Informationen finden Sie unter Qt Extension for Visual Studio Code: Tutorial: Erstellen und Ausführen.
Verwendung benutzerdefinierter Typen
In der RSS-News-App verwenden wir die folgenden benutzerdefinierten Typen, die jeweils in einer separaten .qml-Datei definiert sind:
BusyIndicator.qmlCategoryDelegate.qmlNewsDelegate.qmlRssFeeds.qmlScrollBar.qml
Erstellen des Hauptfensters
In der Datei „ Main.qml “ verwenden wir einen Typ „ Rectangle “ mit benutzerdefinierten Eigenschaften, um das Hauptfenster der App zu erstellen:
Rectangle {
id: window
width: 800
height: 480
property string currentFeed: rssFeeds.get(0).feed
property bool loading: feedModel.status === XmlListModel.Loading
property bool isPortrait: Screen.primaryOrientation === Qt.PortraitOrientationDie benutzerdefinierten Eigenschaften werden später zum Laden von XML-Daten und zur Anpassung des Bildschirmlayouts je nach Ausrichtung verwendet.
Erstellen einer Kategorieliste
In der Datei „ Main.qml “ verwenden wir den benutzerdefinierten Typ „ RssFeeds “, den wir in der Datei „ RssFeeds.qml “ festlegen, um eine Liste der Feed-Kategorien zu erstellen:
RssFeeds { id: rssFeeds }In „ RssFeeds.qml “ verwenden wir einen „ ListModel “-Typ mit einem „ ListElement “-Typ, um eine Kategorieliste zu erstellen, in der die Listenelemente Feed-Kategorien darstellen:
ListModel {
ListElement { name: "Top Stories"; feed: "news.yahoo.com/rss/topstories"; image: "images/TopStories.jpg" }
ListElement { name: "World"; feed: "news.yahoo.com/rss/world"; image: "images/World.jpg" }
ListElement { name: "Europe"; feed: "news.yahoo.com/rss/europe"; image: "images/Europe.jpg" }
ListElement { name: "Asia"; feed: "news.yahoo.com/rss/asia"; image: "images/Asia.jpg" }
ListElement { name: "U.S. National"; feed: "news.yahoo.com/rss/us"; image: "images/USNational.jpg" }
ListElement { name: "Politics"; feed: "news.yahoo.com/rss/politics"; image: "images/Politics.jpg" }
ListElement { name: "Business"; feed: "news.yahoo.com/rss/business"; image: "images/Business.jpg" }
ListElement { name: "Technology"; feed: "news.yahoo.com/rss/tech"; image: "images/Technology.jpg" }
ListElement { name: "Entertainment"; feed: "news.yahoo.com/rss/entertainment"; image: "images/Entertainment.jpg" }
ListElement { name: "Health"; feed: "news.yahoo.com/rss/health"; image: "images/Health.jpg" }
ListElement { name: "Science"; feed: "news.yahoo.com/rss/science"; image: "images/Science.jpg" }
ListElement { name: "Sports"; feed: "news.yahoo.com/rss/sports"; image: "images/Sports.jpg" }
}Listenelemente werden wie andere QML-Typen definiert, mit dem Unterschied, dass sie anstelle von Eigenschaften eine Sammlung von Rollendefinitionen enthalten. Rollen definieren sowohl den Zugriff auf die Daten als auch die Daten selbst.
Für jedes Listenelement verwenden wir die Rolle „ name “, um den Kategorienamen anzugeben, die Rolle „ feed “, um die URL anzugeben, von der die Daten geladen werden sollen, und die Rolle „ image “, um ein Bild für die Kategorie anzuzeigen.
In „ Main.qml “ verwenden wir den Typ „ ListView “, um die Kategorieliste anzuzeigen:
ListView {
id: categories
property int itemWidth: 190
width: window.isPortrait ? parent.width : itemWidth
height: window.isPortrait ? itemWidth : parent.height
orientation: window.isPortrait ? ListView.Horizontal : ListView.Vertical
anchors.top: parent.top
model: rssFeeds
delegate: CategoryDelegate {
itemSize: categories.itemWidth
isLoading: window.loading
onClicked: function () {
if (window.currentFeed == feed)
feedModel.reload()
else
window.currentFeed = feed
}
}Um die Kategorieliste im Hochformat horizontal am oberen Rand des Fensters und im Querformat vertikal auf der linken Seite anzuordnen, verwenden wir die Eigenschaft „ orientation “. Je nach Ausrichtung binden wir entweder die Breite oder die Höhe der Liste an einen festen Wert (itemWidth).
Wir verwenden die Eigenschaft „ anchors.top “, um die Listenansicht in beiden Ausrichtungen am oberen Bildschirmrand zu positionieren.
Wir verwenden die Eigenschaft „ model “, um XML-Daten aus dem Modell „ rssFeeds “ zu laden, und „ CategoryDelegate “ als Delegat, um jedes Element in der Liste zu instanziieren.
Erstellen von Listenelementen
In ` CategoryDelegate.qml` verwenden wir den Typ ` Rectangle ` mit benutzerdefinierten Eigenschaften, um Listenelemente zu erstellen:
Rectangle {
id: delegate
required property real itemSize
required property string name
required property string feed
required property string image
required property int index
required property bool isLoading
property bool selected: ListView.isCurrentItemWir verwenden „ required “, um die Eigenschaften zu deklarieren, die wir vom Modell erwarten.
Wir setzen die Eigenschaft „ selected “ auf die angehängte Eigenschaft „ ListView.isCurrentItem “, um festzulegen, dass „ selected “ den Wert „ true “ annimmt, wenn „ delegate “ das aktuelle Element ist.
Wir verwenden die Eigenschaft „ source “ vom Typ „ Image “, um das Bild zentriert im Delegaten anzuzeigen, das für das Listenelement durch die Rolle „ image “ im Listenmodell „ rssFeeds “ festgelegt wurde:
Image {
anchors.centerIn: parent
source: delegate.image
}Wir verwenden einen Typ vom Typ „ Text “, um den Listenelementen Titel hinzuzufügen:
Text {
id: titleText
anchors {
left: parent.left; leftMargin: 20
right: parent.right; rightMargin: 20
top: parent.top; topMargin: 20
}
font { pixelSize: 18; bold: true }
text: delegate.name
color: delegate.selected ? "#ffffff" : "#ebebdd"
scale: delegate.selected ? 1.15 : 1.0
Behavior on color { ColorAnimation { duration: 150 } }
Behavior on scale { PropertyAnimation { duration: 300 } }Wir verwenden die Eigenschaft „ anchors “, um den Titel oben im Listenelement mit einem Rand von 20 Pixeln zu positionieren. Mit den Eigenschaften „ font “ passen wir die Schriftgröße und die Textformatierung an.
Wir verwenden die Eigenschaften „ color “ und „ scale “, um den Text heller zu gestalten und ihn etwas zu vergrößern, wenn das Listenelement das aktuelle Element ist. Durch Anwenden eines „ Behavior “ auf die Eigenschaft animieren wir die Aktionen zum Auswählen und Abwählen von Listenelementen.
Wir verwenden einen „ MouseArea “-Typ, um XML-Daten herunterzuladen, wenn Benutzer auf ein Element der Kategorieliste tippen:
MouseArea {
anchors.fill: delegate
onClicked: {
delegate.ListView.view.currentIndex = delegate.index
delegate.clicked()
}
}Die Eigenschaft „ anchors.fill “ ist auf „ delegate “ gesetzt, damit Benutzer an einer beliebigen Stelle innerhalb des Listenelements tippen können.
Um die XML-Daten für die Kategorieliste bei einem „ clicked “-Ereignis zu laden, setzen wir die Eigenschaft „ currentIndex “ der angehängten Eigenschaft „ ListView “ und lösen das Signal „ clicked “ in „ onClicked “ aus.
Herunterladen von XML-Daten
In „ Main.qml “ verwenden wir einen Typ vom Typ „ XmlListModel “ als Datenquelle für „ ListView “-Elemente, um Nachrichtenartikel in der ausgewählten Kategorie anzuzeigen:
XmlListModel {
id: feedModel
source: "https://" + window.currentFeed
query: "/rss/channel/item"Wir verwenden die Eigenschaft „ source “ und die benutzerdefinierte Eigenschaft „ window.currentFeed “, um Nachrichtenartikel für die ausgewählte Kategorie abzurufen.
Die Eigenschaft „ query “ legt fest, dass der Typ „ XmlListModel “ für jedes „ <item> “-Element im XML-Dokument ein Modellelement generiert.
Wir verwenden den Typ „ XmlListModelRole “, um die Attribute des Modellelements festzulegen. Jedes Modellelement verfügt über die Attribute „ title “, „ content “, „ link “ und „ pubDate “, die den Werten der entsprechenden „ <item> “ im XML-Dokument entsprechen:
XmlListModelRole { name: "title"; elementName: "title"; attributeName: ""}
XmlListModelRole { name: "content"; elementName: "content"; attributeName: "url" }
XmlListModelRole { name: "link"; elementName: "link"; attributeName: "" }
XmlListModelRole { name: "pubDate"; elementName: "pubDate"; attributeName: "" }
}Zur Darstellung der Daten verwenden wir das Modell „ feedModel “ im Typ „ ListView “:
ListView {
id: list
anchors.left: window.isPortrait ? window.left : categories.right
anchors.right: closeButton.left
anchors.top: window.isPortrait ? categories.bottom : window.top
anchors.bottom: window.bottom
anchors.leftMargin: 30
anchors.rightMargin: 4
clip: window.isPortrait
model: feedModel
footer: footerText
delegate: NewsDelegate {}
}Um die Nachrichten unterhalb der Kategorieliste im Hochformat und rechts davon im Querformat aufzulisten, verwenden wir die benutzerdefinierte Eigenschaft „ isPortrait “, um den oberen Rand der Nachrichtenliste im Hochformat links von „ window “ und am unteren Rand von „ categories “ sowie im Querformat rechts von „ categories “ und am unteren Rand von „ window “ zu verankern.
Wir verwenden die Eigenschaft „ anchors.bottom “, um den unteren Rand der Listenansicht in beiden Ausrichtungen am unteren Rand des Fensters zu verankern.
Im Hochformat beschneiden wir die Darstellung der Nachrichtenartikel auf das Begrenzungsrechteck der Listenansicht, um grafische Artefakte zu vermeiden, wenn Nachrichtenartikel über andere Elemente gescrollt werden. Im Querformat ist dies nicht erforderlich, da sich die Liste vertikal über den gesamten Bildschirm erstreckt.
Wir verwenden die Eigenschaft „ model “, um XML-Daten aus dem „ feedModel “-Modell zu laden, und nutzen „ NewsDelegate “ als Delegat, um jedes Element in der Liste zu instanziieren.
In ` NewsDelegate.qml` verwenden wir den Typ „ Column “, um die XML-Daten anzuordnen:
Column {
id: delegate
required property string title
required property string content
required property string link
required property string pubDate
width: delegate.ListView.view.width
spacing: 8Innerhalb der Spalte verwenden wir eine Zeile und eine weitere Spalte, um Bilder und Titeltext zu positionieren:
Row {
width: parent.width
spacing: 8
Column {
Item {
width: 4
height: titleText.font.pixelSize / 4
}
Image {
id: titleImage
source: delegate.content
width: Math.min(delegate.width / 2, sourceSize.width)
fillMode: Image.PreserveAspectFit
}
}
Text {
id: titleText
text: delegate.title.replace(/'/g, "'")
width: delegate.width - titleImage.width
wrapMode: Text.WordWrap
font.pixelSize: 26
font.bold: true
}
}Wir generieren mithilfe der JavaScript-Funktion „ timeSinceEvent() “ eine textuelle Darstellung, wie lange es her ist, dass der Eintrag veröffentlicht wurde:
Text {
width: delegate.width
font.pixelSize: 12
textFormat: Text.RichText
font.italic: true
text: delegate.timeSinceEvent(delegate.pubDate) + " (<a href=\"" + delegate.link + "\">Link</a>)"
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
}Wir verwenden den Signal-Handler „ onLinkActivated “, um die URL in einem externen Browser zu öffnen, wenn Nutzer den Link auswählen.
Feedback an Benutzer geben
In „ CategoryDelegate.qml “ verwenden wir den benutzerdefinierten Typ „ BusyIndicator “, um die Aktivität während des Ladens der XML-Daten anzuzeigen:
BusyIndicator {
scale: 0.8
visible: delegate.ListView.isCurrentItem && delegate.isLoading
anchors.centerIn: parent
}Wir verwenden die Eigenschaft „ scale “, um die Größe des Indikators auf „ 0.8 “ zu verringern. Wir binden die Eigenschaft „ visible “ an die angehängte Eigenschaft „ isCurrentItem “ der Listenansicht „ delegate “ sowie an die Eigenschaft „ loading “ des Hauptfensters, um das Indikatorbild anzuzeigen, wenn ein Element der Kategorieliste das aktuelle Element ist und XML-Daten geladen werden.
Wir definieren den Typ „ BusyIndicator “ in „ BusyIndicator.qml “. Wir verwenden einen „ Image “-Typ, um ein Bild anzuzeigen, und wenden ein „ NumberAnimation “ auf dessen „ rotation “-Eigenschaft an, um das Bild in einer Endlosschleife zu drehen:
Image {
id: container
source: "images/busy.png";
NumberAnimation on rotation {
running: container.visible
from: 0; to: 360;
loops: Animation.Infinite;
duration: 1200
}
}In Ihren Apps können Sie auch den Typ „ BusyIndicator “ aus dem Qt Quick Controls Moduls verwenden.
Erstellen von Bildlaufleisten
In „ Main.qml “ verwenden wir unseren eigenen benutzerdefinierten Typ „ ScrollBar “, um Bildlaufleisten in den Listenansichten der Kategorien und Nachrichten zu erstellen. In Ihren Apps können Sie ebenfalls den Typ „ ScrollView “ aus dem Qt Quick Controls Moduls verwenden.
Zunächst erstellen wir eine Bildlaufleiste in der Kategorie-Listenansicht. Wir binden die Eigenschaft „ orientation “ an die Eigenschaft „ isPortrait “ sowie an den Wert „ Horizontal “ des Enum-Typs „ Qt::Orientation “, um eine horizontale Bildlaufleiste im Hochformat anzuzeigen, und an den Wert „ Vertical “, um eine vertikale Bildlaufleiste im Querformat anzuzeigen:
ScrollBar {
id: listScrollBar
orientation: window.isPortrait ? Qt.Horizontal : Qt.Vertical
height: window.isPortrait ? 8 : categories.height;
width: window.isPortrait ? categories.width : 8
scrollArea: categories;
anchors.right: categories.right
}Genau wie bei der Listenansicht „ categories “ passen wir die Breite und Höhe der Bildlaufleiste anhand der Eigenschaft „ isPortrait “ an.
Wir verwenden die Eigenschaft „ scrollArea “, um die Bildlaufleiste in der Listenansicht „ categories “ anzuzeigen.
Wir verwenden die Eigenschaft „ anchors.right “, um die Bildlaufleiste am rechten Rand der Kategorieliste zu verankern.
ScrollBar {
scrollArea: list
width: 8
anchors.right: window.right
anchors.top: window.isPortrait ? categories.bottom : window.top
anchors.bottom: window.bottom
}Zweitens erstellen wir eine weitere Bildlaufleiste in der Nachrichtenlistenansicht. Wir möchten, dass unabhängig von der Bildschirmausrichtung eine vertikale Bildlaufleiste auf der rechten Seite der Ansicht erscheint. Daher setzen wir die Eigenschaft „ width “ auf „ 8 “ und binden die Eigenschaft „ anchors.right “ an die Eigenschaft „ window.right “. Wir verwenden die Eigenschaft „ anchors.top “, um den oberen Rand der Bildlaufleiste im Hochformat am unteren Rand der Kategorieliste und im Querformat am oberen Rand der Nachrichtenliste zu verankern. Mit der Eigenschaft „ anchors.bottom “ verankern wir den unteren Rand der Bildlaufleiste in beiden Ausrichtungen am unteren Rand der Listenansicht.
Wir definieren den Typ „ ScrollBar “ in „ ScrollBar.qml “. Wir verwenden einen Typ „ Item “ mit benutzerdefinierten Eigenschaften, um einen Container für die Bildlaufleiste zu erstellen:
Wir verwenden den Typ „ BorderImage “, um den Schieberegler an der x- und y-Position anzuzeigen, die wir mithilfe der Funktion „ position() “ berechnen:
BorderImage {
source: "images/scrollbar.png"
border { left: 1; right: 1; top: 1; bottom: 1 }
x: container.orientation == Qt.Vertical ? 2 : container.position()
y: container.orientation == Qt.Vertical ? container.position() : 2
width: container.orientation == Qt.Vertical ? container.width - 4 : container.size()
height: container.orientation == Qt.Vertical ? container.size() : container.height - 4
}Wir verwenden die Funktion „ size “, um die Breite und Höhe des Schiebereglers in Abhängigkeit von der Bildschirmausrichtung zu berechnen.
Wir verwenden ` states `, um die Bildlaufleiste sichtbar zu machen, wenn der Benutzer den Bildlaufbereich verschiebt:
states: State {
name: "visible"
when: container.orientation == Qt.Vertical ?
container.scrollArea.movingVertically :
container.scrollArea.movingHorizontally
PropertyChanges { container { opacity: 1.0 } }
}Wir verwenden „ transitions “, um ein „ NumberAnimation “ auf die Eigenschaft „ opacity “ anzuwenden, wenn sich der Zustand von „ "visible" “ in den Standardzustand ändert:
transitions: Transition {
from: "visible"; to: ""
NumberAnimation { properties: "opacity"; duration: 600 }
}
}Fußzeilen erstellen
In „ Main.qml “ verwenden wir einen „ Component “-Typ mit einem „ Rectangle “-Typ, um eine Fußzeile für die Nachrichtenlistenansicht zu erstellen:
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Window
import QtQml.XmlListModel
Rectangle {
id: window
width: 800
height: 480
property string currentFeed: rssFeeds.get(0).feed
property bool loading: feedModel.status === XmlListModel.Loading
property bool isPortrait: Screen.primaryOrientation === Qt.PortraitOrientation
onLoadingChanged: {
if (feedModel.status == XmlListModel.Ready)
list.positionViewAtBeginning()
}
RssFeeds { id: rssFeeds }
XmlListModel {
id: feedModel
source: "https://" + window.currentFeed
query: "/rss/channel/item"
XmlListModelRole { name: "title"; elementName: "title"; attributeName: ""}Wir binden die „ width “ der Fußzeile an die Breite der Komponente und die „ height “ an die Höhe der Schaltfläche „Schließen“, um sie auszurichten, wenn keine Nachrichten angezeigt werden.
Erstellen von Schaltflächen
In ` Main.qml` verwenden wir den Typ ` Image `, um eine einfache Schaltfläche zu erstellen, auf die Benutzer tippen können, um die App zu schließen:
XmlListModelRole { name: "content"; elementName: "content"; attributeName: "url" }
XmlListModelRole { name: "link"; elementName: "link"; attributeName: "" }
XmlListModelRole { name: "pubDate"; elementName: "pubDate"; attributeName: "" }
}
ListView {
id: categories
property int itemWidth: 190
width: window.isPortrait ? parent.width : itemWidth
height: window.isPortrait ? itemWidth : parent.height
orientation: window.isPortrait ? ListView.Horizontal : ListView.Vertical
anchors.top: parent.top
model: rssFeeds
delegate: CategoryDelegate {
itemSize: categories.itemWidth
isLoading: window.loading
onClicked: function () {
if (window.currentFeed == feed)
feedModel.reload()
else
window.currentFeed = feed
}
}
spacing: 3
}
ScrollBar {
id: listScrollBar
orientation: window.isPortrait ? Qt.Horizontal : Qt.Vertical
height: window.isPortrait ? 8 : categories.height;
width: window.isPortrait ? categories.width : 8
scrollArea: categories;
anchors.right: categories.right
}
ListView {
id: list
anchors.left: window.isPortrait ? window.left : categories.right
anchors.right: closeButton.left
anchors.top: window.isPortrait ? categories.bottom : window.top
anchors.bottom: window.bottom
anchors.leftMargin: 30
anchors.rightMargin: 4
clip: window.isPortrait
model: feedModel
footer: footerText
delegate: NewsDelegate {}
}
ScrollBar {
scrollArea: list
width: 8
anchors.right: window.right
anchors.top: window.isPortrait ? categories.bottom : window.top
anchors.bottom: window.bottom
}
Component {
id: footerText
Rectangle {
width: parent.width
height: closeButton.height
color: "lightgray"
Text {
text: "RSS Feed from Yahoo News"
anchors.centerIn: parent
font.pixelSize: 14
}
}
}
Image {
id: closeButton
source: "content/images/btn_close.png"
scale: 0.8
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: 4
opacity: (window.isPortrait && categories.moving) ? 0.2 : 1.0
Behavior on opacity {
NumberAnimation { duration: 300; easing.type: Easing.OutSine }
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit()
}
}
}Wir verwenden „ anchors “, um die Schaltfläche „Schließen“ in der oberen rechten Ecke der Nachrichtenlistenansicht mit Rändern von 4 Pixeln zu positionieren. Da die Schaltfläche „Schließen“ im Hochformat die Kategorieliste überlappt, animieren wir die Eigenschaft „ opacity “, um die Schaltfläche fast vollständig transparent zu machen, wenn Benutzer durch die Kategorieliste scrollen.
Wir verwenden den Signal-Handler „ onClicked “ innerhalb eines „ MouseArea “, um die Funktion „ quit() “ aufzurufen, wenn der Nutzer die Schaltfläche „Schließen“ auswählt.
Siehe auch QML-Anwendungen.
© 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.