Demo 2

Feature Selection

Demo 2 Screenshot

Interaction with the Map and Features

What We Will Learn

1. Layer Query via qgisProject Object

// imports qgisProject import org.qfield // get QgsVectorLayer by name let layer = qgisProject.mapLayersByName("plots")[0]

1. Feature Query via LayerUtils

//imports LayerUtils import org.qfield // build your expression just like in QGIS let expression = "plot_id = 'plot_123'" // create feature iterator from expression let it = LayerUtils.createFeatureIteratorFromExpression(layer, expression) if (it.hasNext()) { // Real QgsFeature const feature = it.next() it.close() } it.close();

Intercepting Map Interactions with pointHandler

// imports iface import org.qfield Item { // 1. Add the pointHandler to the plugin property var handler: iface.findItemByObjectName("pointHandler") Component.onCompleted: { // 2. register the point handler and define its callback handler.registerHandler("demo2_selection", (point, type, interactionType) => { if(point === "the right point"){ // block other handlers return true } else { // not using the point, pass event to other handlers return false } } }); // 3. Deregister the point handler on destruction (project close) Component.onDestruction: { handler.deregisterHandler("demo2_selection"); } }

Intercepting Map Interactions with pointHandler

Point Handler interactionType

var isMobile = Qt.platform.os === "ios" || Qt.platform.os === "android" var shouldHandle = (isMobile && interactionType === "doubleClicked") || (!isMobile && interactionType === "clicked")

Android not tested (but probably similar to iOS)

Point Handler Coordinates

let mapCanvas = iface.mapCanvas() handler.registerHandler("demo2_selection", (point, type, interactionType) => { // 20 pixel tolerance box let tl = mapCanvas.mapSettings.screenToCoordinate(Qt.point(point.x - 20, point.y - 20)) let br = mapCanvas.mapSettings.screenToCoordinate(Qt.point(point.x + 20, point.y + 20)) let topleft = tl.x + " " + tl.y let topright = br.x + " " + tl.y let bottomright = br.x + " " + br.y let bottomleft = tl.x + " " + br.y let wkt = "'POLYGON((" + topleft + ", " + topright + ", " + bottomright \ + ", " + bottomleft + ", " + topleft + "))'" let expression = "intersects(geom_from_wkt("+wkt+"), $geometry)" let it = LayerUtils.createFeatureIteratorFromExpression(layer, expression) }

Passing Data to Component

Loader { id: pluginLoader source: Qt.resolvedUrl('./components/d2_plugin_component.qml') } pluginLoader.item.plotId = feature.attribute("plot_id")

pluginLoader.item = Root element of the Component

Property Binding in Component

// d2_plugin_component.qml Rectangle { id: pluginFrame property string plotId: "" Text { id: messageBox text: "Plot loaded: " + pluginFrame.plotId // Automatically updated! } }

Note the difference from imperative assignment: Property binding makes UI updates automatic!

Custom Signals

Closing the plugin with a button:

// In Component: Define signal Rectangle { id: pluginFrame signal closed() Button { onClicked: { closed() } } } // In Plugin: Connect signal Item { id: plugin Loader{} Connections { target: pluginLoader.item function onClosed() { pluginLoader.active = false } } }

Too many different mechanisms for interactions? Yes, I think so too.

Exercises for the Next 20 Minutes

Tasks:

Demo 2a

1 / 13