Demo 1: Hello World

Plugin Structure and Installation

Demo 1 Screenshot

What We Will Learn

Production Installation and Update

Development Installation and Update

>>> "C:\Program Files\QField\usr\bin\qfield.exe" C:\demopath\demo1_hello.qgs

Plugin Structure

demo1_hello/ | ├── demo1_hello.qml # Main QML file | ├── demo1_hello.qgs # QGIS project | └── components/ | ├── d1_plugin_component.qml # Main component / Dialog | ├── d1_plugin_theme.qml # Style definitions | └── qmldir # Global imports

Plugin Structure

Core QML Classes (Components)

QObject |___ QtObject | |___ Item (Base for Visual Types, like QtWidget) | | |___ Rectangle | | |___ Text | | |___ Image | | |___ MouseArea | | |___ Loader | | |___ Controls | | | |___ Button | | | |___ AbstractButton | | | | |___ QToolButton | | | | | |___ QfToolButton | |___ Component (Container/Utility Class. Not related to Item!) | |___ Connections | |___ Other non visual types and utilities

1. An Item is the Root Object of Our Plugin

Item { id: plugin parent: iface.mapCanvas() anchors.fill: parent Rectangle{...} ... }

Every QML Document has a single root Object.

2. Component Provides Lifecycle Hooks

Component.onCompleted and Component.onDestruction can be attached to any QML object

Item { id: plugin parent: iface.mapCanvas() anchors.fill: parent Loader {...} Component.onCompleted: { // Called AFTER Item is fully constructed iface.logMessage("Plugin loaded") } Component.onDestruction: { // Called BEFORE Item is destroyed iface.logMessage("Plugin unloaded") } }

Use Case: Register/deregister handlers, initialize data, clean up resources

3. Loader "Constructs" and "Destructs" the Root Object of the Source Component with the "active" Property

Item { Loader { id: pluginLoader active: false source: Qt.resolvedUrl( './components/d1_plugin_component.qml' ) } QfToolButton { onClicked: { pluginLoader.active = !pluginLoader.active } } }

Loader loads/unloads components dynamically

Component Also Defines Reusable Templates

Component can wrap Item definitions for reuse with Loader

// Explicit Component definition (we don't use this) Component { id: myTemplate Rectangle { text: "Reusable content" } } Loader { sourceComponent: myTemplate }
// Loading from file (what we use) // QML file = implicit Component Loader { source: "d1_plugin_component.qml" }

Why the confusion? QML developers call all reusable QML definitions "components," but Component is also a specific class. When loading from files, Components exist invisibly behind the scenes.

4. d1_plugin_component.qml Contains the Loaded Rectangle Component

Rectangle { id: pluginFrame anchors.fill: parent color: PluginTheme.vanilla Text { text: "Demo 1 Vegetation Monitoring: Plugin Component" color: PluginTheme.green font.pixelSize: 20 horizontalAlignment: Text.AlignHCenter anchors.centerIn: parent } ... }

PluginTheme.green comes from the style in qmldir and d1_plugin_theme.qml

qmldir and PluginTheme

Globally imported style definitions:

// qmldir singleton PluginTheme 1.0 d1_plugin_theme.qml
// d1_plugin_theme.qml QtObject { readonly property color vanilla: "#ffecd1" readonly property color green: "#6baa75" }

Exercises for the Next 20 Minutes

Tasks:

Demo2

1 / 14