Processing scripts do not allow parameter inputs to be changed by other parameter inputs. This can be overcome by defining a custom widget which does have the desired interactions, then using a 'widget_wrapper' to add the custom widget to the processing parameter inputs. The source for this can be found in the link: QGIS processing parameter using values from layer feature in processing plugin and How to chose a Vector layer, chose a field, then chose values using parameterAsEnums
def initAlgorithm(self, config=None):
file_param = QgsProcessingParameterMatrix(self.INPUT_PARAMS, 'Input Parameters')
file_param.setMetadata({'widget_wrapper': {'class': CustomParametersWidget}})
self.addParameter(file_param)
The perameters are prased by using 'parameterAsMatrix'
input_params_list = self.parameterAsMatrix(parameters, self.INPUT_PARAMS, context)
However I have not found any way to define the parameters the way they would normaly be defined in a processing algorithim, eg:
class MergeEMFandGPS(QgsProcessingAlgorithm):
INPUT_PARAMS = 'INPUT_PARAMS'
WORKDIR = 'WORKDIR'
FILEEMF = 'FILEEMF'
FILEGPS = 'FILEGPS'
OUTPUT = 'OUTPUT'
Then it is tied to the parameter in the initAlortihim then prased in the process processAlgorithm
def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorAnyGeometry]
)
)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(
parameters,
self.INPUT,
context
)
Is there away to tie the inputs from the parameterMatrix to the individual parameter constants? Is it necessary for other functionality?
The full code I am using is below:
from processing.gui.wrappers import WidgetWrapper # for custom widgets
from qgis.PyQt.QtWidgets import (QLabel,
QWidget,
QGridLayout)
from qgis.gui import QgsFileWidget
from qgis.PyQt.QtCore import (QCoreApplication,
QVariant,
Qt)
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterFile,
QgsProcessingParameterFileDestination,
QgsProcessingParameterDefinition,
QgsProcessingParameterMatrix)
from qgis import processing
import os
# Widget Wrapper class
class CustomParametersWidget(WidgetWrapper):
'''
Custom widgets so file inputs and outputs can be populated
using the selected woring direcetory
'''
def createWidget(self):
self.cpw = CustomFileSelectWidget()
return self.cpw
def value(self):
# This method gets the parameter values and returns them in a list...
# which will be retrieved and parsed in the processAlgorithm() method
self.Wdir = self.cpw.getWdir()
self.Femf = self.cpw.getFemf()
self.Fgps = self.cpw.getFgps()
self.Fgmf = self.cpw.getFgmf()
return [self.Wdir, self.Femf, self.Fgps, self.Fgmf]
# Custom Widget class
class CustomFileSelectWidget(QWidget):
def __init__(self):
super(CustomFileSelectWidget, self).__init__()
self.Wdir_lbl = QLabel('Select Working Directory', self)
self.Wdir_sel = QgsFileWidget(self)
self.Wdir_sel.setDialogTitle('Select Working Directory')
self.Wdir_sel.setStorageMode(QgsFileWidget.StorageMode.GetDirectory)
self.Femf_lbl = QLabel('Select EMF File', self)
self.Femf_sel = QgsFileWidget(self)
self.Femf_sel.setDialogTitle('Select EMF File')
self.Femf_sel.setStorageMode(QgsFileWidget.StorageMode.GetFile)
self.Femf_sel.setFilter('emfhistory*.csv')
self.Femf_sel.setFileWidgetButtonVisible(False)
self.Fgps_lbl = QLabel('Select GPS File', self)
self.Fgps_sel = QgsFileWidget(self)
self.Fgps_sel.setStorageMode(QgsFileWidget.StorageMode.GetFile)
self.Fgps_sel.setFilter('*.csv')
self.Fgps_sel.setFileWidgetButtonVisible(False)
self.Fgmf_lbl = QLabel('Select Output File', self)
self.Fgmf_sel = QgsFileWidget(self)
self.Fgmf_sel.setStorageMode(QgsFileWidget.StorageMode.GetFile)
self.Fgmf_sel.setFilter('*.csv')
self.Fgmf_sel.setFileWidgetButtonVisible(False)
# Define the layout
self.layout = QGridLayout(self)
self.layout.addWidget(self.Wdir_lbl, 0, 0, 1, 1, Qt.AlignRight)
self.layout.addWidget(self.Wdir_sel, 0, 1, 1, 2)
self.layout.addWidget(self.Femf_lbl, 1, 0, 1, 1, Qt.AlignRight)
self.layout.addWidget(self.Femf_sel, 1, 1, 1, 2)
self.layout.addWidget(self.Fgps_lbl, 2, 0, 1, 1, Qt.AlignRight)
self.layout.addWidget(self.Fgps_sel, 2, 1, 1, 2)
self.layout.addWidget(self.Fgmf_lbl, 3, 0, 1, 1, Qt.AlignRight)
self.layout.addWidget(self.Fgmf_sel, 3, 1, 1, 2)
# whenever the working directory is changed, repopulate the input files
self.Wdir_sel.fileChanged.connect(self.populateInputFiles)
# update the output files when the GPS or EMF file is changed.
self.Femf_sel.fileChanged.connect(self.updateOutputFile, Qt.QueuedConnection)
self.Fgps_sel.fileChanged.connect(self.updateOutputFile, Qt.QueuedConnection)
# populates the input and outut files from working directory
def populateInputFiles(self):
folderPath = self.Wdir_sel.filePath()
for file in os.listdir(folderPath):
if file.endswith(".csv"):
if 'emfhistory' in file:
self.Femf_sel.setFilePath(os.path.join(folderPath, file))
self.Femf_sel.setFileWidgetButtonVisible(True)
print("EMF :", file)
elif 'gmf' not in file:
print("GPS :", file)
self.Fgps_sel.setFilePath(os.path.join(folderPath, file))
self.Fgps_sel.setFileWidgetButtonVisible(True)
def updateOutputFile(self):
self.Fgmf_sel.setFileWidgetButtonVisible(True)
if self.Fgps_sel.filePath() == '':
print('Select GPS file')
if self.Femf_sel.filePath() == '':
print('Select EMF file')
if self.Fgps_sel.filePath() != '' and self.Femf_sel.filePath() != '':
folderPath = self.Wdir_sel.filePath()
fileNameStart = 'gmf_'+ os.path.basename(self.Fgps_sel.filePath())[:10] + '_'
fileNameEnd = os.path.basename(self.Femf_sel.filePath()).split('_')[3]
fileName = fileNameStart + fileNameEnd
self.Fgmf_sel.setFilePath(os.path.join(folderPath, fileName))
print ('update File Name : ', fileName)
def getWdir(self):
return self.Wdir_sel.filePath()
def getFemf(self):
return self.Femf_sel.filePath()
def getFgps(self):
return self.Fgps_sel.filePath()
def getFgmf(self):
return self.Fgmf_sel.filePath()
class MergeEMFandGPS(QgsProcessingAlgorithm):
"""
All Processing algorithms should extend the QgsProcessingAlgorithm
class.
"""
# Constants used to refer to parameters and outputs. They will be
# used when calling the algorithm from another algorithm, or when
# calling from the QGIS console.
INPUT = 'INPUT'
INPUT_PARAMS = 'INPUT_PARAMS'
WORKDIR = 'WORKDIR'
FILEEMF = 'FILEEMF'
FILEGPS = 'FILEGPS'
OUTPUT = 'OUTPUT'
def createInstance(self):
return MergeEMFandGPS()
def initAlgorithm(self, config=None):
"""
Here we define the inputs and output of the algorithm, along
with some other properties.
"""
file_param = QgsProcessingParameterMatrix(self.INPUT_PARAMS, 'Input Parameters')
file_param.setMetadata({'widget_wrapper': {'class': CustomParametersWidget}})
self.addParameter(file_param)
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
# Retrieve the list of parameters returned by the custom widget wrapper
input_params_list = self.parameterAsMatrix(parameters, self.INPUT_PARAMS, context)
WorkDIR = input_params_list[0]
FileEMF = input_params_list[1]
FileGPS = input_params_list[2]
FileOUT = input_params_list[3]
#do something with the FileEMF and FileGPS files and create a new file FileOUT
return {'OUTPUT': FileOUT}