Qt Quick Best Practices Part 4 Justin Noel Senior Consulting Engineer ICS, Inc.
Agenda • QML Data Models • Keyboard Navigation and Focus • Performance Tips
Data Models
Model – View – Delegate Pattern • Views in QML are Model-View-Delegate • Model is an interface to data • View manages item geometries • Delegate implements item UI • Drawing graphics • Editing data
Models in QML • All models are lists in QML • No tables • Can be implemented using roles • No trees • Can be implemented using QSortFilterProxyModel
Model Roles • Roles are like a “3rd Dimension” to cells • Can be use to apply extra attributes • Visible and non-visible • These roles in basic QML are used to make complex cells • Can be used to emulate a table
Model Roles • Consider this ContactsListModel • One item in the list can be very complex Name Role Phone Number Role Address Role Image Role Justin Noel 54 B Middlesex Tpke Bedford, MA (617 ) 621 - 0060
Model Types in QML • QML ListModel Item • QML list<> property • JavaScript JSON • QQmlListProperty<Type> • QList<QObject*> • QAbstractItemModel*
QML List Model • ListModel is a list of ListElement Items • ListElement is a list of Key/Value pairs • Key names are arbitrary • Use whatever is convenient ListView { model: contactModel } ListModel { id: contactModel ListElement { name: “Justin Noel”; phoneNumber: “(617) 621-0060” } ListElement { name: “John Doe”; phoneNumber: “(555) 555-5555” } }
Delegates • Roles appear as attached properties in a Delegate ListView { model: contactModel delegate: Rectangle { Column { Text { text: name } Text { text: phoneNumber } } } ListModel { id: contactModel ListElement { name: “Justin Noel”; phoneNumber: “(617) 621-0060” } ListElement { name: “John Doe”; phoneNumber: “(555) 555-5555” } }
QML Specialty Models • XmlListModel • Create a model from XML • Using XPath and XQuery statements • FolderListModel • Lists a directory on the disk • Not a tree
QML List Property Model //ContactList.qml Item { property list<Contact> contactModel: undefined ListView { model: contactModel delegate: Rectangle { Column { Text { text: name } Text { text: phoneNumer } } } } //Main.qml ContactList { contactModel: [ Contact{ name: “Justin Noel”; phoneNumber: “(617) 621-0060” }, Contact{ name:” John Doe”; phoneNumber: “(555) 555-5555” } ] }
JSON Model Item { property var json: [ { name:”Justin Noel” phoneNumber:”(617) 621-0060” }, { name:” John Doe” phoneNumber “(555) 555-5555” } ] ListView { model: json }
QList<QObject*> Model class Alarm : public QObject { Q_OBJECT Q_PROPERTY(Severity severity...) Q_PROPERTY(QString description...) [...] }; QML_DECLARE_METATYPE(Alarm*); class CoffeeMaker : public QObject { Q_OBJECT Q_PROPERTY(QList<Alarm*> alarms READ alarms NOTIFY alarmsChanged) public: QList<Alarm*> alarms() const { return m_alarms; } };
QList<QObject*> Model import MrCoffee 1.0 Rectangle { CoffeeMaker { id: maker } ListView { anchors.fill: parent model: maker.alarms } }
QAbstractItemModel • Data model interface from Qt Interview Framework • Originally designed for QWidgets • QListView, QTableView, QTreeView • QAbstractItemModel is a tree interface w/ roles • Remember: QML Doesn’t support Tables or Trees • Makes the interface a little confusing for those not familiar with the QWidget views
QAbstractListModel • QAbstractListModel is a specialized QAIM • Implements some of the tree interface • Makes it easier to implement a list • Data models should wrap data rather than store data • Simple interface
Alarm Model Implementation class AlarmModel : public QAbstractListModel { Q_OBJECT public: enum Roles { SeverityRole = Qt::UserRole, DescriptionRole }; AlarmModel(DataModel& data); QHash<int, QByteArray> roleNames() const; int rowCount(const QModelIndex& parent = QModelIndex()) const; QVariant data(const QModelIndex& index, int role) const; private slots: void handleAlarmAppened(); void handleAlarmRemoved(int alarm); private: DataModel& m_data; };
Alarm Model Implementation AlarmModel::AlarmModel(DataModel& data) : m_data(data) { connect(&data, SINGAL(alarmsAppened()), this, SLOT(handleAlarmAppened())); connect(&data, SINGAL(alarmsRemoved(int)), this, SLOT(handleAlarmRemoved(int))); } QHash<int, QByteArray> AlarmModel::roleNames() const { static QHash<int, QByteArray> roles; if(roles.isEmpty) { roles.insert(SeverityRole, “severity”); roles.insert(DescriptionRole, “description”); } return roles; }
Alarm Model Implementation int AlarmModel::rowCount(const QModelIndex& parent) const { if(!parent.isValid()) return m_data.alarms().size(); else return 0; } QVariant AlarmModel::data(const QModelIndex& index, int role) const { if(!index.isValid() || index.column() != 0) return QVariant(); else if(role == SeverityRole) return m_data.alarms()[index.row()].severity(); else if(role == DescriptionRole) return m_data.alarms()[index.row()].description(); }
Alarm Model Implementation void AlarmModel::handleAlarmAppened() { beginInsertRows(QModelIndex(), rowCount(), rowCount()); endInsertRows(); } void AlarmModel::handleAlarmRemoved(int alarm) { beginRemoveRows(QModelIndex(), alarm, alarm); endRemoveRows(); }
Which Model Is Right For Me? • Use Case! Use Case! Use Case! • Web Services based app • Use JSON or XmlListModel • C++ based app • Use QAbstractItemModel or QList<QObject*> • Composite QML items like BarChart • Consists of N Bar items • property list<Type>
Keyboard Handling
Focus Order • Tab order works like a linked list • KeyNavigation is an attached property • Executed only when this Item has focus TextInput { id: firstField focus: true KeyNavigation.tab: secondField } TextInput { id: secondField focus: true KeyNavigation.backTab: firstField }
KeyNavigation • Navigation Possibilities • Tab – Backtab • Right - Left • Down - Up • Qt will automatically reverse a singly linked tab order • If you only specify (Tab, Right, Down) • Qt will automatically do (Backtab, Left, Up)
Focus Property • Only one item in a qml file can have focus = true • Many QML files can be composed together • This results in more than one item with focus = true • This is actual a good thing as focus will be stored Item { //Main.qml OptionsBox { model: firstOptions } OptionsBox { model: otherOptions } } Item { //OptionsBox.qml property alias model: listView.model ListView { focus: true delegate: ... } }
Active Focus • Only one item in a QmlEngine will have activeFocus = true • When drawing focus effects use activeFocus • When taking focus call forceActiveFocus() • Set focus = true • Sets focus on all FocusScope items in parent hierarchy
FocusScope • Proxies Focus to a child item • Can be use directly as a wrapper item • More often it is the base class for QML files Item { //Main.qml OptionsBox { model: firstOptions focus: true } OptionsBox { model: otherOptions } } FocusScope{ //OptionsBox.qml property alias model: listView.model ListView { focus: true delegate: ... } }
FocusScope • When a child of a FocusScope has focus • The FocusScope will also report focus = true • FocusScopes can be nested • If your application needs keyboard input • Use FocusScope as the base class for all your custom items • ListViews, Loader, etc have FocusScope built in
Handling Keyboard Input • Handling actual key stroke is easy • Keys is an attached property • Key specific handlers • Handlers for all keys • Like how QWidgets work
Key Specific Handlers Rectangle { color: “black” focus: true Image { id: rocket x: 150, y:150 source: “../images/rocket.svg” transformOrigin: Item.Center } Keys.onLeftPressed: rocket.rotation = (rocket.rotation - 10) %360 Keys.onRightPressed: rocket.rotation = (rocket.rotation + 10) %360 //Note there are only a few specific key handler available for use }
All Keys Handler Rectangle { color: “black” focus: true Image { id: rocket x: 150, y:150 source: “../images/rocket.svg” transformOrigin: Item.Center } Keys.onPressed: { if(event.key == Qt.Key_Left) rocket.rotation = (rocket.rotation - 10) %360 else if (event.key == Qt.Key_Right) rocket.rotation = (rocket.rotation + 10) %360 } }
Key Event Propagation • Key Events will propagate • From child to parent up to the root item • Propagation can be stopped with • event.accepted = true • Key event will stop at the accepted handler
Event Propagation is Convenient Rectangle { color: “black” focus: true Keys.onVolumeDownPressed: cppMixer.decrementVolume() Keys.onVolumeUpPressed: cppMixer.incrementVolume() Mp3Player { //Internally handles Key_MediaNext, Key_MediaPrevious visible: false focus: visible } AmFmRadio { //Internally handles Key_MediaNext, Key_MediaPrevious visible: false focus: visible } }
Performance Tips
Be Asynchronous • Never spend more than a couple of milliseconds within blocking functions • 60Hz drawing leaves 16ms to get work done • Or frames get dropped! • User worker threads to do heavy lifting • QThread or QML WorkerScript • Never manually spin the event loop • QCoreApplication::processEvents() • This was sorta-kinda acceptable for with widgets
Optimized Binding Evaluator • QML Engine has a binding optimizer • Doesn’t need to invoke the full JS interpreter • If bindings fit certain criteria • Help it out by following some guidelines • Don’t go overboard enforcing these as rules • Micro-optimized unreadable code could ensue • Use the QML Profiler to examine JS performance
Binding Optimizer • Make sure types are known at compile time • Avoid using var as property type • Qt Creator will underline this yellow • Avoid assigning properties to derivative types • Avoid caching intermediate vars in bindings • However, this can be beneficial with full JS interpeter
Binding Optimizer • Avoid calling JavaScript functions • Even though code may be easier to read • Includes anonymous functions • value: function() {…} • Avoid using symbols from JavaScript imports
Binding Optimizer • Only access Properties in “Component” Scope • Properties of this item • Ids of any objects in the containing component • Properties of the root item of the component ListView { id: view property cellHeight: 50 // Bad. Move to inside delegate delegate: Rectangle { height: view.cellHeight } } }
Maximize Binding Optimizer • Avoid writing to other properties in a property binding • This should be obvious. property int other: 0 value: { other = foo } //Also happens to bind value to foo • QML_COMPILER_STATS env var • Print statistics about how many bindings were able to be optimized / not optimized.
C++ Type Conversions • Avoid variant type QML properties • Marked as deprecated • Use var instead • Assigning list types can be expensive • Optimizations implemented are made for • QString, QUrl, int, bool, qreal, pointer types
Cache results • In non-optimized bindings cache results • Save lookup times. • Especially on objects not in “Component Scope”
Don’t Over Update Propeties • Don’t a update property more than one in a binding or signal handler
Delegates • Keep it short. Keep it Simple • Avoid Loader • Avoid Shader Effects • Avoid clip: true • Increase cacheBuffer property for smoother scrolling • At the cost of memory
Animations • Animating properties will cause bindings to update • Usually what is wanted • If not use PropertyAction to “unbind” temporarily • Or create a second animatedValue property • See Bar Chart Example
Painting • Avoid Clipping • Very expensive • Hide non-visible items (visible = false) • Off screen items • Completely obscured items • QtQuick will call rendering methods for all visible items
Startup Performance • Load as little QML as possible at startup • main.qml loads a splash screen • main.qml uses async loader to show 1st screen • Connect loader.progress to an indicator • main.qml hides splash screen when • loader.status === Loader.Ready • From here load the screens as the user finds them • Using Loader or component.createObject()
Runtime Performance • Use lazy loading to load screens on demand • Cache screens as they are found • Or at least common screens • Caching screens causes two side effects • Increase in memory footprint • Processing of bindings for items not on the screen
Processing Bindings Off Screen • Bindings are re-calculated when property NOTIFY signals are emitted • On screen or not • This might not be a bad thing • If your system is mostly idle • Might as well update bindings while system is idle • Rather than fetch all the data and re-calc when switching screens which might be animated • Use case dependent. YMMV.
Memory Usage • QML uses quite a bit of memory • Typical app is around 80MB resident • Qt internals is making this better • Delete items made with Component createObject • Use destroy() • Delete uncommon dialogs after the user is done with them • Trading memory for screen reload performance
Processor Performance • QtQuick 2 is OpenGL ES 2.0 based • But some things still need to be run on the main processor • Animations @ 60 Hz require about 30% of the lowend TI AM3358 CPU* • Code from event handlers can only block for 16ms max • Or frames will be dropped • User will notice if it’s bad enough
Fake Animations • If you just need small animated indicators • Consider AnimatedImage • Takes an animated GIF • QtQuick has some optimizations for AnimatedImage • 15fps is around 5 percent CPU • User won’t notice
Thank You! Justin Noel Senior Consulting Engineer ICS, Inc.

Best Practices in Qt Quick/QML - Part IV

  • 1.
    Qt Quick BestPractices Part 4 Justin Noel Senior Consulting Engineer ICS, Inc.
  • 2.
    Agenda • QML DataModels • Keyboard Navigation and Focus • Performance Tips
  • 3.
  • 4.
    Model – View– Delegate Pattern • Views in QML are Model-View-Delegate • Model is an interface to data • View manages item geometries • Delegate implements item UI • Drawing graphics • Editing data
  • 5.
    Models in QML •All models are lists in QML • No tables • Can be implemented using roles • No trees • Can be implemented using QSortFilterProxyModel
  • 6.
    Model Roles • Rolesare like a “3rd Dimension” to cells • Can be use to apply extra attributes • Visible and non-visible • These roles in basic QML are used to make complex cells • Can be used to emulate a table
  • 7.
    Model Roles • Considerthis ContactsListModel • One item in the list can be very complex Name Role Phone Number Role Address Role Image Role Justin Noel 54 B Middlesex Tpke Bedford, MA (617 ) 621 - 0060
  • 8.
    Model Types inQML • QML ListModel Item • QML list<> property • JavaScript JSON • QQmlListProperty<Type> • QList<QObject*> • QAbstractItemModel*
  • 9.
    QML List Model •ListModel is a list of ListElement Items • ListElement is a list of Key/Value pairs • Key names are arbitrary • Use whatever is convenient ListView { model: contactModel } ListModel { id: contactModel ListElement { name: “Justin Noel”; phoneNumber: “(617) 621-0060” } ListElement { name: “John Doe”; phoneNumber: “(555) 555-5555” } }
  • 10.
    Delegates • Roles appearas attached properties in a Delegate ListView { model: contactModel delegate: Rectangle { Column { Text { text: name } Text { text: phoneNumber } } } ListModel { id: contactModel ListElement { name: “Justin Noel”; phoneNumber: “(617) 621-0060” } ListElement { name: “John Doe”; phoneNumber: “(555) 555-5555” } }
  • 11.
    QML Specialty Models •XmlListModel • Create a model from XML • Using XPath and XQuery statements • FolderListModel • Lists a directory on the disk • Not a tree
  • 12.
    QML List PropertyModel //ContactList.qml Item { property list<Contact> contactModel: undefined ListView { model: contactModel delegate: Rectangle { Column { Text { text: name } Text { text: phoneNumer } } } } //Main.qml ContactList { contactModel: [ Contact{ name: “Justin Noel”; phoneNumber: “(617) 621-0060” }, Contact{ name:” John Doe”; phoneNumber: “(555) 555-5555” } ] }
  • 13.
    JSON Model Item { propertyvar json: [ { name:”Justin Noel” phoneNumber:”(617) 621-0060” }, { name:” John Doe” phoneNumber “(555) 555-5555” } ] ListView { model: json }
  • 14.
    QList<QObject*> Model class Alarm: public QObject { Q_OBJECT Q_PROPERTY(Severity severity...) Q_PROPERTY(QString description...) [...] }; QML_DECLARE_METATYPE(Alarm*); class CoffeeMaker : public QObject { Q_OBJECT Q_PROPERTY(QList<Alarm*> alarms READ alarms NOTIFY alarmsChanged) public: QList<Alarm*> alarms() const { return m_alarms; } };
  • 15.
    QList<QObject*> Model import MrCoffee1.0 Rectangle { CoffeeMaker { id: maker } ListView { anchors.fill: parent model: maker.alarms } }
  • 16.
    QAbstractItemModel • Data modelinterface from Qt Interview Framework • Originally designed for QWidgets • QListView, QTableView, QTreeView • QAbstractItemModel is a tree interface w/ roles • Remember: QML Doesn’t support Tables or Trees • Makes the interface a little confusing for those not familiar with the QWidget views
  • 17.
    QAbstractListModel • QAbstractListModel isa specialized QAIM • Implements some of the tree interface • Makes it easier to implement a list • Data models should wrap data rather than store data • Simple interface
  • 18.
    Alarm Model Implementation classAlarmModel : public QAbstractListModel { Q_OBJECT public: enum Roles { SeverityRole = Qt::UserRole, DescriptionRole }; AlarmModel(DataModel& data); QHash<int, QByteArray> roleNames() const; int rowCount(const QModelIndex& parent = QModelIndex()) const; QVariant data(const QModelIndex& index, int role) const; private slots: void handleAlarmAppened(); void handleAlarmRemoved(int alarm); private: DataModel& m_data; };
  • 19.
    Alarm Model Implementation AlarmModel::AlarmModel(DataModel&data) : m_data(data) { connect(&data, SINGAL(alarmsAppened()), this, SLOT(handleAlarmAppened())); connect(&data, SINGAL(alarmsRemoved(int)), this, SLOT(handleAlarmRemoved(int))); } QHash<int, QByteArray> AlarmModel::roleNames() const { static QHash<int, QByteArray> roles; if(roles.isEmpty) { roles.insert(SeverityRole, “severity”); roles.insert(DescriptionRole, “description”); } return roles; }
  • 20.
    Alarm Model Implementation intAlarmModel::rowCount(const QModelIndex& parent) const { if(!parent.isValid()) return m_data.alarms().size(); else return 0; } QVariant AlarmModel::data(const QModelIndex& index, int role) const { if(!index.isValid() || index.column() != 0) return QVariant(); else if(role == SeverityRole) return m_data.alarms()[index.row()].severity(); else if(role == DescriptionRole) return m_data.alarms()[index.row()].description(); }
  • 21.
    Alarm Model Implementation voidAlarmModel::handleAlarmAppened() { beginInsertRows(QModelIndex(), rowCount(), rowCount()); endInsertRows(); } void AlarmModel::handleAlarmRemoved(int alarm) { beginRemoveRows(QModelIndex(), alarm, alarm); endRemoveRows(); }
  • 22.
    Which Model IsRight For Me? • Use Case! Use Case! Use Case! • Web Services based app • Use JSON or XmlListModel • C++ based app • Use QAbstractItemModel or QList<QObject*> • Composite QML items like BarChart • Consists of N Bar items • property list<Type>
  • 23.
  • 24.
    Focus Order • Taborder works like a linked list • KeyNavigation is an attached property • Executed only when this Item has focus TextInput { id: firstField focus: true KeyNavigation.tab: secondField } TextInput { id: secondField focus: true KeyNavigation.backTab: firstField }
  • 25.
    KeyNavigation • Navigation Possibilities •Tab – Backtab • Right - Left • Down - Up • Qt will automatically reverse a singly linked tab order • If you only specify (Tab, Right, Down) • Qt will automatically do (Backtab, Left, Up)
  • 26.
    Focus Property • Onlyone item in a qml file can have focus = true • Many QML files can be composed together • This results in more than one item with focus = true • This is actual a good thing as focus will be stored Item { //Main.qml OptionsBox { model: firstOptions } OptionsBox { model: otherOptions } } Item { //OptionsBox.qml property alias model: listView.model ListView { focus: true delegate: ... } }
  • 27.
    Active Focus • Onlyone item in a QmlEngine will have activeFocus = true • When drawing focus effects use activeFocus • When taking focus call forceActiveFocus() • Set focus = true • Sets focus on all FocusScope items in parent hierarchy
  • 28.
    FocusScope • Proxies Focusto a child item • Can be use directly as a wrapper item • More often it is the base class for QML files Item { //Main.qml OptionsBox { model: firstOptions focus: true } OptionsBox { model: otherOptions } } FocusScope{ //OptionsBox.qml property alias model: listView.model ListView { focus: true delegate: ... } }
  • 29.
    FocusScope • When achild of a FocusScope has focus • The FocusScope will also report focus = true • FocusScopes can be nested • If your application needs keyboard input • Use FocusScope as the base class for all your custom items • ListViews, Loader, etc have FocusScope built in
  • 30.
    Handling Keyboard Input •Handling actual key stroke is easy • Keys is an attached property • Key specific handlers • Handlers for all keys • Like how QWidgets work
  • 31.
    Key Specific Handlers Rectangle{ color: “black” focus: true Image { id: rocket x: 150, y:150 source: “../images/rocket.svg” transformOrigin: Item.Center } Keys.onLeftPressed: rocket.rotation = (rocket.rotation - 10) %360 Keys.onRightPressed: rocket.rotation = (rocket.rotation + 10) %360 //Note there are only a few specific key handler available for use }
  • 32.
    All Keys Handler Rectangle{ color: “black” focus: true Image { id: rocket x: 150, y:150 source: “../images/rocket.svg” transformOrigin: Item.Center } Keys.onPressed: { if(event.key == Qt.Key_Left) rocket.rotation = (rocket.rotation - 10) %360 else if (event.key == Qt.Key_Right) rocket.rotation = (rocket.rotation + 10) %360 } }
  • 33.
    Key Event Propagation •Key Events will propagate • From child to parent up to the root item • Propagation can be stopped with • event.accepted = true • Key event will stop at the accepted handler
  • 34.
    Event Propagation isConvenient Rectangle { color: “black” focus: true Keys.onVolumeDownPressed: cppMixer.decrementVolume() Keys.onVolumeUpPressed: cppMixer.incrementVolume() Mp3Player { //Internally handles Key_MediaNext, Key_MediaPrevious visible: false focus: visible } AmFmRadio { //Internally handles Key_MediaNext, Key_MediaPrevious visible: false focus: visible } }
  • 35.
  • 36.
    Be Asynchronous • Neverspend more than a couple of milliseconds within blocking functions • 60Hz drawing leaves 16ms to get work done • Or frames get dropped! • User worker threads to do heavy lifting • QThread or QML WorkerScript • Never manually spin the event loop • QCoreApplication::processEvents() • This was sorta-kinda acceptable for with widgets
  • 37.
    Optimized Binding Evaluator •QML Engine has a binding optimizer • Doesn’t need to invoke the full JS interpreter • If bindings fit certain criteria • Help it out by following some guidelines • Don’t go overboard enforcing these as rules • Micro-optimized unreadable code could ensue • Use the QML Profiler to examine JS performance
  • 38.
    Binding Optimizer • Makesure types are known at compile time • Avoid using var as property type • Qt Creator will underline this yellow • Avoid assigning properties to derivative types • Avoid caching intermediate vars in bindings • However, this can be beneficial with full JS interpeter
  • 39.
    Binding Optimizer • Avoidcalling JavaScript functions • Even though code may be easier to read • Includes anonymous functions • value: function() {…} • Avoid using symbols from JavaScript imports
  • 40.
    Binding Optimizer • Onlyaccess Properties in “Component” Scope • Properties of this item • Ids of any objects in the containing component • Properties of the root item of the component ListView { id: view property cellHeight: 50 // Bad. Move to inside delegate delegate: Rectangle { height: view.cellHeight } } }
  • 41.
    Maximize Binding Optimizer •Avoid writing to other properties in a property binding • This should be obvious. property int other: 0 value: { other = foo } //Also happens to bind value to foo • QML_COMPILER_STATS env var • Print statistics about how many bindings were able to be optimized / not optimized.
  • 42.
    C++ Type Conversions •Avoid variant type QML properties • Marked as deprecated • Use var instead • Assigning list types can be expensive • Optimizations implemented are made for • QString, QUrl, int, bool, qreal, pointer types
  • 43.
    Cache results • Innon-optimized bindings cache results • Save lookup times. • Especially on objects not in “Component Scope”
  • 44.
    Don’t Over UpdatePropeties • Don’t a update property more than one in a binding or signal handler
  • 45.
    Delegates • Keep itshort. Keep it Simple • Avoid Loader • Avoid Shader Effects • Avoid clip: true • Increase cacheBuffer property for smoother scrolling • At the cost of memory
  • 46.
    Animations • Animating propertieswill cause bindings to update • Usually what is wanted • If not use PropertyAction to “unbind” temporarily • Or create a second animatedValue property • See Bar Chart Example
  • 47.
    Painting • Avoid Clipping •Very expensive • Hide non-visible items (visible = false) • Off screen items • Completely obscured items • QtQuick will call rendering methods for all visible items
  • 48.
    Startup Performance • Loadas little QML as possible at startup • main.qml loads a splash screen • main.qml uses async loader to show 1st screen • Connect loader.progress to an indicator • main.qml hides splash screen when • loader.status === Loader.Ready • From here load the screens as the user finds them • Using Loader or component.createObject()
  • 49.
    Runtime Performance • Uselazy loading to load screens on demand • Cache screens as they are found • Or at least common screens • Caching screens causes two side effects • Increase in memory footprint • Processing of bindings for items not on the screen
  • 50.
    Processing Bindings OffScreen • Bindings are re-calculated when property NOTIFY signals are emitted • On screen or not • This might not be a bad thing • If your system is mostly idle • Might as well update bindings while system is idle • Rather than fetch all the data and re-calc when switching screens which might be animated • Use case dependent. YMMV.
  • 51.
    Memory Usage • QMLuses quite a bit of memory • Typical app is around 80MB resident • Qt internals is making this better • Delete items made with Component createObject • Use destroy() • Delete uncommon dialogs after the user is done with them • Trading memory for screen reload performance
  • 52.
    Processor Performance • QtQuick2 is OpenGL ES 2.0 based • But some things still need to be run on the main processor • Animations @ 60 Hz require about 30% of the lowend TI AM3358 CPU* • Code from event handlers can only block for 16ms max • Or frames will be dropped • User will notice if it’s bad enough
  • 53.
    Fake Animations • Ifyou just need small animated indicators • Consider AnimatedImage • Takes an animated GIF • QtQuick has some optimizations for AnimatedImage • 15fps is around 5 percent CPU • User won’t notice
  • 54.
    Thank You! Justin Noel SeniorConsulting Engineer ICS, Inc.