Viktigt
Översättning är en gemenskapsinsats du kan gå med i. Den här sidan är för närvarande översatt till 100.00%.
17. Skriva ett Processing-plugin
Beroende på vilken typ av plugin du ska utveckla kan det vara ett bättre alternativ att lägga till dess funktionalitet som en Processing-algoritm (eller en uppsättning av dem). Det skulle ge en bättre integration i QGIS, ytterligare funktionalitet (eftersom den kan köras i komponenterna i Processing, t.ex. modelleraren eller batchbehandlingsgränssnittet) och en snabbare utvecklingstid (eftersom Processing kommer att ta en stor del av arbetet).
För att distribuera dessa algoritmer bör du skapa ett nytt insticksprogram som lägger till dem i Processing Toolbox. Insticksprogrammet ska innehålla en algoritmleverantör som måste registreras när insticksprogrammet instansieras.
17.1. Skapa från grunden
Om du vill skapa ett plugin från början som innehåller en algoritmleverantör kan du följa dessa steg med hjälp av Plugin Builder:
Installera insticksprogrammet Plugin Builder
Skapa ett nytt plugin med hjälp av Plugin Builder. När Plugin Builder frågar dig om vilken mall du vill använda väljer du ”Processing provider”.
Det skapade insticksprogrammet innehåller en provider med en enda algoritm. Både providerfilen och algoritmfilen är fullständigt kommenterade och innehåller information om hur man ändrar providern och lägger till ytterligare algoritmer. Hänvisa till dem för mer information.
17.2. Uppdatering av ett plugin
Om du vill lägga till ditt befintliga plugin till Processing måste du lägga till lite kod.
I din fil
metadata.txt
behöver du lägga till en variabel:hasProcessingProvider=yes
I Python-filen där ditt plugin konfigureras med
initGui
-metoden måste du anpassa några rader så här:1from qgis.core import QgsApplication 2from .processing_provider.provider import Provider 3 4class YourPluginName: 5 6 def __init__(self): 7 self.provider = None 8 9 def initProcessing(self): 10 self.provider = Provider() 11 QgsApplication.processingRegistry().addProvider(self.provider) 12 13 def initGui(self): 14 self.initProcessing() 15 16 def unload(self): 17 QgsApplication.processingRegistry().removeProvider(self.provider)
Du kan skapa en mapp
processing_provider
med tre filer i den:__init__.py
med ingenting i den. Detta är nödvändigt för att skapa ett giltigt Python-paket.provider.py
som skapar Processing-providern och exponerar dina algoritmer.1from qgis.core import QgsProcessingProvider 2from qgis.PyQt.QtGui import QIcon 3 4from .example_processing_algorithm import ExampleProcessingAlgorithm 5 6class Provider(QgsProcessingProvider): 7 8 """ The provider of our plugin. """ 9 10 def loadAlgorithms(self): 11 """ Load each algorithm into the current provider. """ 12 self.addAlgorithm(ExampleProcessingAlgorithm()) 13 # add additional algorithms here 14 # self.addAlgorithm(MyOtherAlgorithm()) 15 16 def id(self) -> str: 17 """The ID of your plugin, used for identifying the provider. 18 19 This string should be a unique, short, character only string, 20 eg "qgis" or "gdal". This string should not be localised. 21 """ 22 return 'yourplugin' 23 24 def name(self) -> str: 25 """The human friendly name of your plugin in Processing. 26 27 This string should be as short as possible (e.g. "Lastools", not 28 "Lastools version 1.0.1 64-bit") and localised. 29 """ 30 return self.tr('Your plugin') 31 32 def icon(self) -> QIcon: 33 """Should return a QIcon which is used for your provider inside 34 the Processing toolbox. 35 """ 36 return QgsProcessingProvider.icon(self)
example_processing_algorithm.py
som innehåller exempelalgoritmfilen. Kopiera/klistra in innehållet i skriptmallfilen och uppdatera den efter dina behov.
Du bör ha ett träd som liknar detta:
1└── your_plugin_root_folder 2 ├── __init__.py 3 ├── LICENSE 4 ├── metadata.txt 5 └── processing_provider 6 ├── example_processing_algorithm.py 7 ├── __init__.py 8 └── provider.py
Nu kan du ladda om ditt plugin i QGIS och du bör se ditt exempelskript i verktygslådan Processing och modelleraren.
17.3. Implementering av anpassade bearbetningsalgoritmer
17.3.1. Skapa en anpassad algoritm
Här är ett enkelt exempel på en anpassad buffertalgoritm:
1from qgis.core import (
2 QgsProcessingAlgorithm,
3 QgsProcessingParameterFeatureSource,
4 QgsProcessingParameterNumber,
5 QgsProcessingParameterFeatureSink,
6 QgsFeatureSink,
7)
8
9class BufferAlgorithm(QgsProcessingAlgorithm):
10
11 INPUT = 'INPUT'
12 DISTANCE = 'DISTANCE'
13 OUTPUT = 'OUTPUT'
14
15 def initAlgorithm(self, config=None):
16 self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 'Input layer'))
17 self.addParameter(QgsProcessingParameterNumber(self.DISTANCE, 'Buffer distance', defaultValue=100.0))
18 self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, 'Output layer'))
19
20 def processAlgorithm(self, parameters, context, feedback):
21 source = self.parameterAsSource(parameters, self.INPUT, context)
22 distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
23 (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
24 source.fields(), source.wkbType(), source.sourceCrs())
25
26 for f in source.getFeatures():
27 f.setGeometry(f.geometry().buffer(distance, 5))
28 sink.addFeature(f, QgsFeatureSink.FastInsert)
29
30 return {self.OUTPUT: dest_id}
31
32 def name(self):
33 return 'buffer'
34
35 def displayName(self):
36 return 'Buffer Features'
37
38 def group(self):
39 return 'Examples'
40
41 def groupId(self):
42 return 'examples'
43
44 def createInstance(self):
45 return BufferAlgorithm()
17.3.2. Anpassning av algoritmdialogrutan
Anpassade dialogrutor är särskilt användbara när du arbetar med kapslade eller dynamiska indata, när parametrar beror på externa datakällor som API:er (t.ex. dynamiskt ifyllda rullgardinsmenyer) eller när du behöver avancerad validering och anpassat layoutbeteende som inte stöds av standarddialogrutan för bearbetning. För att åsidosätta standardgränssnittet (t.ex. för komplexa parametertyper eller dynamisk logik), underordna QgsProcessingAlgorithmDialogBase
. För att återge ditt anpassade användargränssnitt i standarddialogfönstret för bearbetning måste du anropa self.setMainWidget(panel)
, där panel
är en QgsPanelWidget
som innehåller din anpassade layout. Detta säkerställer att ditt gränssnitt visas korrekt och interagerar korrekt med Processing-ramverket.
Här är ett exempel som integrerar signalhantering med hjälp av QTimer för avbouncad ingång:
1from qgis.PyQt.QtCore import Qt, QT_VERSION_STR, QTimer
2from qgis.core import (
3 QgsProcessingAlgorithm,
4 QgsProcessingContext,
5 QgsProcessingFeedback,
6 Qgis,
7)
8from qgis.PyQt.QtWidgets import QWidget, QVBoxLayout, QLineEdit
9from qgis import gui, processing
10from datetime import datetime
11from typing import Dict, Optional
12from osgeo import gdal
13
14class CustomAlgorithmDialog(gui.QgsProcessingAlgorithmDialogBase):
15 def __init__(
16 self,
17 algorithm: QgsProcessingAlgorithm,
18 parent: Optional[QWidget] = None,
19 title: Optional[str] = None,
20 ):
21 super().__init__(
22 parent,
23 flags=Qt.WindowFlags(),
24 mode=gui.QgsProcessingAlgorithmDialogBase.DialogMode.Single,
25 )
26 self.context = QgsProcessingContext()
27 self.setAlgorithm(algorithm)
28 self.setModal(True)
29 self.setWindowTitle(title or algorithm.displayName())
30
31 self.panel = gui.QgsPanelWidget()
32 layout = self.buildDialog()
33 self.panel.setLayout(layout)
34 self.setMainWidget(self.panel)
35
36 self.cancelButton().clicked.connect(self.reject)
37
38 def buildDialog(self) -> QVBoxLayout:
39 layout = QVBoxLayout()
40
41 self.input = QLineEdit()
42
43 # Set up a debounced signal using QTimer
44 self._update_timer = QTimer(self, singleShot=True)
45 self._update_timer.timeout.connect(self._on_collection_id_ready)
46 self.input.textChanged.connect(self._on_collection_id_changed)
47
48 layout.addWidget(self.input)
49
50 return layout
51
52 def _on_collection_id_changed(self):
53 self._update_timer.start(500) # Debounce input
54
55 def _on_collection_id_ready(self):
56 self.pushInfo("Fetching metadata for collection ID…")
57
58 def getParameters(self) -> Dict:
59 try:
60 return {'DISTANCE': float(self.input.text())}
61 except ValueError:
62 raise ValueError("Invalid buffer distance")
63
64 def processingContext(self):
65 return self.context
66
67 def createFeedback(self):
68 return QgsProcessingFeedback()
69
70 def runAlgorithm(self):
71 context = self.processingContext()
72 feedback = self.createFeedback()
73 params = self.getParameters()
74
75 self.pushDebugInfo(f"QGIS version: {Qgis.QGIS_VERSION}")
76 self.pushDebugInfo(f"QGIS code revision: {Qgis.QGIS_DEV_VERSION}")
77 self.pushDebugInfo(f"Qt version: {QT_VERSION_STR}")
78 self.pushDebugInfo(f"GDAL version: {gdal.VersionInfo('--version')}")
79 self.pushCommandInfo(f"Algorithm started at: {datetime.now().isoformat(timespec='seconds')}")
80 self.pushCommandInfo(f"Algorithm '{self.algorithm().displayName()}' starting…")
81 self.pushCommandInfo("Input parameters:")
82 for k, v in params.items():
83 self.pushCommandInfo(f" {k}: {v}")
84
85 results = processing.run(self.algorithm(), params, context=context, feedback=feedback)
86 self.setResults(results)
87 self.showLog()
För att starta den anpassade dialogen för en viss algoritm instansierar du helt enkelt CustomAlgorithmDialog
med din algoritminstans och anropar exec()
:
dlg = CustomAlgorithmDialog(BufferAlgorithm())
dlg.exec()
17.3.3. Hantera Qt-signaler
När du bygger reaktiva dialogrutor ska du hantera signalanslutningar noggrant. I mönstret ovan används en QTimer för att fördröja inmatning från textfältet, vilket förhindrar snabba upprepade anrop. Detta är särskilt användbart när du hämtar metadata eller uppdaterar användargränssnittselement baserat på användarens inmatning. Anslut alltid signaler en gång (vanligtvis i __init__
) och använd `singleShot=True
för att säkerställa att sloten bara utlöses en gång efter en fördröjning.