best practices in qt quick/qml - part 4

43
© Integrated Computer Solutions, Inc. All Rights Reserved Best Practices in Qt Quick/QML Part 4 Justin Noel Senior Consulting Engineer ICS, Inc.

Upload: ics

Post on 24-Jan-2018

1.242 views

Category:

Software


9 download

TRANSCRIPT

Page 1: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

Best Practices in QtQuick/QML Part 4Justin NoelSenior Consulting EngineerICS, Inc.

Page 2: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

Agenda

• QML Data Models• View Delegates• Performance Tips

Page 3: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

Data Models

Page 4: Best Practices in Qt Quick/QML - Part 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

Page 5: Best Practices in Qt Quick/QML - Part 4

© 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

Page 6: Best Practices in Qt Quick/QML - Part 4

© 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

Page 7: Best Practices in Qt Quick/QML - Part 4

© 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

Page 8: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

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 4

© 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” }

}

Page 10: Best Practices in Qt Quick/QML - Part 4

© 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” }

}

Page 11: Best Practices in Qt Quick/QML - Part 4

© 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

Page 12: Best Practices in Qt Quick/QML - Part 4

© 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” }

]}

Page 13: Best Practices in Qt Quick/QML - Part 4

© 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 }

}}

}

Page 14: Best Practices in Qt Quick/QML - Part 4

© 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;}

};

Page 15: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

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 4

© 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;

};

Page 17: Best Practices in Qt Quick/QML - Part 4

© 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];

}

Page 18: Best Practices in Qt Quick/QML - Part 4

© 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();

}

Page 19: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

QQmlListPropertyimport BarChart 1.0

Rectangle {

BarChart {

Bar {color: “red”value: 50

}

Bar {color: “blue”value: 10

}}

}

Page 20: Best Practices in Qt Quick/QML - Part 4

© 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

Page 21: Best Practices in Qt Quick/QML - Part 4

© 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

Page 22: Best Practices in Qt Quick/QML - Part 4

© 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;

};

Page 23: Best Practices in Qt Quick/QML - Part 4

© 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;

}

Page 24: Best Practices in Qt Quick/QML - Part 4

© 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();

}

Page 25: Best Practices in Qt Quick/QML - Part 4

© 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();

}

Page 26: Best Practices in Qt Quick/QML - Part 4

© 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>

Page 27: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

Delegates

Page 28: Best Practices in Qt Quick/QML - Part 4

© 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

Page 29: Best Practices in Qt Quick/QML - Part 4

© 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)}

}}

Page 30: Best Practices in Qt Quick/QML - Part 4

© 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()

}}

Page 31: Best Practices in Qt Quick/QML - Part 4

© 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)

}}

Page 32: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

Performance Tips

Page 33: Best Practices in Qt Quick/QML - Part 4

© 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

Page 34: Best Practices in Qt Quick/QML - Part 4

© 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

Page 35: Best Practices in Qt Quick/QML - Part 4

© 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

Page 36: Best Practices in Qt Quick/QML - Part 4

© 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

Page 37: Best Practices in Qt Quick/QML - Part 4

© 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()

Page 38: Best Practices in Qt Quick/QML - Part 4

© 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

Page 39: Best Practices in Qt Quick/QML - Part 4

© 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.

Page 40: Best Practices in Qt Quick/QML - Part 4

© 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

Page 41: Best Practices in Qt Quick/QML - Part 4

© 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

Page 42: Best Practices in Qt Quick/QML - Part 4

© 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

Page 43: Best Practices in Qt Quick/QML - Part 4

© Integrated Computer Solutions, Inc. All Rights Reserved

Thank You!

Justin NoelSenior Consulting EngineerICS, Inc.