Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

QckWeb (Qt Quick Project)

From Wiki
Jump to: navigation, search
Article Metadata
Compatibility
Platform(s):
Symbian
Article
Created: croozeus (25 Feb 2011)
Last edited: kiran10182 (22 Oct 2013)

Contents

Introduction

QckWeb is a Qt Quick project which focuses on improving the internet accessibility on mobile devices. We are concentrating on adding features that would make QckWeb - a one stop application for frequently used internet services.

QckWeb1.png QckWeb2.png QckWeb3.png


As of now, QckWeb consists of weather information and news service, which are briefly described below. We are looking forward to add more features which would include frequently used services like stock market indexes, sports information, etc.

QckWeb is an open source project. This article is a tutorial for developers and explains how to create fully functional standalone Qt Quick applications. Moreover, this article may also be considered as reference for developers willing to contribute to this open source project, to familiarize with the user-interface/code of the project.

Below is an video of the current version (1.0) The media player is loading...

Basic User Interface design

The basic interface design of the QckWeb is shown below.

QckWeb wireframe1.png

From the above wire frame, the user interface can be divided into following components or elements,

  • Title bar
  • Weather view
    • Text Edit
    • Info view
    • Current conditions view
    • Forecast view
  • News view
    • News Title
    • News List
  • Navigation bar
  • View Switching (View Container)

The higher level main.qml would have a structure similar to the following for the above interface design.


Here is how the main.qml file would appear, at a higher level

// QckWeb
// main.qml
 
Rectangle{
width: 360
height: 640
 
TitleBar{
}
 
MainView{
}
 
Navigation Bar{
}
 
}

With the above approach (in main.qml), our MainView could either be the Weather View or the News view. Both these views display live content from Google APIs - Google weather API and Google News API respectively. Let's now see how each of the main components listed above are implemented.

Title bar

The title bar is an Image element. It also contains the close button which is used to quit the application (i.e. it contains a mouse area which triggers the application to quit.

import QtQuick 1.0
 
Image{
width: myApp.width
height: 86
source: "images/title.png"
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
 
MouseArea{
height: parent.height
width: parent.width
onClicked:{
if (mouseX>295)
{
Qt.quit()
}
}
}
}

Weather View

To begin with, let's check what the Google weather API has to offer. Paste the following URL in a browser and check the source to see the XML response from the API.

  http://www.google.com.au/ig/api?weather=tampere

We get the following response,

<?xml version="1.0" ?> 
<xml_api_reply version="1">
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0">
<forecast_information>
<city data="tampere" />
<postal_code data="tampere" />
<latitude_e6 data="" />
<longitude_e6 data="" />
<forecast_date data="2011-02-22" />
<current_date_time data="2011-02-22 18:20:00 +0000" />
<unit_system data="US" />
</forecast_information>
<current_conditions>
<condition data="Light snow" />
<temp_f data="5" />
<temp_c data="-15" />
<humidity data="Humidity: 85%" />
<icon data="/ig/images/weather/flurries.gif" />
<wind_condition data="Wind: NE at 6 mph" />
</current_conditions>
<forecast_conditions>
<day_of_week data="Tue" />
<low data="-11" />
<high data="12" />
<icon data="/ig/images/weather/mostly_sunny.gif" />
<condition data="Mostly Sunny" />
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Wed" />
<low data="-11" />
<high data="8" />
<icon data="/ig/images/weather/mostly_sunny.gif" />
<condition data="Partly Sunny" />
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Thu" />
<low data="-14" />
<high data="13" />
<icon data="/ig/images/weather/cloudy.gif" />
<condition data="Cloudy" />
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Fri" />
<low data="12" />
<high data="22" />
<icon data="/ig/images/weather/chance_of_snow.gif" />
<condition data="Chance of Snow" />
</forecast_conditions>
</weather>
</xml_api_reply>

After analysing the XML response, we can summarize the following data which we can get from the API. We have divided the data into 3 sections as follows,

  • Information
    • City Name (With state, if any)
    • Forecast date
  • Current Conditions
    • Current temparature in Celcius
    • Humidity
    • Icon
  • Forcast conditions for next 4 days, including today
    • Day
    • Low temperature in Farenhite
    • High temperature in Farenhite
    • Sky Conditions

In QML, there exists an element called XmlListModel which is used to create a model from XML data. This model can be used as data source for various views (ListView, Gridview, etc) and elements such as a Repeater. If you are not familiar with the model-view in QML, please refer to the ListView example here.

We would require a line-edit where the user can enter a city name for which the weather information is required. The line-edit can simplistic with a TextInput element. For the aestestics and UX to be rich, we use a BorderImage element as the parent of TexInput; we also implement a MouseArea within it to open the virtual keyboard and show instruction text "Enter a vaild city name" as default text.

We would design 3 XMLListModels for the above 3 sections of data, as follows. Its worth noting that source url contains the text from the line-edit to give us results for the required location. Since the qml properties on the left, bind themselves to the javascript expressions on the right, the XMLListModels would refresh every time the text in the line edit changes. This behaviour helps us to eliminate any 'OK' or 'Sumbit' button which would traditionally accompany the line-edit.

// ===Information Model: City, Date, City===//
XmlListModel {
id: infoModel
source: "http://www.google.com.au/ig/api?weather=" + textbar.text
query: "/xml_api_reply/weather/forecast_information"
 
//forecast information
XmlRole { name: "city"; query: "city/@data/string()" }
XmlRole { name: "forecast_date"; query: "forecast_date/@data/string()" }
XmlRole { name: "current_date_time"; query: "current_date_time/@data/string()" }
 
}
 
// ===Current Conditions Models===//
XmlListModel {
id: currentconditionsModel
source: "http://www.google.com.au/ig/api?weather=" + textbar.text
query: "/xml_api_reply/weather/current_conditions"
 
//current condition
XmlRole { name: "condition"; query: "condition/@data/string()" }
XmlRole { name: "temp_c"; query: "temp_c/@data/string()" }
XmlRole { name: "humidity"; query: "humidity/@data/string()" }
XmlRole { name: "icon"; query: "icon/@data/string()" }
XmlRole { name: "wind_condition"; query: "wind_condition/@data/string()" }
}
 
// ===ForeCast Model===//
XmlListModel {
id: forecastModel
 
source: "http://www.google.com.au/ig/api?weather=" + textbar.text
query: "/xml_api_reply/weather/forecast_conditions"
 
XmlRole { name: "day_of_week"; query: "day_of_week/@data/string()" }
XmlRole { name: "low_f"; query: "low/@data/string()" }
XmlRole { name: "high_f"; query: "high/@data/string()" }
XmlRole { name: "icon"; query: "icon/@data/string()" }
XmlRole { name: "condition"; query: "condition/@data/string()" }
 
}

Once the models are in place, we just need to bring in the views and their delegates to display the data. We would use the Repeater for the information section while for the current conditions and forecast sections, we would go with a ListView. (For no particular reason other than demonstrating the feasiblility. Either of them can be used by you).

The code for information view element is illustrated below. It contains two Text elements to display city name and date.

 
// === Information ===//
Repeater{
id: infoView
width: parent.width
model: infoModel
delegate: Rectangle {
id: infoViewLabel
width: parent.width
anchors.top: parent.top
anchors.topMargin: 10
color: "transparent"
 
// === City Label ===//
Text {
id: cityDateLabelText
anchors.left: parent.left
anchors.leftMargin: 10
text: city
font.pixelSize: 16
font.bold: true
color: "#809fbb"
}
 
// === Date Label ===//
Text {
id: dateLabel
anchors.left: parent.left
anchors.leftMargin: 10
anchors.top: cityDateLabelText.bottom
anchors.topMargin: 2
text: forecast_date
font.pixelSize: 16
font.bold: true
color: "#809fbb"
}
}
}

In the current conditions section, we get a partial icon path from the API, in addition to the text data - temperature and humidity. On careful observation we can see that the path is relative to "http://www.google.com.au/" and "http://www.google.com.au/" + icon path leads to an icon! For example the following url,

 http://www.google.com.au/ig/images/weather/sunny.gif

So for the icon, we can use the Image element with the source pointing to the valid urls of icons. The code for the current conditions view is shown below. You may want to note, how the items inside the delegate are anchored to arrange them.

 
// === Current Conditions ===//
ListView
{
id: currentconditionsView
width: parent.width
height: 90
// y: 300
model: currentconditionsModel
delegate:
Rectangle{
id: currentconditionsViewLabel
width: parent.width
color: "transparent"
Image {
id: currenticon
width: 40
height: 40
anchors.left: parent.left
anchors.leftMargin: 10
anchors.top: parent.top
anchors.topMargin:10
source: "http://www.google.com.au/" + icon
}
 
// === Current Temp Label ===//
Text {
id: tempLabelText
height: 40
anchors.left: currenticon.right
anchors.leftMargin: 10
anchors.top: parent.top
text: temp_c + "\u00B0C"
font.pixelSize: 40
color: "#809fbb"
}
 
// === Current Humidity Label ===//
Text {
id: humidityLabelText
anchors.top: currenticon.bottom
anchors.topMargin: 5
anchors.left: currenticon.left
text: humidity
font.pixelSize: 20
color: "#809fbb"
}
 
}
 
}

When the delegate of a view starts becoming big (in terms of code), its good to define the delegate separately as a Component. For example, for the forecast view, we have defined the delegate separately as follows.

Also, since the Google weather API gives us the low and high temparatures of the next 4 days in farenhite, we should manually convert it to celcius. Here is where we are going to write a Javascript function within our delegate to convert farenhite to celcius. The function can be used within the delegate as javascript expression

// === Forecast Delgate===//
Component{
id: forecastViewDelegate
Rectangle{
id: forecastViewDelegateRect
width: parent.width
height: 50
color: "transparent"
 
// === Icon Label ===//
Image {
id: iconLabel
anchors.leftMargin: 10
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
source: "http://www.google.com.au/" + icon
}
 
// === Day Label ===//
Text{
id: dayLabel
anchors.leftMargin: 10
anchors.left: iconLabel.right
anchors.top: parent.top
text: day_of_week
font.pixelSize: 14
font.bold: true
color: "#809fbb"
}
 
// === Low Temp Label ===//
Text{
id: lowcLabel
anchors.leftMargin: 10
anchors.left: dayLabel.right
anchors.top: parent.top
font.pixelSize: 14
text: "<b>Low</b>: " + f2d(low_f) + "\u00B0C"
color: "#809fbb"
}
 
// === High Temp Label ===//
Text{
id: highcLabel
anchors.leftMargin: 14
anchors.left: lowcLabel.right
anchors.top: parent.top
font.pixelSize: 14
textFormat: Text.StyledText
text: "<b>High</b>: " + f2d(high_f) +"\u00B0C"
color: "#809fbb"
}
 
// === Sky Condition Label ===//
Text{
id: conditionLabel
anchors.top: dayLabel.bottom
anchors.topMargin: 5
anchors.left: iconLabel.right
anchors.leftMargin: 10
font.pixelSize: 14
text: "<b>Sky</b>: " + condition
color: "#809fbb"
}
 
// === Javascript Function for Fahrenheit to Celcius ===//
function f2d(f)
{
var d = (parseInt(f)-32)*(5/9)
return parseInt(d);
}
}
}

Finally, we write the view for the forecast section, where we refer to the above delegate.

// === Forecast List View===//
ListView{
id: forecastView
width: parent.width
height: 200
anchors.top: currentconditionsView.bottom
model: forecastModel
delegate: forecastViewDelegate
}

News View

The news views the RSS feed for Google News for its XMLListModel. Since we wish to only display the headlines i.e. the title from the XML response, the XMLListModel is simplified as shown below,

// ===News Model===//
XmlListModel {
id: newsModel
 
source: "http://news.google.com/news?ned=us&topic=h&output=rss"
query: "/rss/channel/item"
 
XmlRole { name: "title"; query: "title/string()" }
}

The view that we use for the news is a ListView. We are using a graphic/png as the BorderImage parent for each delegate.

ListView{
width: parent.width
height: parent.height - newstitle.height
anchors.top: newstitle.bottom
id: newsList
model: newsModel
delegate:BorderImage{
width: parent.width
height: 40
source:"images/newsbox.png"
Text {
width: parent.width-10
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 10
text: "\u2022 " + title
wrapMode:Text.WordWrap
color: "#809fbb"
font.weight: Font.DemiBold
font.pixelSize: 14
 
}
}
}


View Switching and Navigation bar

From what was indicated earlier, we have 2 MainViews in the application viz. Weather view and News View. With the initial design approach (in main.qml), our MainView could either be the Weather View or the News view. So to accomplish view switching we create a Row element as the view container - which would contain both our main views and also help us to switch between them.

The re-defined design and the main.qml are posted below,

Weather view in use News view in use

// QckWeb
// main.qml
 
Rectangle{
width: 360
height: 640
 
TitleBar{
}
 
Row{
id: viewContainer
WeatherView{
}
NewsView{
}
}
 
Navigation Bar{
}
 
}

Since weather view would be our initial view, to accomplish the view switching we define a new state "newsView". When we switch to the newsView state, we change the x co-ordinate of the Row element, so that it would show us the NewsView.

states: [
State {
name: "newsView"
PropertyChanges {
target: viewContaier
x: -360
}
}
]

The Navigation Bar is used to switch between the weather view and the news view. Thus, we have implemented the mouse area to trigger the view switching the state to "newsView" or "" accordingly. Note, the initial state is refered by "".

Image{
id: navigationBar
width: parent.width
height: 102
source: "images/navigationbar1.png"
anchors.bottom: parent.bottom
MouseArea{
anchors.fill: parent
onClicked: {
if (mouseX<187) // width of weather button
{
// Weather button clicked
myApp.state=""
}
else{
myApp.state = "newsView"
}
}
}
}

We can also add an transition when the state changes. Since we are changing the "x" co-ordinate/property of Row element - we could have a NumberAnimation with an easing curve as follows,

transitions: [
Transition {
NumberAnimation { target: viewContaier; property: "x"; duration: 1000; easing.type: Easing.OutElastic}
}
]


Further additions and contributions

The project contains more elements than which are demonstrated in this article. For example, an "About me" dialog is displayed when the title bar is clicked. Thus, this article only describes the basic components and functionality used in the project and how they can be used.

  • If you would be interested to try out the application - you can download it from here. Download and install instructions can be found in readme.txt from here.
  • Feature requests and bug request are welcome. Please add comment below.

If possible, QckWeb could become a useful application on the Nokia OVI store, when Qt Quick applications are supported.

Useful links

This page was last modified on 22 October 2013, at 18:03.
77 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×