Upload
ics
View
1.243
Download
9
Embed Size (px)
Citation preview
© Integrated Computer Solutions, Inc. All Rights Reserved
Best Practices in QtQuick/QML Part 4Justin NoelSenior Consulting EngineerICS, Inc.
© Integrated Computer Solutions, Inc. All Rights Reserved
Agenda
• QML Data Models• View Delegates• Performance Tips
© Integrated Computer Solutions, Inc. All Rights Reserved
Data Models
© 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
© 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
© 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
© 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 Noel230 Second AveWaltham, MA(617 ) 621 - 0060
© Integrated Computer Solutions, Inc. All Rights Reserved
Model Types in QML
• QML ListModel Item• QML list<> property• JavaScript JSON• QQmlListProperty<Type>• QList<QObject*>• QAbstractItemModel*
© 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: contactModelListElement { name: “Justin Noel”; phoneNumber: “(617) 621-0060” }ListElement { name: “John Doe”; phoneNumber: “(555) 555-5555” }
}
© Integrated Computer Solutions, Inc. All Rights Reserved
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” }
}
© 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
© Integrated Computer Solutions, Inc. All Rights Reserved
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” }
]}
© Integrated Computer Solutions, Inc. All Rights Reserved
JSON ModelItem {property var json: [
{ name:”Justin Noel” phoneNumber:”(617) 621-0060” },{ name:” John Doe” phoneNumber “(555) 555-5555” }
]
ListView {model: jsondelegate: Rectangle {Column {Text { text: name }Text { text: phoneNumer }
}}
}
© Integrated Computer Solutions, Inc. All Rights Reserved
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;}
};
© Integrated Computer Solutions, Inc. All Rights Reserved
QList<QObject*> Modelimport MrCoffee 1.0
Rectangle {
CoffeeMaker {id: maker
}
ListView {anchors.fill: parentmodel: maker.alarms
}}
© Integrated Computer Solutions, Inc. All Rights Reserved
QQmlListPropertyclass BarChart : public QObject{Q_OBJECTQ_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;
};
© Integrated Computer Solutions, Inc. All Rights Reserved
QQmlListPropertyQQmlListProperty 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];
}
© Integrated Computer Solutions, Inc. All Rights Reserved
QQmlListPropertyvoid 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();
}
© Integrated Computer Solutions, Inc. All Rights Reserved
QQmlListPropertyimport BarChart 1.0
Rectangle {
BarChart {
Bar {color: “red”value: 50
}
Bar {color: “blue”value: 10
}}
}
© 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
© 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
© Integrated Computer Solutions, Inc. All Rights Reserved
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;
};
© Integrated Computer Solutions, Inc. All Rights Reserved
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;
}
© Integrated Computer Solutions, Inc. All Rights Reserved
Alarm Model Implementationint 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();
}
© Integrated Computer Solutions, Inc. All Rights Reserved
Alarm Model Implementationvoid AlarmModel::handleAlarmAppened(){beginInsertRows(QModelIndex(), rowCount(), rowCount());endInsertRows();
}
void AlarmModel::handleAlarmRemoved(int alarm){beginRemoveRows(QModelIndex(), alarm, alarm);endRemoveRows();
}
© 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>
© Integrated Computer Solutions, Inc. All Rights Reserved
Delegates
© 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
© 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: jsondelegate: Rectangle {color: ListView.view.isCurrentItem ? “blue” : “white” Column {Image { source: icon }Text { text: name }
}MouseArea { onClicked: doSomething(index)}
}}
© Integrated Computer Solutions, Inc. All Rights Reserved
New Delegate Item• Create a new item for your Delegate
ContactRow.qml------------------------------------------------------Rectangle {id: contactRowproperty alias icon: icon.sourceproperty alias text: name.textproperty bool isSelected: falsesignal clicked()
color: isSelected ? “blue” : “white”
Column {Image { id: icon }Text { id: text }
}MouseArea { onClicked: contactRow.clicked()
}}
© Integrated Computer Solutions, Inc. All Rights Reserved
Delegate AbstractionItem {
property var json: [{ name:”Justin Noel” icon:”jn.png” },{ name:” John Doe” icon: “jd.png” }
]
ListView {model: jsondelegate: ContactRow {isSelected: ListView.view.isCurrentItemtext: modelData.nameicon: modelData.icononClicked: doSomething(index)
}}
© Integrated Computer Solutions, Inc. All Rights Reserved
Performance Tips
© 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
© 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
© 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
© 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
© 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()
© 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
© 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.
© 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
© 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
© 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
© Integrated Computer Solutions, Inc. All Rights Reserved
Thank You!
Justin NoelSenior Consulting EngineerICS, Inc.