Demo 1: Hello World
Plugin-Struktur und Installation
Was wir lernen werden
- Wie man ein Projekt-Plugin bereitstellt und aktualisiert
- Die Struktur eines Projekt-Plugins
- Wichtigste QML Objekt Klassen
Produktive Installation und Update
- Liefern mit QField Sync
- Probleme? Projekt neu öffnen, QField neu starten
Entwicklung Installation und update
- Von DOS direkt in QField für Windows laden (lokal oder Cloud)
- Bei jedes update schliessen und neu starten.
>>> "C:\Program Files\QField\usr\bin\qfield.exe" C:\demopath\demo1_hello.qgs
Plugin-Struktur
demo1_hello/
|
├── demo1_hello.qml # Haupt-QML-Datei
|
├── demo1_hello.qgs # QGIS-Projekt
|
└── components/
|
├── d1_plugin_component.qml # Hauptkomponent / Dialog
|
├── d1_plugin_theme.qml # Stildefinitionen
|
└── qmldir # Global imports
Plugin-Struktur
- Haupt-QML denselben Namen wie das Projekt
- Alle andere Dateien im Attachment Verzeichnis "components"
Kern QML Klassen (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. Ein Item ist der Wurzel Object unseres Plugins
Item {
id: plugin
parent: iface.mapCanvas()
anchors.fill: parent
Rectangle{...}
...
}
- parent: Muss auf mapCanvas gesetzt werden
- anchors.fill: Füllt den gesamten Bildschirm
- id: Objektname für Referenzen
Jeder QML Dokument hat ein einzelne Wurzel-Objekt.
2. Component bietet Lifecycle-Hooks
Component.onCompleted und Component.onDestruction können an jedes QML-Objekt angehängt werden
Item {
id: plugin
parent: iface.mapCanvas()
anchors.fill: parent
Loader {...}
Component.onCompleted: {
// Wird NACH vollständiger Konstruktion aufgerufen
iface.logMessage("Plugin geladen")
}
Component.onDestruction: {
// Wird VOR Zerstörung aufgerufen
iface.logMessage("Plugin entladen")
}
}
Verwendung: Handler registrieren/deregistrieren, Daten initialisieren, Ressourcen aufräumen
3. Loader "constructs" und "destructs" der Wurzel Objekt des Source-Components mit den "active" Property
Item {
Loader {
id: pluginLoader
active: false
source: Qt.resolvedUrl(
'./components/d1_plugin_component.qml'
)
}
QfToolButton {
onClicked: {
pluginLoader.active = !pluginLoader.active
}
}
}
Loader lädt/entlädt Komponenten dynamisch
Component definiert auch wiederverwendbare Vorlagen
Component kann Item-Definitionen für die Wiederverwendung mit Loader umschließen
// Explizite Component-Definition (verwenden wir nicht)
Component {
id: myTemplate
Rectangle { text: "Wiederverwendbarer Inhalt" }
}
Loader { sourceComponent: myTemplate }
// Laden aus Datei (was wir verwenden)
// QML-Datei = implizite Component
Loader { source: "d1_plugin_component.qml" }
Warum die Verwirrung? QML-Entwickler nennen alle wiederverwendbaren QML-Definitionen "Components,"
aber Component ist auch eine spezifische Klasse. Beim Laden aus Dateien existieren Components unsichtbar im Hintergrund.
4. d1_plugin_component.qml enthaltet das geladene 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 kommt von der Stil in qmldir und d1_plugin_theme.qml
qmldir und PluginTheme
Global importierte Stildefinitionen:
// qmldir
singleton PluginTheme 1.0 d1_plugin_theme.qml
// d1_plugin_theme.qml
QtObject {
readonly property color vanilla: "#ffecd1"
readonly property color green: "#6baa75"
}
Übungen für die nächsten 20- 30 Minuten
Aufgaben:
- Übung 1: Demo1-Plugin bereitstellen und in QField öffnen
- Übung 2: Farbe des Titeltexts ändern (PluginTheme)
- Übung 3: Text im Rectangle ändern