Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Best Practices in Qt Quick/QML - Part 4

3,615 views

Published on

The final webinar in our 4 part webinar series explore covers:

QML Data Models
View Delegates
Performance Tips

Published in: Software

Best Practices in Qt Quick/QML - Part 4

  1. 1. © Integrated Computer Solutions, Inc. All Rights Reserved Best Practices in Qt Quick/QML Part 4 Justin Noel Senior Consulting Engineer ICS, Inc.
  2. 2. © Integrated Computer Solutions, Inc. All Rights Reserved Agenda • QML Data Models • View Delegates • Performance Tips
  3. 3. © Integrated Computer Solutions, Inc. All Rights Reserved Data Models
  4. 4. © Integrated Computer Solutions, Inc. All Rights Reserved 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. 5. © Integrated Computer Solutions, Inc. All Rights Reserved Models in QML • All models are lists in QML • No tables • Can be implemented using roles • No trees • Can be implemented using QSortFilterProxyModel
  6. 6. © Integrated Computer Solutions, Inc. All Rights Reserved 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
  7. 7. © Integrated Computer Solutions, Inc. All Rights Reserved 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 230 Second Ave Waltham, MA (617 ) 621 - 0060
  8. 8. © Integrated Computer Solutions, Inc. All Rights Reserved Model Types in QML • QML ListModel Item • QML list<> property • JavaScript JSON • QQmlListProperty<Type> • QList<QObject*> • QAbstractItemModel*
  9. 9. © Integrated Computer Solutions, Inc. All Rights Reserved 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. 10. © Integrated Computer Solutions, Inc. All Rights Reserved 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” } }
  11. 11. © Integrated Computer Solutions, Inc. All Rights Reserved 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. 12. © Integrated Computer Solutions, Inc. All Rights Reserved 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” } ] }
  13. 13. © Integrated Computer Solutions, Inc. All Rights Reserved JSON Model Item { property var json: [ { name:”Justin Noel” phoneNumber:”(617) 621-0060” }, { name:” John Doe” phoneNumber “(555) 555-5555” } ] ListView { model: json delegate: Rectangle { Column { Text { text: name } Text { text: phoneNumer } } } }
  14. 14. © Integrated Computer Solutions, Inc. All Rights Reserved 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. 15. © Integrated Computer Solutions, Inc. All Rights Reserved QList<QObject*> Model import MrCoffee 1.0 Rectangle { CoffeeMaker { id: maker } ListView { anchors.fill: parent model: maker.alarms } }
  16. 16. © Integrated Computer Solutions, Inc. All Rights Reserved QQmlListProperty class BarChart : public QObject { Q_OBJECT Q_CLASSINFO("DefaultProperty", “bars") Q_PROPERTY(QQmlListProperty<Bar> bars READ bars NOTIFY barsChanged) public: QQmlListProperty bars() const; protected: static int barCount(QQmlListProperty<Bar>* property); static Axis* barAt(QQmlListProperty<Bar>* property, int index); static void appendBar(QQmlListProperty<Bar>* property, Bar* value); static void clearBars(QQmlListProperty<Bar>* property); private: QList<Bar*> m_bars; };
  17. 17. © Integrated Computer Solutions, Inc. All Rights Reserved QQmlListProperty QQmlListProperty BarChart::bars() const { return QQmlListProperty<Bar>(this, nullptr, &BarChart::appendBar, &BarChart::barCount, &BarChart::barAt, &BarChart::clearBars); } int BarChart::barCount(QQmlListProperty<Bar>* property) { BarChart* self = qobject_cast<BarChart*>(property->object); return self->m_bars.count(); } Bar* BarChart::barAt(QQmlListProperty<Bar>* property, int index) { BarChart* self = qobject_cast<BarChart*>(property->object); return self->m_bars[index]; }
  18. 18. © Integrated Computer Solutions, Inc. All Rights Reserved QQmlListProperty void BarChart::appendBar(QQmlListProperty<Bar>* property, Bar* value) { BarChart* self = qobject_cast<BarChart*>(property->object); self->m_bars.append(value); emit self->barsChanged(); } void BarChart::clearBars(QQmlListProperty<Bar>* property) { BarChart* self = qobject_cast<BarChart*>(property->object); self->m_bars.clear(); emit self->barsChanged(); }
  19. 19. © Integrated Computer Solutions, Inc. All Rights Reserved QQmlListProperty import BarChart 1.0 Rectangle { BarChart { Bar { color: “red” value: 50 } Bar { color: “blue” value: 10 } } }
  20. 20. © Integrated Computer Solutions, Inc. All Rights Reserved 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
  21. 21. © Integrated Computer Solutions, Inc. All Rights Reserved 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
  22. 22. © Integrated Computer Solutions, Inc. All Rights Reserved 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; };
  23. 23. © Integrated Computer Solutions, Inc. All Rights Reserved 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; }
  24. 24. © Integrated Computer Solutions, Inc. All Rights Reserved 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(); }
  25. 25. © Integrated Computer Solutions, Inc. All Rights Reserved Alarm Model Implementation void AlarmModel::handleAlarmAppened() { beginInsertRows(QModelIndex(), rowCount(), rowCount()); endInsertRows(); } void AlarmModel::handleAlarmRemoved(int alarm) { beginRemoveRows(QModelIndex(), alarm, alarm); endRemoveRows(); }
  26. 26. © Integrated Computer Solutions, Inc. All Rights Reserved 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>
  27. 27. © Integrated Computer Solutions, Inc. All Rights Reserved Delegates
  28. 28. © Integrated Computer Solutions, Inc. All Rights Reserved Delegate Performance Tips • Keep it short. Keep it Simple • Avoid Loader • Avoid Shader Effects / Graphical Effects • Avoid clip: true • Increase cacheBuffer property for smoother scrolling • At the cost of memory
  29. 29. © Integrated Computer Solutions, Inc. All Rights Reserved Coupled Delegate/Model/View • Avoid tight relationships between the view properties, model roles and athedelegate Item { property var json: [ { name:”Justin Noel” icon:”jn.png” }, { name:” John Doe” icon: “jd.png” } ] ListView { model: json delegate: Rectangle { color: ListView.view.isCurrentItem ? “blue” : “white” Column { Image { source: icon } Text { text: name } } MouseArea { onClicked: doSomething(index)} } }
  30. 30. © Integrated Computer Solutions, Inc. All Rights Reserved New Delegate Item • Create a new item for your Delegate ContactRow.qml ------------------------------------------------------ Rectangle { id: contactRow property alias icon: icon.source property alias text: name.text property bool isSelected: false signal clicked() color: isSelected ? “blue” : “white” Column { Image { id: icon } Text { id: text } } MouseArea { onClicked: contactRow.clicked() } }
  31. 31. © Integrated Computer Solutions, Inc. All Rights Reserved Delegate Abstraction Item { property var json: [ { name:”Justin Noel” icon:”jn.png” }, { name:” John Doe” icon: “jd.png” } ] ListView { model: json delegate: ContactRow { isSelected: ListView.view.isCurrentItem text: modelData.name icon: modelData.icon onClicked: doSomething(index) } }
  32. 32. © Integrated Computer Solutions, Inc. All Rights Reserved Performance Tips
  33. 33. © Integrated Computer Solutions, Inc. All Rights Reserved 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
  34. 34. © Integrated Computer Solutions, Inc. All Rights Reserved C++ Type Conversions • Avoid variant type QML properties • Marked as deprecated • Use var instead • Still try to use a specific type if you can • Assigning list types can be expensive • Optimizations implemented are made for • QString, QUrl, int, bool, qreal, pointer types
  35. 35. © Integrated Computer Solutions, Inc. All Rights Reserved 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
  36. 36. © Integrated Computer Solutions, Inc. All Rights Reserved Rendering Performance • 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
  37. 37. © Integrated Computer Solutions, Inc. All Rights Reserved 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()
  38. 38. © Integrated Computer Solutions, Inc. All Rights Reserved 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
  39. 39. © Integrated Computer Solutions, Inc. All Rights Reserved 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.
  40. 40. © Integrated Computer Solutions, Inc. All Rights Reserved Memory Usage • QML uses quite a bit of memory • Typical app is around 10MB 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
  41. 41. © Integrated Computer Solutions, Inc. All Rights Reserved 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
  42. 42. © Integrated Computer Solutions, Inc. All Rights Reserved Fake Animations • If you just need small animated indicators and are very short on processor power…. • Consider AnimatedImage • Takes an animated GIF • 15fps is around 5 percent CPU • User won’t notice
  43. 43. © Integrated Computer Solutions, Inc. All Rights Reserved Thank You! Justin Noel Senior Consulting Engineer ICS, Inc.

×