O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Best Practices in Qt Quick/QML - Part IV

26.992 visualizações

Publicada em

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

Publicada em: Tecnologia
  • Login to see the comments

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.

×