Weather service, maps and navigation, photo viewer, instant messaging, web browser, flick list or kinetic scrolling. You want all these with Qt? You get it!
Presentation by Ariya Hidayat held during Qt Developer Days 2009.
http://qt.nokia.com/developer/learning/elearning
2. Agenda
• Mobile platform challenges:
– differences vs desktop
– things to keep in mind
• Examples which demonstrate:
– Low-level painting
– Graphics View
– Network and web stack
2
3. Spread the Love
All examples are available from...
labs.qt.nokia.com
bit.ly/graphicsdojo
3
4. Desktop vs Mobile Platforms
• Hardware power
• Screen size and resolutions
• Input method
• Network access
4
9. Graphics Power
• Lower resolution
• Software rendering
– hardware acceleration with OpenGL ES
• Font metrics
9
10. Input Methods
• Keypad, not keyboard
– often not full QWERTY
• No mouse
– don't bother with mouse move event
• Touch interface
– single vs multitouch
– stylus vs finger
• Sensors: accelerometer, GPS, compass, ...
10
18. Sliding Effect: The Code
QPainter p(this);
int y = height() * currentFrame / 100;
p.drawPixmap(0, y, m_lastPixmap);
p.drawPixmap(0, y - height(), m_pixmap);
p.end();
18
24. A Trick with QBasicTimer
QBasicTimer ticker;
ticker.start(1000, this);
void timerEvent(QTimerEvent*)
{
// update the clock
}
No need for QTimer, a slot, and
periodic triggering of signal/slot !
24
25. QTimeLine for Frame-based Animation
QTimeLine animator;
animator.setFrameRange(0, 100);
animator.setDuration(600);
animator.setCurveShape(QTimeLine::EaseInOutCurve);
int progress = animator.currentFrame();
Linear EaseInOut
deacceleration
acceleration
25
31. Lock the Orientation
S60-specific, usually you do
NOT need to do this!
#include <eikenv.h>
#include <eikappui.h>
#include <aknenv.h>
#include <aknappui.h>
CAknAppUi* appUi = dynamic_cast<CAknAppUi*>
(CEikonEnv::Static()->AppUi());
appUi->SetOrientationL
(CAknAppUi::EAppUiOrientationPortrait);
31
35. Handle the Network Reply
http://www.google.com/ig/api?hl=en&weather=oslo
QUrl url = networkReply->url();
data = QString::fromUtf8(networkReply->readAll());
networkReply->deleteLater();
networkReply->manager()->deleteLater();
35
36. XML Stream Reader for Parsing
QXmlStreamReader xml(data);
while (!xml.atEnd()) {
xml.readNext();
if (xml.tokenType() == QXmlStreamReader::StartElement)
if (xml.name() == "city")
city = xml.attributes().value("data").toString()
}
faster and requires less memory than
using QDom!
36
38. Optimize Your SVG
<g>
<ellipse cx="10" cy="10" rx=2" ry="2"/>
</g>
<ellipse cx="10" cy="10" rx=2" ry="2"/>
Because one element in a group often
does not make sense!
38
39. SVG Loading Time Comparison
Use tools like:
codedread.com/scour
svgmin.googlecode.com
39
43. Web Scraping
• Grab the HTML contents
• Scrap it
– remove unnecessary clutters
– parse and extract the interesting bits
• Legal aspect
– some sites explicitly prohibit the use other than
in a web browser
43
44. Parsing HTML with XML Stream Reader
• HTML != XML
• Potentially provoke the parser (→ errors)
– Solution: “scrub it”, i.e. clean up the raw HTML
// remove all inline frames
while (true) {
i = data.indexOf("<iframe");
if (i < 0)
break;
data.remove(i, data.indexOf("</iframe>") - i + 8);
}
44
45. The Usual Tricks
• Use network request and reply
• Contents
– Construct the request
– Get the HTML data
– Clean it up and then parse it
• Flight map
– Construct the request
– Get data and feed it to a QPixmap
– Display the pixmap, e.g. with QLabel
45
51. Panning with Mouse/Finger/Stylus
Record the tap position
void mousePressEvent(QMouseEvent *event) {
if (event->buttons() != Qt::LeftButton)
return;
pressed = true;
pressPos = dragPos = event->pos();
}
Pan the map based on the movement
void mouseMoveEvent(QMouseEvent *event) {
if (!event->buttons())
return;
QPoint delta = event->pos() - pressPos;
pressPos = event->pos();
pan(delta);
}
51
56. OpenStreetMap vs [Google,Yahoo]Maps
• Free content
– Creative Commons Attribution-ShareAlike 2.0
• API does not require the license key
• Available in
– rendered images
– vector data
More info at www.openstreetmap.org !
56
57. Getting the Rendered Tiles
• Each tile is 256 x 256 pixels
• Zoom level of 0 → the whole world
• Zoom level of 17 → most detailed
QPointF tileForCoordinate(qreal lat, qreal lng, int zoom)
{
qreal zn = static_cast<qreal>(1 << zoom);
qreal tx = (lng + 180.0) / 360.0;
qreal ty = (1.0 - log(tan(lat * M_PI / 180.0) +
1.0 / cos(lat * M_PI / 180.0)) / M_PI)
/ 2.0;
return QPointF(tx * zn, ty * zn);
}
57
61. Night Mode: The Code
Color channel inversion
QPainter p(this);
p.setCompositionMode
(QPainter::CompositionMode_Difference);
p.fillRect(event->rect(), Qt::white);
p.end();
red = 255 – red
green = 255 – green
blue = 255 - blue
61
69. Web Browser
• QtWebKit:
– Standard compliant, fast rendering engine
– Used in Apple Safari, Google Chrome, …
– S60 Browser, Apple iPhone, Google Android,
Palm WebOS, …
• Use QWebView and you are done!
• Add flick support for kinetic scrolling
69
76. Direct Screen Blit
Don't bother “clearing” the widget!
setAttribute(Qt::WA_OpaquePaintEvent, true);
Faster direct screen access using
CDirectScreenBitmap or
Anti-Tearing API
76
77. Bypass Alpha-Blending
Since we handle each and every pixel, ...
QPainter p(this);
p.setCompositionMode(QPainter::Composition_Source)
p.drawImage(0, 0, buffer);
77
79. Memory Access Optimization
Minimize location (in memory) between
two vertically separated pixels
Jump several Jump few
hundreds bytes bytes only
79