# QField Plugins workshop ### QGIS User Conference 2025 - Norrköping, Sweden
--- ### Who we are  --v-- ### Who you are  --v-- ### AGENDA 1. Why plugins for QField? 2. Types of QField plugins 3. Intro to QML 4. Developing QField plugins 5. Implementing the Weather Forecast plugin! 6. Plugin showcase 7. Resources --- ### Why plugins for QField? + Address clients specific needs + Keeping the UX simple + QField is *your* tool --- ### Types of QField Plugins PROJECT PLUGINS | APPLICATION PLUGINS ----------------|-------------------- Shared alongside QField project | Shared via URL (ZIP file) Single plugin | Multiple plugins Installation not required | Required installation Lasts project session | Lasts QField session --- ## Intro to QML --v-- ### Why QML +
Q
t
M
odeling
L
anguage, declarative, design-oriented + Elements (aka types) + Attributes: Properties, Signals, Handlers and Methods --v-- ### \.\./Elements (aka value types) ```Item, Rectangle, Text, TextInput, MouseArea, Dialog, ...``` ---- ``` qml Text { [...] } ``` --v-- ### \.\./Elements (aka value types) ```Item, Rectangle, Text, TextInput, MouseArea, Dialog, ...``` ---- ``` qml Rectangle { [...] Text { [...] } } ``` --v-- ### \.\./Elements (aka value types) ```Item, Rectangle, Text, TextInput, MouseArea, Dialog, ...``` ---- ``` qml Item { [...] Text { [...] } } ``` --v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { ... MouseArea { id: myArea ... } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: "green" MouseArea { anchors.fill: parent } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: "green" MouseArea { anchors.fill: parent onClicked: ... } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: "green" MouseArea { anchors.fill: parent onClicked: parent.color = "red" } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: "green" MouseArea { anchors.fill: parent onClicked: { parent.color = "red" } } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: "green" MouseArea { anchors.fill: parent onClicked: myCustomMethod() function myCustomMethod() { parent.color = "red" } } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: theColor property var theColor: "green" MouseArea { anchors.fill: parent onClicked: { parent.theColor = "red" } } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: theColor property var theColor: "green" MouseArea { anchors.fill: parent onClicked: { if (theColor == "green") { theColor = "red" } else { theColor = "green" } } } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: isGreen ? "red" : "green" property bool isGreen: true MouseArea { anchors.fill: parent onClicked: { isGreen = !isGreen } } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: "green" MouseArea { anchors.fill: parent onClicked: { parent.color = "red" } } } ```
--v-- ### \.\./Attributes ```Properties, Signals, Handlers and Methods``` ----
``` qml Rectangle { color: "green" signal colorChanged(info: string) MouseArea { anchors.fill: parent onClicked: { parent.color = "red" parent.colorChanged("by in the mouse area") } } onColorChanged: { console.log("Color changed to:", parent.color, " info:", info) } } ```
--v-- ## Resources - QML Docu https://doc.qt.io/qt-6/qtquick-index.html - QML Reference: https://doc.qt.io/qt-6/qmlreference.html - QML Tutorial: https://doc.qt.io/qt-6/qml-tutorial.html - Introduction to Qt/QML, by KDAB: [YouTube Playlist](https://www.youtube.com/watch?v=JxyTkXLbcV4&list=PL6CJYn40gN6hdNC1IGQZfVI707dh9DPRc&index=2) --v-- ## Hello world (QML) --v-- ### \.\./Check it out ``` qml import QtQuick 2.0 Text { text: "Hello world!" } ``` or here https://qmlweb.github.io --v-- ### \.\./Exercise online - Go to: https://qmlweb.github.io - Modify it to change the **text color** on clicking on it. - ... and *optionally* to change the color back with another click --v-- ## Break ☕ --- ## Developing QField plugins --- ### \.\./QField GUI
Dashboard
| Main menu | Search bar | Plugins toolbar | Positioning | Canvas actions
 --v-- ### \.\./QField GUI
Dashboard |
Main menu
| Search bar | Plugins toolbar | Positioning | Canvas actions
 --v-- ### \.\./QField GUI
Dashboard | Main menu |
Search bar
| Plugins toolbar | Positioning | Canvas actions
 --v-- ### \.\./QField GUI
Dashboard | Main menu | Search bar |
Plugins toolbar
| Positioning | Canvas actions
 --v-- ### \.\./QField GUI
Dashboard | Main menu | Search bar | Plugins toolbar |
Positioning
| Canvas actions
 --v-- ### \.\./QField GUI
Dashboard | Main menu | Search bar | Plugins toolbar | Positioning |
Canvas actions
 --v-- ### \.\./QField API ####
Root objects
| iface | Theme | QField GUI types | QGIS | Utils
-------- ``` iface qgisProject settings clipboardManager ... ``` --------
_See [qgismobileapp.cpp](https://github.com/opengisch/QField/blob/master/src/core/qgismobileapp.cpp#L574-L591) for details._
--v-- ### \.\./QField API ####
Root objects |
iface
| Theme | QField GUI types | QGIS | Utils
-------- ``` iface.mainWindow() iface.mapCanvas() iface.findItemByObjectName("...") iface.logMessage("...") iface.addItemToPluginsToolbar() iface.addItemToMainMenuActionsToolbar() iface.addItemToCanvasActionsToolbar() ``` --------
_See [appinterface.h](https://github.com/opengisch/QField/blob/master/src/core/appinterface.h) for details._
--v-- ### \.\./QField API ####
Root objects | iface |
Theme
| QField GUI types | QGIS | Utils
-------- ``` qml Theme.mainColor // #80cc28 Theme.mainTextColor Theme.mainBackgroundColor Theme.darkGray Theme.defaultFont Theme.getThemeVectorIcon("...") ``` --------
_See [Theme.qml](https://github.com/opengisch/QField/blob/master/src/qml/imports/Theme/Theme.qml) for details._
--v-- ### \.\./QField API ####
Root objects | iface | Theme |
QField GUI types
| QGIS | Utils
-------- ``` QfButton QfToolButton QfTextField QfSwitch QfComboBox ... ``` --------
_See [src/qml/imports/Theme/*](https://github.com/opengisch/QField/blob/master/src/qml/imports/Theme/Theme.qml) for details._
--v-- ### \.\./QField API ####
Root objects | iface | Theme | QField GUI types |
QGIS
| QGIS | Utils
-------- ``` QgsFeature QgsGeometry QgsAttributes QgsPointXY QgsField ... ``` --------
_See [qgismobileapp.cpp::initDeclarative](https://github.com/opengisch/QField/blob/master/src/core/qgismobileapp.cpp#L381-L407) for details._
--v-- ### \.\./QField API ####
Root objects | iface | Theme | QField GUI types |
Utils
-------- ``` LayerUtils GeometryUtils FeatureUtils CoordinateReferenceSystemUtils SnappingUtils ... ``` --------
_See [src/core/utils/*](https://github.com/opengisch/QField/tree/master/src/core/utils) for details._
--v-- ### \.\./Plugin Location #### Application Plugins - Install Plugins via *QField Settings > Manage Plugins*  --v-- ### \.\./Plugin Location #### Application Plugins - Find location in "About QField"  - Folder structure  --v-- ### \.\./Plugin Location #### Project Plugins - Copy to project folder - Name the main-file like the project qgz  --v-- ### \.\./Install "First Demo" - Get the link on the Schedule... - Install "First Demo" via *QField Settings > Manage Plugins*  --v-- ### \.\./Install "First Demo" Check out the `main.qml` in the plugin directory. ``` qml import QtQuick Item { Component.onCompleted: { iface.mainWindow().displayToast('First demo!') } } ``` --v-- ### \.\./Debugging - Popup on application display ```mainWindow.displayToast("")``` - Log message in the log panel ```iface.logMessage("")``` - Console output (not visible in QField) ```console.log("")``` --v-- ### \.\./Let's play #### All the world is green ```qml Rectangle{ id: myRectangle parent: iface.mapCanvas() anchors.fill: parent color: '#5000ff00' } ``` --v-- ### \.\./Let's play #### Template Plugin https://github.com/opengisch/qfield-template-plugin --v-- ## Break ☕ --- ### Weather Forecast plugin Let's create a forecast plugin! --v-- ### \.\./What we need + Button to fetch a weather forecast *(reuse the edited template plugin)* + Show an info dialog *(reuse the edited template plugin)* + Our location *(reuse the edited template plugin)* + API call + `XmlHttpRequest` to do an API call and fetch the forecast from open-meteo.com + Whatever we want --v-- ### \.\./What we do + Check out open-meteo.com + Get snippets at pad.opengis.ch (or the slides below) + We test the Java Script at https://runjs.app/play + We map the weather code to description and image + We integrate it into our template plugin --v-- ### \.\./API Request snippet The Java Script for using `XmlHttpRequest` ``` JavaScript //Norrköping lat = 58.5833; lon = 16.1833; let request = new XMLHttpRequest(); request.onreadystatechange = function() { if (request.readyState === XMLHttpRequest.DONE) { console.log(request.response) } } request.open("GET", "https://api.open-meteo.com/v1/forecast?latitude=" + lat + "&longitude=" + lon + "&daily=weather_code,temperature_2m_max&timezone=auto"); request.send(); ``` --v-- ### \.\./Code Mapping ```JSON { "0": { "description": "Sunny", "image": "http: //openweathermap.org/img/wn/01d@2x.png" }, "1": { "description": "Mainly Sunny", "image": "http://openweathermap.org/img/wn/01d@2x.png" }, [...] }; --- ### Plugin showcase
--v-- ### Plugin showcase Snap!  --v-- ### Plugin showcase Nominatim locator plugin  --v-- ### Plugin showcase LiveField plugin
--- ### Resources QML Docu https://doc.qt.io/qt-6/qtquick-index.html QML Reference: https://doc.qt.io/qt-6/qmlreference.html QML Tutorial: https://doc.qt.io/qt-6/qml-tutorial.html Introduction to Qt/QML, by KDAB ([YouTube Playlist](https://www.youtube.com/watch?v=JxyTkXLbcV4&list=PL6CJYn40gN6hdNC1IGQZfVI707dh9DPRc&index=2)) QML online editor: https://qmlweb.github.io QML advanced online editor: https://patrickelectric.work/qmlonline/ QField plugins: https://github.com/topics/qfield-plugin Plugin icons: https://fonts.google.com/icons JavaScript online editor: https://runjs.app/play ---  Thanks, and happy coding!