We’ve already used JavaScript a lot in our code, but we have only scratched the surface. JavaScript can be used in many more sophisticated and powerful ways in a Qt Quick application. In fact, Qt Quick is implemented as a JavaScript extension. JavaScript can be used almost anywhere as long as the code returns the value of the expected type. Moreover, using JavaScript is the standard way of writing parts of the application code which deal with application logic and calculations.
There are two important topics we need to talk about before we continue developing our application.
JavaScript has its origins in the web development. In the course of time, JavaScript has rapidly grown in its popularity and inspired development of many extensions and add-ons. In order to support a broad use, JavaScript was formalized as a programming language in ECMAScript-262 standard. It is important to underline that ECMAScript-262 standard only covers the language aspects and leaves out any API providing additional functionality such as objects and libraries to access the web page content. Despite the standardization efforts, many JavaScript details in web development are still browser-specific - even though the situation has improved in the last few years. See the Wikipedia article about JavaScript [http://en.wikipedia.org/wiki/Javascript] for more details.
JavaScript is also used outside of the web where its functionality is tailored to support a use case. Still, the use of JavaScript for client-side programming in web development is dominating. Due to this, all books and most web resources about JavaScript are actually dedicated to web development. Qt Quick belongs to one of the platforms which use JavaScript outside of the web. If you read books or other materials about JavaScript to understand and use it better with Qt Quick, be aware of this difference.
Qt development teams are doing their best to provide all the details the use of JavaScript in Qt Quick, and this guide is part of that effort.
This guide contains an annex about basics of JavaScript tailored for Qt Quick. We strongly recommend reading it if you are not familiar with JavaScript, but have some general background in programming.
In addition to the references in the annex, consider reading the following articles on the Mozilla Developer Network:
- “About JavaScript” [http://developer.mozilla.org/en/JavaScript/About_JavaScript]
- “A re-introduction to JavaScript” [http://developer.mozilla.org/en/A_re-introduction_to_JavaScript]
- “JavaScript Guide” [http://developer.mozilla.org/en/JavaScript/Guide]
The following three articles in Qt Documentation explain essential details of JavaScript in Qt Quick:
- Integrating JavaScript [http://qt-project.org/doc/qt-4.8/qdeclarativejavascript.html] - key aspects to be aware of when using JavaScript in Qt Quick
- ECMAScript Reference [http://qt-project.org/doc/qt-4.8/ecmascript.html] - a list of built-in objects, functions and properties supported by QtScript and so in Qt Quick
- QML Scope [http://qt-project.org/doc/qt-4.8/qdeclarativescope.html] - explains the visibility of JavaScript objects and Qt Quick items
Note that significant changes and large updates to Qt Documentation may come with the future Qt releases to provide a full coverage of the use of JavaScript in Qt Quick. Stay tuned and check Qt Documentation again and again.
We’ve already used a bit of JavaScript in previous sections. Most of it was for catching error conditions while loading a custom font and an image. In this section, we use JavaScript to show the actual time and date.
We are going to use the Date from the global object to get the current time and date. The returned data has to be formatted so that we only keep parts of the date and time information that we need. We use Qt.formatDateTime [http://qt-project.org/doc/qt-4.8/qml-qt.html#formatDateTime-method] for this:
function getFormattedDateTime(format) {
var date = new Date
return Qt.formatDateTime(date, format)
}
The :Qt.formatDateTime [http://qt-project.org/doc/qt-4.8/qml-qt.html#formatDateTime-method] function is part of QML Global Object [http://qt-project.org/doc/qt-4.8/qdeclarativeglobalobject.html], which provides many other useful utilities in addition to the standard set defined by the ECMAScript Reference [http://qt-project.org/doc/qt-4.8/ecmascript.html]. It is worth taking a closer look at its documentation.
The getFormattedDateTime() function is used in another function, which creates actual values for the Text [http://qt-project.org/doc/qt-4.8/qml-text.html] elements in our clock:
function updateTime() {
root.currentTime = "<big>" +
getFormattedDateTime(Style.timeFormat) +
"</big>" +
(showSeconds ? "<sup><small> " + getFormattedDateTime("ss") +
"</small></sup>" : "");
root.currentDate = getFormattedDateTime(Style.dateFormat);
}
Note
We use rich-text formatting in the text value of the time as discussed in the previous section.
We also use the conditional operator (also called the “ternary operator”) on the value of showSeconds. showSeconds is a custom property that defines whether the seconds must be shown on the clock. Using the conditional operator in Qt Quick is a very convenient way to bind a property (or any other variable) to a value depending on a condition.
The updateTime() function needs a trigger so that the currentTime and currentDate properties are constantly updated. We use the Timer [http://qt-project.org/doc/qt-4.8/qml-timer.html] item for this:
Timer {
id: updateTimer
running: Qt.application.active && visible == true
repeat: true
triggeredOnStart: true
onTriggered: {
updateTime()
// refresh the interval to update time each second or minute.
// consider the delta in order to update on a full minute
interval = 1000 (showSeconds? 1 : (60 - getFormattedDateTime("ss")))
}
}
Our timer implements some interesting aspects.
In order to optimize battery consumption, we bind the timer’s running property to two other properties, which stops the timer, thereby reducing CPU activity. It stops if our clock element becomes invisible (when used as a component in another application) or if our application becomes inactive (running in the background or iconified).
We also assign a value to the interval property while not loading, but when the timer is triggered. This is needed to catch the delta time to the full minute when seconds are not used. This ensures that we update the clock exactly on the minute.
The full code of our application including all enhancements discussed above looks like this:
(NightClock/NightClock.qml in qt_quick_app_dev_intro_src.zip, see Downloads section)
import QtQuick 1.1
Rectangle {
id: root
property bool showDate: true
property bool showSeconds: true
property string currentTime
property string currentDate
// the sizes are in proportion to the hight of the clock.
// There are three borders, text and date.
// 3*borderProportion+timeTextProportion+dateTextProportion has to be 1.0
property real borderProportion: 0.1
property real timeTextProportion: 0.5
property real dateTextProportion: 0.2
property string textColor: "red"
property string timeFormat: "hh :mm"
property string dateFormat: "dd/MM/yy"
height:120
width:250
color: "transparent"
// returns formated time and date
function getFormattedDateTime(format) {
var date = new Date
return Qt.formatDateTime(date, format)
}
function updateTime() {
root.currentTime = "<big>" +
getFormattedDateTime(timeFormat) +
"</big>" +
(showSeconds ? "<sup><small> " + getFormattedDateTime("ss") +
"</small></sup>" : "");
root.currentDate = getFormattedDateTime(dateFormat);
}
Image {
id: background
source: "../content/resources/background.png"
fillMode: "Tile"
anchors.fill: parent
onStatusChanged: if (background.status == Image.Error)
console.log (qsTr("Background image \"") +
source +
qsTr("\" cannot be loaded"))
}
FontLoader {
id: ledFont
// unfortunately, the font will not load on a Symbian device,
// and the default font will be used:
// http://bugreports.qt-project.org/browse/QTBUG-6611
// The bug should be fixed in 4.8
source: "../content/resources/font/LED_REAL.TTF"
onStatusChanged: if (ledFont.status == FontLoader.Error)
console.log("Font \"" + source + "\" cannot be loaded")
}
Timer {
id: updateTimer
running: Qt.application.active && visible == true
repeat: true
triggeredOnStart: true
onTriggered: {
updateTime()
// refresh the interval to update the time each second or minute.
// consider the delta in order to update on a full minute
interval = 1000*(showSeconds? 1 : (60 - getFormattedDateTime("ss")))
}
}
// trigger an update if the showSeconds setting has changed
onShowSecondsChanged: {
updateTime()
}
Column {
id: clockText
anchors.centerIn: parent
spacing: root.height*root.borderProportion
Text {
id: timeText
textFormat: Text.RichText
text: root.currentTime
font.pixelSize: root.height*root.timeTextProportion
font.family: ledFont.name // use "Series 60 ZDigi" on Symbian instead
font.bold: true
color: root.textColor
style: Text.Raised
styleColor: "black"
}
Text {
id: dateText
text: root.currentDate
color: root.textColor
anchors.horizontalCenter: parent.horizontalCenter
font.family: ledFont.name // use "Series 60 ZDigi" on Symbian instead
font.pixelSize: root.height*root.dateTextProportion
visible: root.showDate
style: Text.Raised
styleColor: "black"
}
}
}
The appearance of the application has remained the same:
If your application has a lot of JavaScript code, consider moving it to a separate file. You can import those files just like we imported the Qt Quick module. Due to a special role that JavaScript plays in Qt Quick, you must define the namespace for the content of the that file, for example, Logic in this example. Your source code would then use Logic.foo() instead of just foo(). The import statement looks like this:
import QtQuick 1.1
import "logic.js" as Logic
Note
If the application logic is complex, consider implementing it in C++ and importing it into Qt Quick. See the “Extending QML Functionalities using C++” [http://qt-project.org/doc/qt-4.8/qml-extending.html] article for more details.
When you import a JavaScript file, it is used like a library and has the scope of the QML file importing it. In some cases you might need a stateless library or a set of global variables shared by multiple QML files. You can use the .pragma library declaration for this. See the “Integrating JavaScript” [http://qt-project.org/doc/qt-4.8/qdeclarativejavascript.html] article in Qt Documentation for more details.
We move the JavaScript functions of our clock into the logic.js file imported as Logic. We also move all style properties into the style.js file imported as Style. This considerably simplifies the code and allows sharing the style with other components that we’re going to develop later.
The complete code of our application importing JavaScript files as discussed above looks like this:
(components/NightClock.qml in qt_quick_app_dev_intro_src.zip, see Downloads section)
import QtQuick 1.1
import "../js/style.js" as Style
import "../js/logic.js" as Logic
Rectangle {
id: root
property bool showDate: true
property bool showSeconds: true
property string currentTime
property string currentDate
property string textColor: "green"
height:120
width:300
color: "transparent"
function updateTime() {
root.currentTime = "<big>" + Logic.getFormattedDateTime(Style.timeFormat) + "</big>" +
(showSeconds ? "<sup><small> " + Logic.getFormattedDateTime("ss") + "</small></sup>" : "");
root.currentDate = Logic.getFormattedDateTime(Style.dateFormat);
}
FontLoader {
id: ledFont
// unfortunately, the font will not load on a Symbian device,
// and the default font will be used:
// http://bugreports.qt-project.org/browse/QTBUG-6611
// The bug should be fixed in 4.8
source: "../content/resources/font/LED_REAL.TTF"
onStatusChanged: if (ledFont.status == FontLoader.Error)
console.log("Font \"" + source + "\" cannot be loaded")
}
Timer {
id: updateTimer
running: Qt.application.active && visible == true
repeat: true
triggeredOnStart: true
onTriggered: {
updateTime()
// refresh the interval to update the time each second or minute.
// consider the delta in order to update on a full minute
interval = 1000*(showSeconds? 1 : (60 - Logic.getFormattedDateTime("ss")))
}
}
// trigger an update if the showSeconds setting has changed
onShowSecondsChanged: {
updateTime()
}
Column {
id: clockText
anchors.centerIn: parent
spacing: root.height*Style.borderProportion
Text {
id: timeText
textFormat: Text.RichText
text: root.currentTime
font.pixelSize: root.height*Style.timeTextProportion
font.family: ledFont.name // use "Series 60 ZDigi" on Symbian instead
font.bold: true
color: root.textColor
style: Text.Raised
styleColor: "black"
}
Text {
id: dateText
text: root.currentDate
color: root.textColor
anchors.horizontalCenter: parent.horizontalCenter
font.family: ledFont.name // use "Series 60 ZDigi" on Symbian instead
font.pixelSize: root.height*Style.dateTextProportion
visible: root.showDate
style: Text.Raised
styleColor: "black"
}
}
}
More Advanced Use of JavaScript
If you are interested in a more advanced use of JavaScript with Qt Quick, consider reading “Qt Quick Application Developer Guide for Desktop” available under this link [http://qt-project.org/wiki/Developer-Guides/].
What’s Next?
In the next chapter, we start developing the weather forecast application and learn how to retrieve and represent data in Qt Quick.