best practices in qt quick/qml - part i

38
Qt Quick Best Practices Part I Justin Noel Senior Consulting Engineer ICS, Inc.

Upload: ics

Post on 28-Jul-2015

654 views

Category:

Technology


7 download

TRANSCRIPT

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

Qt Quick Best PracticesPart I

Justin Noel Senior Consulting EngineerICS, Inc.

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

Agenda

• Building Blocks of QML• Qt Properties• Declarative Code• Anchors

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

Building Blocks of QML

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

QObject

• Heart and Soul of Qt Object• Signals and Slots are implemented here• QObjects can have “child objects”

• Parents have some control over children• Deleting them, laying them out, etc

• Also Qt Properties!

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

Introspection

• QObjects can report at runtime• Class name, Super class• Lists of signals and list their arguments• Lists of functions and list their arguments• Invoke methods by name

• QMetaObject::invokeMethod(objPtr, “function”…)

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

Meta Object Compiler

• Introspection info is generated by moc• Reads header files. Writes source code

• moc -o moc_class.cpp class.h

• MetaObject is static • One instance per QObject subclass

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

QQuickItem

• Most Qt Objects inherit QObject• QQuickItem is no exception

• Gets many of it’s features directly from QObject

• We will be leveraging these capabilities throughout class

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

Deferred Deletion

• Qt is an event driven GUI toolkit• Deleting object can be tricky in an event based

system• Deleting objects from within an event• Deleting the sender object from a signal and slot

connection

• QObject has a deleteLater() method

Page 9: Best Practices in Qt Quick/QML - Part I

deleteLater()

• Posts an event to the event loop• On the next lap of the loop

• The object is deleted and all events cleared

• destroy() in QML is QObject::deleteLater()

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

QVariant

• Qt’s “Anything” class• Think: Typed void*• Supports most Qt data types out of the box

• Easy to add support for your own types• Automatically supports all pointer types

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

QVariant and QML

• QVariant maps to var in JavaScript• Used to pass data back and forth to C++• If you register your types correctly you can

attain runtime type safety

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

QVariant Containers

• QVariantList maps to Array in JavaScript• QList<QVariantMap> can be used with JSON

syntax JavaScript• Better off using QJson classes

• If you are using JSON data• Easier to convert back to JSON

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

Qt Properties

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

Qt Properties

• Combination of Get/Set/Notify• Allows introspection system to use these

functions as one concept• Properties have been in Qt for a very long time

• Qt Designer is based on properties• QML is also based on properties

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

Declaration of a Qt Property#include <QObject>

class Car : public QObject{ Q_OBJECT Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)

public: int getValue() const; void setValue(int newValue);

signals: void valueChanged(int value);};

Page 16: Best Practices in Qt Quick/QML - Part I

Qt Property with Enum#include <QObject>

class Car : public QObject{ Q_OBJECT Q_ENUMS(KeyState) Q_PROPERTY(KeyState keyState READ keyState NOTIFY keyStateChanged)public: enum KeyState { KeyOff, KeyOn, KeyStart }; [...]};

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

Getting and Setting Qt Properties

void someFunction(Qobject* obj){ // Getting QVariant propValue = obj->property(“value”); qDebug() << propValue.typeName() << propValue.toInt();

//Setting QVariant newValue = QVariant::fromValue(Car::KeyOn); obj->setProperty(“keyState”, newValue);}

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

Dynamic Propeties

• Properties are Key-Value Pairs• QObject can create properties on demand

• Less type safe, but perfectly useful for QML

obj->setProperty(“newPropName”, 1);obj->setProperty(“another”, “Value”);

int propInt = obj->property(“newPropName”).toInt();QString propString = obj->property(“another”).toString();

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

Declarative Code

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

Basic QML Syntax

• QML is declarative language• With hooks for procedural JavaScript

• Use as little JavaScript as possible

• QML files a read at runtime• The declarative parts create C++ instances• JavaScript is JIT interpreted

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

QtQuick Hello Worldimport QtQuick 2.2

Rectangle{ id: toplevel color: “blue” Text { text: “Hello World” }

MouseArea { anchors.fill: parent onClicked: Qt.quit() }}

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

Qt Quick Items

• Rectangle, Text and MouseArea• Are implemented in C++• Instances of QQuickRectangle, QQuickText, Etc• Loading QML is slower than compiled code

• At runtime performance is great

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

QML Bindings

• “:” is the binding operator• Right of the binding operator is JavaScript• Text {

text: “Hello World ” + Math.rand() }

• If the expression is simple• The full JavaScript interpreter may be skipped

• More on this later in the webinar series

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

Bindings are Declarative

• When any property used in a binding changes the expression is recalculated

Gauge { value: Math.min(gaugeMax, Math.max(gaugeMin, oilPressure.value)) }

• Value is updated whenever properties change• gaugeMax, gaugeMin or oilPressure.value

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

JavaScript is Procedural

• Avoid this!Gauge {

Component.onCompleted: { setGaugeValue(oilPressure.value) oilPressure.valueChanged.connect(setGaugeValue) }

onGaugeMinChanged: setGaugeValue(value) onGaugeMaxChanged: setGaugeValue(value)

function setGaugeValue(oilValue) { value = Math.min(gaugeMax, Math.max(gaugeMin, oilValue)) }}

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

Broken Bindings

• Assignment operator breaks bindings• Binding works for awhile. Then doesn’t.• Solution: Use States

• More in later in the webinar series Gauge { id: gauge visible: Dashboard.isOilPressureVisible }

Button { onClicked: { // Tries to temporarily hide gauge if(gauge.visible) gauge.visible = false

else gauge.visible = Dashboard.isOilPressureVisible } }

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

Anchors

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

Dead Reckoning LayoutItem { width: 800; height: 400; Rectangle { id:rectA color: 'red‘ height: 50 ; width: 70 x: 0; y: 0 }

Rectangle { id:rectB color: 'blue‘ height: rectA.height * 2; width: rectA.width * 2 x: 0; y: 100 }}

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

Why is dead reckoning bad?

• The good:• It resizes correctly• It uses bindings so it’s “declarative”

• The bad:• There are a lot of binding re-calculations

• Each recalculation is run in JavaScript

• Cascading bindings cause intermediate states

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

Binding Recalculation

• This example has ~40 items• If each item needs 2 bindings

• 80 Recalculations on resize• Not including intermediate states

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

Intermediate StatesExample 2.2. src/anchors/tst_bindings_1.qmlItem { property int c: a + b property int a property int b: a

onAChanged: console.log("a == " + a) onBChanged: console.log("b == " + b) onCChanged: console.log("c == " + c) Component.onCompleted: a = 1}

Output: a == 1 c == 1 b == 1 c == 2

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

Anchors Are Better!

• Anchors are stored and calculated in C++• Remember all Items are actually C++ instances• Anchors let you attach an item to other items

• Parent item• Any sibling item

• Anyone remember the Motif Form Widget?• Eerily similar. What’s old is new again!

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

Anchor Lines

• There are 6 anchors lines all Items have

• Text item has a 7th anchor called baseline• Bottom of text without descenders

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

Setting AnchorsRectangle { width: 800; height:600

Rectangle { id: rect1 width: 400 anchors.top: parent.top anchors.bottom: parent.bottom }

Rectangle { id: rect2 anchors { top: parent.top; bottom: parent.bottom left: rect1.right; right: parent.right } }}

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

Anchor Margins

• Each item has 6 adjustable margins

• Not shown are [horizontal|vertical]CenterOffset• Text has a baselineOffset margin• anchors.margins sets all outer margins at once

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

Complex Anchors

• Set multiple anchors at once• anchors.fill: anotherItem

• Sets left, right, top and bottom• Can use all outer margins

• anchors.centerIn: anotherItem• Sets horizontalCenter and verticalCenter• Can use horizontal and vertical offsets

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

Upcoming Webinars• Qt Quick Best Practices

• Part 2 July 9th 1:00 PM EST• Creating New Items

• States and Transitions

• Part 3 July 23 1:00 PM EST• C++ Integration

• Creating QML Modules

• Part 4 August 6th 1:00 PM EST• Dynamic Item Creation

• Keyboard Input Handling

• Performance Tips

Register Now: ics.com/webinars

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

Thank You!

Justin NoelSenior Consulting Engineer

ICS, Inc.