Best Practices in Qt Quick/QML - Part IV
-
Upload
ics -
Category
Technology
-
view
139 -
download
5
Transcript of Best Practices in Qt Quick/QML - Part IV
![Page 1: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/1.jpg)
Qt Quick Best PracticesPart 4
Justin NoelSenior Consulting Engineer
ICS, Inc.
![Page 2: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/2.jpg)
Agenda• QML Data Models• Keyboard Navigation and Focus• Performance Tips
![Page 3: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/3.jpg)
Data Models
![Page 4: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/4.jpg)
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
![Page 5: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/5.jpg)
Models in QML• All models are lists in QML
• No tables• Can be implemented using roles
• No trees• Can be implemented using QSortFilterProxyModel
![Page 6: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/6.jpg)
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
![Page 7: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/7.jpg)
Model Roles• Consider this ContactsListModel
• One item in the list can be very complex
Name RolePhone Number Role
Address Role
Image RoleJustin Noel54 B Middlesex TpkeBedford, MA(617 ) 621 - 0060
![Page 8: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/8.jpg)
Model Types in QML• QML ListModel Item• QML list<> property• JavaScript JSON• QQmlListProperty<Type>• QList<QObject*>• QAbstractItemModel*
![Page 9: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/9.jpg)
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 convenientListView {
model: contactModel}
ListModel {id: contactModelListElement { name: “Justin Noel”; phoneNumber: “(617) 621-0060” }ListElement { name: “John Doe”; phoneNumber: “(555) 555-5555” }
}
![Page 10: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/10.jpg)
Delegates• Roles appear as attached properties in a
DelegateListView {
model: contactModeldelegate: Rectangle {
Column {Text { text: name }Text { text: phoneNumber }
}}
ListModel {id: contactModelListElement { name: “Justin Noel”; phoneNumber: “(617) 621-0060” }ListElement { name: “John Doe”; phoneNumber: “(555) 555-5555” }
}
![Page 11: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/11.jpg)
QML Specialty Models• XmlListModel
• Create a model from XML• Using XPath and XQuery statements
• FolderListModel• Lists a directory on the disk• Not a tree
![Page 12: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/12.jpg)
QML List Property Model//ContactList.qmlItem {
property list<Contact> contactModel: undefined
ListView {model: contactModeldelegate: Rectangle {
Column {Text { text: name }Text { text: phoneNumer }
}}
}
//Main.qmlContactList {contactModel: [
Contact{ name: “Justin Noel”; phoneNumber: “(617) 621-0060” }, Contact{ name:” John Doe”; phoneNumber: “(555) 555-5555” }
]}
![Page 13: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/13.jpg)
JSON ModelItem {
property var json: [{ name:”Justin Noel” phoneNumber:”(617) 621-0060” },{ name:” John Doe” phoneNumber “(555) 555-5555” }
]
ListView {model: json
}
![Page 14: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/14.jpg)
QList<QObject*> Modelclass Alarm : public QObject{
Q_OBJECTQ_PROPERTY(Severity severity...)Q_PROPERTY(QString description...)[...]
};QML_DECLARE_METATYPE(Alarm*);
class CoffeeMaker : public QObject{Q_OBJECTQ_PROPERTY(QList<Alarm*> alarms READ alarms NOTIFY alarmsChanged)
public:QList<Alarm*> alarms() const{
return m_alarms;}
};
![Page 15: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/15.jpg)
QList<QObject*> Modelimport MrCoffee 1.0
Rectangle {
CoffeeMaker {id: maker
}
ListView {anchors.fill: parentmodel: maker.alarms
}}
![Page 16: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/16.jpg)
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
![Page 17: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/17.jpg)
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
![Page 18: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/18.jpg)
Alarm Model Implementationclass 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;
};
![Page 19: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/19.jpg)
Alarm Model ImplementationAlarmModel::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;
}
![Page 20: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/20.jpg)
Alarm Model Implementationint AlarmModel::rowCount(const QModelIndex& parent) const{if(!parent.isValid())return m_data.alarms().size();
elsereturn 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();
}
![Page 21: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/21.jpg)
Alarm Model Implementationvoid AlarmModel::handleAlarmAppened(){
beginInsertRows(QModelIndex(), rowCount(), rowCount());endInsertRows();
}
void AlarmModel::handleAlarmRemoved(int alarm){beginRemoveRows(QModelIndex(), alarm, alarm);endRemoveRows();
}
![Page 22: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/22.jpg)
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>
![Page 23: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/23.jpg)
Keyboard Handling
![Page 24: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/24.jpg)
Focus Order• Tab order works like a linked list• KeyNavigation is an attached property
• Executed only when this Item has focusTextInput {
id: firstFieldfocus: trueKeyNavigation.tab: secondField
}
TextInput {id: secondFieldfocus: trueKeyNavigation.backTab: firstField
}
![Page 25: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/25.jpg)
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)
![Page 26: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/26.jpg)
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.qmlOptionsBox {
model: firstOptions}OptionsBox {
model: otherOptions}
}
Item { //OptionsBox.qmlproperty alias model:
listView.model
ListView {focus: truedelegate: ...
}}
![Page 27: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/27.jpg)
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
![Page 28: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/28.jpg)
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.qmlOptionsBox {
model: firstOptionsfocus: true
}OptionsBox {
model: otherOptions}
}
FocusScope{ //OptionsBox.qmlproperty alias model:
listView.model
ListView {focus: truedelegate: ...
}}
![Page 29: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/29.jpg)
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
![Page 30: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/30.jpg)
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
![Page 31: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/31.jpg)
Key Specific HandlersRectangle {
color: “black”focus: true
Image {id: rocketx: 150, y:150source: “../images/rocket.svg”transformOrigin: Item.Center
}
Keys.onLeftPressed: rocket.rotation = (rocket.rotation - 10) %360Keys.onRightPressed: rocket.rotation = (rocket.rotation + 10) %360//Note there are only a few specific key handler available for use
}
![Page 32: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/32.jpg)
All Keys HandlerRectangle {
color: “black”focus: true
Image {id: rocketx: 150, y:150source: “../images/rocket.svg”transformOrigin: Item.Center
}
Keys.onPressed: {if(event.key == Qt.Key_Left)
rocket.rotation = (rocket.rotation - 10) %360else if (event.key == Qt.Key_Right)
rocket.rotation = (rocket.rotation + 10) %360 }
}
![Page 33: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/33.jpg)
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
![Page 34: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/34.jpg)
Event Propagation is ConvenientRectangle {
color: “black”focus: true
Keys.onVolumeDownPressed: cppMixer.decrementVolume()Keys.onVolumeUpPressed: cppMixer.incrementVolume()
Mp3Player {//Internally handles Key_MediaNext, Key_MediaPreviousvisible: falsefocus: visible
}
AmFmRadio {//Internally handles Key_MediaNext, Key_MediaPreviousvisible: falsefocus: visible
}}
![Page 35: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/35.jpg)
Performance Tips
![Page 36: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/36.jpg)
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
![Page 37: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/37.jpg)
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
![Page 38: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/38.jpg)
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
![Page 39: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/39.jpg)
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
![Page 40: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/40.jpg)
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: viewproperty cellHeight: 50 // Bad. Move to inside delegate delegate:
Rectangle {
height: view.cellHeight}
} }
![Page 41: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/41.jpg)
Maximize Binding Optimizer• Avoid writing to other properties in a property
binding• This should be obvious.
property int other: 0value: { 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.
![Page 42: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/42.jpg)
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
![Page 43: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/43.jpg)
Cache results• In non-optimized bindings cache results
• Save lookup times.• Especially on objects not in “Component Scope”
![Page 44: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/44.jpg)
Don’t Over Update Propeties• Don’t a update property more than one in a
binding or signal handler
![Page 45: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/45.jpg)
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
![Page 46: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/46.jpg)
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
![Page 47: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/47.jpg)
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
![Page 48: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/48.jpg)
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()
![Page 49: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/49.jpg)
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
![Page 50: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/50.jpg)
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.
![Page 51: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/51.jpg)
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
![Page 52: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/52.jpg)
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
![Page 53: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/53.jpg)
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
![Page 54: Best Practices in Qt Quick/QML - Part IV](https://reader036.fdocuments.in/reader036/viewer/2022082217/55cff2b9bb61eb43328b4789/html5/thumbnails/54.jpg)
Thank You!
Justin NoelSenior Consulting Engineer
ICS, Inc.