This demo uses Qt Quick components to create a simple Flickr client. It shows a selection of the images that have most recently been added to Flickr. The chief purpose of the demo is to show how to use Qt Quick components to create a user interface that responds to orientation changes.
It also demonstrates the use of the following Qt Quick components: Window, Page, PageStack, Button, ProgressBar, TextField, Toolbar, ToolBarLayout, ToolButton, Slider, ScrollDecorator and StatusBar.
Source: Browse here
The Flickr demo is almost completely written in QML. Qt Quick components are used to create the UI and a simple C++ wrapper collects the QML files and image files of the application into a single binary using the Qt resource system. The main.cpp sets the network proxy for the QApplication that runs the demo. Note that if FLICKR_FULLSCREEN is defined, then the demo will be compiled to run in fullscreen mode. This is required when compiling the application for mobile devices.
The code in main.cpp sets the main QML file of the application to be flickr.qml which starts loading the first page and shows a splash screen for a short period while network requests to Flickr service are being made.
#include <QApplication> #include <QDeclarativeEngine> #include <QDeclarativeView> #include <QNetworkProxy> #include <QUrl> int main(int argc, char **argv) { QApplication app(argc, argv); QUrl proxyUrl(qgetenv("http_proxy")); if (proxyUrl.isValid() && !proxyUrl.host().isEmpty()) { int proxyPort = (proxyUrl.port() > 0) ? proxyUrl.port() : 8080; QNetworkProxy proxy(QNetworkProxy::HttpProxy, proxyUrl.host(), proxyPort); QNetworkProxy::setApplicationProxy(proxy); } else { QNetworkProxyQuery query(QUrl(QLatin1String("http://www.flickr.com"))); QNetworkProxy proxy = QNetworkProxyFactory::systemProxyForQuery(query).value(0); if (proxy.type() != QNetworkProxy::NoProxy) QNetworkProxy::setApplicationProxy(proxy); } QDeclarativeView view; view.setSource(QUrl("qrc:/qml/flickr.qml")); #if defined(FLICKR_FULLSCREEN) view.window()->showFullScreen(); #else view.window()->show(); #endif QObject::connect(view.engine(), SIGNAL(quit()), &view, SLOT(close())); return app.exec(); }
The Window component is the root component of the application. It provides the means to react to orientation changes, as well as sizing the application.
The PageStack component manages a stack of Page components, which in turn implement the different views of the Flickr application. There are three Page components in the application:
All three Page components share a common ancestor, the FlickrPage component, which implements background graphics.
The ToolBar component shows the buttons for the different Pages. A Page component can specify the a set of tools that automatically show up in the ToolBar when the page is on the top of the stack of pages in the PageStack.
When the application starts the Component.onCompleted() handler in Window pushes the ThumbnailPage to the PageStack.
The StatusBar and ToolBar are hidden based on largeImagePage.chromeOpacity.
Note the use of the PageStack.replace() function, pressing on the rightmost button of the LargeImagePage will not increase the stack depth in PageStack, it will instead replace the LargeImagePage with a DetailsPage object with the id detailsPage. The LargeImagePage object will not be destroyed even if it is not in the PageStack as it is defined within the Window element in flickr.qml. The PageStack.replace() function is used similarly in the DetailsPage to replace itself with the id largeImagePage.
Window { id: window PageStack { id: pageStack anchors.fill: parent toolBar: toolBar onDepthChanged: searchBar.close(); } StatusBar { id: statusBar anchors { top: parent.top; left: parent.left; right: parent.right } opacity: largeImagePage.chromeOpacity } SearchBar { id: searchBar anchors.top: statusBar.bottom width: statusBar.width onSearchTagChanged: photoFeedModel.tags = searchTag } ToolBar { id: toolBar anchors { bottom: parent.bottom; left: parent.left; right: parent.right } opacity: largeImagePage.chromeOpacity } ThumbnailPage { id: thumbnailPage anchors { fill: parent; topMargin: statusBar.height; bottomMargin: toolBar.height } inPortrait: window.inPortrait model: PhotoFeedModel { id: photoFeedModel } tools: ToolBarLayout { ToolButton { iconSource: "images/tb_back.svg" onClicked: Qt.quit(); } ToolButton { iconSource: "images/tb_reload.svg" onClicked: { photoFeedModel.reload(); searchBar.close(); } } ToolButton { iconSource: "images/tb_search.svg" onClicked: searchBar.toggle(); } } onPhotoClicked: { largeImagePage.setPhotoData(url, photoWidth, photoHeight); detailsPage.setPhotoData(author, date, description, tags, title, photoWidth, photoHeight); pageStack.push(largeImagePage); } } LargeImagePage { id: largeImagePage tools: ToolBarLayout { ToolButton { iconSource: "images/tb_back.svg" onClicked: pageStack.pop(); } ToolButton { iconSource: "images/tb_info.svg" checked: false onClicked: pageStack.replace(detailsPage); } } } DetailsPage { id: detailsPage anchors { fill: parent; topMargin: statusBar.height; bottomMargin: toolBar.height } tools: ToolBarLayout { ToolButton { iconSource: "images/tb_back.svg" onClicked: pageStack.pop(); } ToolButton { iconSource: "images/tb_info.svg" checked: true onClicked: pageStack.replace(largeImagePage); } } } Splash { id: splash image : "images/splash.png" timeout: 1000 fadeout: 700 Component.onCompleted: splash.activate(); onFinished: splash.destroy(); } Component.onCompleted: pageStack.push(thumbnailPage); }
When the Flickr application starts, it shows most recently added images from Flickr as thumbnails. The ThumbnailPage implements this view, it shows the thumbnails differently in portrait and landscape orientations.
import QtQuick 1.1 import com.nokia.symbian 1.1 import "UIConstants.js" as UI FlickrPage { id: thumbnailPage property XmlListModel model property bool inPortrait signal photoClicked(string url, int photoWidth, int photoHeight, string author, string date, string description, string tags, string title) Loader { sourceComponent: inPortrait ? listComponent : gridComponent anchors { fill: parent; margins: UI.LISTVIEW_MARGIN } } Component { id: gridComponent GridView { property int thumbnailsInRow: 4 function cellWidth() { return Math.floor(width / thumbnailsInRow); } cacheBuffer: 2 * height cellHeight: cellWidth cellWidth: cellWidth() delegate: GridDelegate { onPhotoClicked: { thumbnailPage.photoClicked(url, photoWidth, photoHeight, author, date, description, tags, title); } } model: thumbnailPage.model onWidthChanged: { thumbnailsInRow = width / (UI.THUMBNAIL_WRAPPER_SIDE + UI.THUMBNAIL_SPACING); } } } Component { id: listComponent ListView { cacheBuffer: 2 * height delegate: ListDelegate { onPhotoClicked: { thumbnailPage.photoClicked(url, photoWidth, photoHeight, author, date, description, tags, title); } } model: thumbnailPage.model } } }
The property inPortrait is used to control whether a list of thumbnails or a grid of thumbnails is loaded by a Loader element. The GridView component is loaded in !inPortrait mode and the ListView component in inPortrait mode. The inPortrait property is bound to window.inPortrait in flickr.qml.
The GridView and ListView use a common specialized XmlListModel (PhotoFeedModel) that fetches the thumbnail information from an online feed provided by Flickr. Sharing the model reduces code duplication and improves performance as the shared model fetches the thumbnail information only once for both views.
Image of the ThumbnailPage in portrait orientation:
Image of the ThumbnailPage showing a grid of thumbnails in landscape orientation:
Image of the ThumbnailPage with the SearchBar visible:
The Flickr demo will show the a larger version of an image when the user clicks or taps on the thumbnail. This action is handled in the delegates of ListView and GridView, both emitting the photoClicked() signal that is handled in flickr.qml so that the LargeImagePage gets pushed to the PageStack with the function PageStack.push().
The LargeImagePage shows a larger version of an image that is flickable and zoomable.
The LargeImagePage shows a ProgressBar while loading an image. Once the image is loaded, ProgressBar will be hidden and the actual image is shown.
ProgressBar { anchors.centerIn: parent minimumValue: 1 maximumValue: 100 value: image.progress * 100 visible: image.status != Image.Ready Text { text: Math.floor(parent.value) + qsTr(" %"); anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.top anchors.bottomMargin: UI.PROGRESSBAR_LABEL_BOTTOM_MARGIN font.bold: true color: UI.PROGRESSBAR_LABEL_COLOR } }
The Slider component is used to zoom the image, dragging the Slider handle scales the image creating a zoom effect.
Slider { id: slider maximumValue: 1 stepSize: (maximumValue - minimumValue) / 100 opacity: UI.SLIDER_OPACITY anchors { bottom: parent.bottom bottomMargin: UI.SLIDER_BOTTOM_MARGIN left: parent.left leftMargin: UI.SLIDER_SIDE_MARGIN right: parent.right rightMargin: UI.SLIDER_SIDE_MARGIN } } Binding { target: image; property: "scale"; value: slider.value; when: slider.visible }
If the zoom level is such that the image is larger than the screen size, scroll decorators are visible. ScrollDecorator indicates the part of the image that is shown while flicking. The flickableItem property of ScrollDecorator is bound to the id flickable, which identifies the Flickable element that wraps the image.
ScrollDecorator { flickableItem: flickable }
The following image depicts the LargeImagePage component in action, the scroll decorators are visible as the user has zoomed in on the image.
The Details page, implemented in the file DetailsPage.qml, shows detailed information of the image.
© 2008-2011 Nokia Corporation and/or its subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation in Finland and/or other countries worldwide.
All other trademarks are property of their respective owners. Privacy Policy
Licensees holding valid Qt Commercial licenses may use this document in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and Nokia.
Alternatively, this document may be used under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation.