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 IV

24,644 views

Published on

Qt Quick/QML brings designers and developers together to create and collaborate. QML is a collection of technologies that can build modern and fluid interfaces for applications – quickly. Join us for this webinar to explore the best of QML for mobile, embedded and desktop.

Part IV will cover:

- Dynamic Item Creation
- Keyboard Input Handling

Published in: Technology
  • ➤➤ How Long Does She Want You to Last? Here's the link to the FREE report ➤➤ https://tinyurl.com/rockhardxx
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • ★★ How Long Does She Want You to Last? ★★ A recent study proved that the average man lasts just 2-5 minutes in bed (during intercourse). The study also showed that many women need at least 7-10 minutes of intercourse to reach "The Big O" - and, worse still... 30% of women never get there during intercourse. Clearly, most men are NOT fulfilling there women's needs in bed. Now, as I've said many times - how long you can last is no guarantee of being a GREAT LOVER. But, not being able to last 20, 30 minutes or more, is definitely a sign that you're not going to "set your woman's world on fire" between the sheets. Question is: "What can you do to last longer?" Well, one of the best recommendations I can give you today is to read THIS report. In it, you'll discover a detailed guide to an Ancient Taoist Thrusting Technique that can help any man to last much longer in bed. I can vouch 100% for the technique because my husband has been using it for years :) Here's the link to the report ➤➤ https://tinyurl.com/rockhardxxx
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • I like the proposed architecture a lot! However, for small QML apps, you can also introduce a similar pattern with a smaller and lightweight solution purely in QML. If you're interested, you can find the full developer guide here: https://v-play.net/apps/avoid-cpp-models-qt
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hello, what does realy mean "Avoid calling JavaScript function"? Show an example?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Best Practices in Qt Quick/QML - Part IV

  1. 1. Qt Quick Best Practices Part 4 Justin Noel Senior Consulting Engineer ICS, Inc.
  2. 2. Agenda • QML Data Models • Keyboard Navigation and Focus • Performance Tips
  3. 3. Data Models
  4. 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. 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. 6. 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. 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
  8. 8. Model Types in QML • QML ListModel Item • QML list<> property • JavaScript JSON • QQmlListProperty<Type> • QList<QObject*> • QAbstractItemModel*
  9. 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. 10. 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. 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. 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. JSON Model Item { property var json: [ { name:”Justin Noel” phoneNumber:”(617) 621-0060” }, { name:” John Doe” phoneNumber “(555) 555-5555” } ] ListView { model: json }
  14. 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. 15. QList<QObject*> Model import MrCoffee 1.0 Rectangle { CoffeeMaker { id: maker } ListView { anchors.fill: parent model: maker.alarms } }
  16. 16. 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
  17. 17. 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
  18. 18. 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; };
  19. 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. 20. 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(); }
  21. 21. Alarm Model Implementation void AlarmModel::handleAlarmAppened() { beginInsertRows(QModelIndex(), rowCount(), rowCount()); endInsertRows(); } void AlarmModel::handleAlarmRemoved(int alarm) { beginRemoveRows(QModelIndex(), alarm, alarm); endRemoveRows(); }
  22. 22. 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>
  23. 23. Keyboard Handling
  24. 24. 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 }
  25. 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. 26. 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: ... } }
  27. 27. 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
  28. 28. 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: ... } }
  29. 29. 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
  30. 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. 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. 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. 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. 34. 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 } }
  35. 35. Performance Tips
  36. 36. 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
  37. 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. 38. 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
  39. 39. 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
  40. 40. 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 } } }
  41. 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. 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. 43. Cache results • In non-optimized bindings cache results • Save lookup times. • Especially on objects not in “Component Scope”
  44. 44. Don’t Over Update Propeties • Don’t a update property more than one in a binding or signal handler
  45. 45. 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
  46. 46. 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
  47. 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. 48. 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()
  49. 49. 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
  50. 50. 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.
  51. 51. 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
  52. 52. 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
  53. 53. 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
  54. 54. Thank You! Justin Noel Senior Consulting Engineer ICS, Inc.

×