Qt Quick Demo - RSS-Nachrichten
Ein QML-RSS-Newsreader, der die benutzerdefinierten QML-Typen XmlListModel und XmlListModelRole verwendet, um XML-Daten herunterzuladen, ListModel und ListElement, um eine Kategorieliste zu erstellen, und ListView, um die Daten anzuzeigen.

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 zur Erstellung einer Fußzeile für die Listenansicht der Nachrichten.
- Verwendung des Typs Image, um eine Schaltfläche zum Schließen der Anwendung zu erstellen.
Ausführen des Beispiels
Zum Ausführen des Beispiels von Qt Creatorauszuführen, öffnen Sie den Modus Welcome und wählen Sie das Beispiel aus Examples. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
Benutzerdefinierte Typen verwenden
In der RSS-News-App verwenden wir die folgenden benutzerdefinierten Typen, die jeweils in einer eigenen .qml-Datei definiert sind:
BusyIndicator.qmlCategoryDelegate.qmlNewsDelegate.qmlRssFeeds.qmlScrollBar.qml
Erstellen des Hauptfensters
In 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.PortraitOrientation
Wir werden die benutzerdefinierten Eigenschaften später zum Laden von XML-Daten und zum Anpassen des Bildschirmlayouts in Abhängigkeit von seiner Ausrichtung verwenden.
Erstellen einer Kategorieliste
In Main.qml verwenden wir den benutzerdefinierten Typ RssFeeds, den wir in RssFeeds.qml angeben, um eine Liste von 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 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 der Ausnahme, dass sie eine Sammlung von Rollendefinitionen anstelle von Eigenschaften enthalten. Rollen legen fest, wie auf die Daten zugegriffen wird, und enthalten 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, und die Rolle image, um ein Bild für die Kategorie anzuzeigen.
In Main.qml verwenden wir einen ListView Typ, 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).
Mit der Eigenschaft anchors.top positionieren wir die Listenansicht in beiden Ausrichtungen am oberen Rand des Bildschirms.
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.isCurrentItem
Wir 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 anzugeben, dass selected true ist, wenn delegate das aktuelle Element ist.
Wir verwenden die Eigenschaft Image type source, um das Bild anzuzeigen, das im Delegaten zentriert ist und für das Listenelement durch die Rolle image im Listenmodell rssFeeds festgelegt wurde:
Image { anchors.centerIn: parent source: delegate.image }
Wir verwenden einen Text Typ, 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 am oberen Rand des Listenelements mit einem 20-Pixel-Rand zu positionieren. Wir verwenden die Eigenschaften font, um die Schriftgröße und die Textformatierung anzupassen.
Die Eigenschaften color und scale werden verwendet, um den Text aufzuhellen und etwas größer zu skalieren, wenn das Listenelement das aktuelle Element ist. Durch die Anwendung einer Behavior auf die Eigenschaft werden die Aktionen zum Auswählen und Aufheben der Auswahl von Listenelementen animiert.
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 wird auf delegate gesetzt, damit die Benutzer auf eine beliebige Stelle innerhalb des Listenelements tippen können.
Um die XML-Daten für die Kategorieliste bei einem clicked -Ereignis zu laden, setzen wir die currentIndex der ListView angehängten Eigenschaft und geben das clicked -Signal() in onClicked aus.
Herunterladen von XML-Daten
In Main.qml verwenden wir einen XmlListModel Typ als Datenquelle für ListView Elemente, um Nachrichten 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 Nachrichten für die ausgewählte Kategorie abzurufen.
Die Eigenschaft query gibt an, dass XmlListModel ein Modellelement für jedes <item> im XML-Dokument erzeugt.
Wir verwenden den Typ XmlListModelRole, um die Attribute der Modellelemente anzugeben. Jedes Modellelement hat die Attribute title, content, link und pubDate, die mit den Werten der entsprechenden <item> im XML-Dokument übereinstimmen:
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: "" } }
Wir verwenden das Modell feedModel in einem Typ ListView zur Anzeige der Daten:
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 Teil der Nachrichtenliste links von window und unten von categories im Hochformat und rechts von categories und unten von window im Querformat 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 wird das Bild der Nachrichten an das Begrenzungsrechteck der Listenansicht geklammert, um grafische Artefakte zu vermeiden, wenn Nachrichten ü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 Modell feedModel zu laden, und verwenden NewsDelegate als Delegat, um jedes Element in der Liste zu instanziieren.
In NewsDelegate.qml verwenden wir einen Column Typ, 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: 8
Innerhalb 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 } }
Mit der JavaScript-Funktion timeSinceEvent() erzeugen wir eine Textdarstellung, die angibt, 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 onLinkActivated signal handler, um die URL in einem externen Browser zu öffnen, wenn Benutzer den Link auswählen.
Rückmeldung an die Benutzer
In CategoryDelegate.qml verwenden wir den benutzerdefinierten Typ BusyIndicator, um die Aktivität beim Laden 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 reduzieren. Wir binden die Eigenschaft visible an die angehängte Eigenschaft isCurrentItem der Listenansicht delegate und die Eigenschaft loading des Hauptfensters, um das Indikatorbild anzuzeigen, wenn ein Element der Kategorieliste das aktuelle Element ist und die XML-Daten geladen werden.
Wir definieren den Typ BusyIndicator in BusyIndicator.qml. Wir verwenden den Typ Image, um ein Bild anzuzeigen, und wenden NumberAnimation auf seine Eigenschaft rotation 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 Anwendungen können Sie auch den Typ BusyIndicator aus dem Modul Qt Quick Controls verwenden.
Erstellen von Bildlaufleisten
In Main.qml verwenden wir unseren eigenen benutzerdefinierten ScrollBar Typ, um Bildlaufleisten in den Listenansichten der Kategorien und Nachrichten zu erstellen. In Ihren Anwendungen können Sie auch den Typ ScrollView aus dem Modul Qt Quick Controls verwenden.
Zunächst erstellen wir eine Bildlaufleiste in der Kategorie-Listenansicht. Wir binden die Eigenschaft orientation an die Eigenschaft isPortrait und 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 }
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.
Mit der Eigenschaft anchors.right verankern wir die Bildlaufleiste an der rechten Seite der Kategorieliste.
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 Listenansicht der Nachrichten. Wir möchten, dass eine vertikale Bildlaufleiste unabhängig von der Bildschirmausrichtung auf der rechten Seite der Ansicht angezeigt wird. Daher können wir die Eigenschaft width auf 8 setzen und die Eigenschaft anchors.right an die Eigenschaft window.right binden. Wir verwenden die Eigenschaft anchors.top, um die Bildlaufleiste im Hochformat am unteren Rand der Kategorieliste und im Querformat am oberen Rand der Nachrichtenliste zu verankern. Wir verwenden die Eigenschaft anchors.bottom, um die Bildlaufleiste in beiden Ausrichtungen am unteren Rand der Listenansicht zu verankern.
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:
Item { id: container property variant scrollArea property int orientation: Qt.Vertical opacity: 0
Wir verwenden einen BorderImage Typ, um den Daumen der Bildlaufleiste an der x- und y-Position anzuzeigen, die wir mit 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 Daumens in Abhängigkeit von der Bildschirmausrichtung zu berechnen.
Wir verwenden states, um die Bildlaufleiste sichtbar zu machen, wenn der Benutzer den Bildlaufbereich bewegt:
states: State { name: "visible" when: container.orientation == Qt.Vertical ? container.scrollArea.movingVertically : container.scrollArea.movingHorizontally PropertyChanges { container { opacity: 1.0 } } }
Wir verwenden transitions, um NumberAnimation auf die Eigenschaft opacity anzuwenden, wenn der Status von "visible" in den Standardstatus wechselt:
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 News-Listenansicht 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 einen Image Typ, um eine einfache Drucktaste 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() } } }
Mit anchors positionieren wir die Schließen-Schaltfläche in der oberen rechten Ecke der Nachrichtenlistenansicht mit einem Rand von 4 Pixeln. Da die Schließen-Schaltfläche die Kategorieliste im Hochformat überlappt, animieren wir die Eigenschaft opacity, um die Schaltfläche fast vollständig transparent zu machen, wenn der Benutzer die Kategorieliste durchblättert.
Wir verwenden den onClicked Signalhandler innerhalb eines MouseArea, um die quit() Funktion aufzurufen, wenn der Benutzer die Schließen-Schaltfläche auswählt.
Siehe auch QML-Anwendungen.
© 2025 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.