PyQGIS – Using QgsProcessingParameters Checkable Combo Box Option in PyQGIS

pyqgisqgis-processing

Is there a simple method in the QgsProcessingParameters class for a checkable combo box option?

I cant seem to find the function described in the offical documentation or figured out any alternative. Ideally I would need something along the lines of

def initAlgorithm(self, config=None):

    self.addParameter(QgsProcessingParameterCheckableComboBox...

Best Answer

I think that the QgsProcessingParameterEnum will be sufficient to do what you are are asking.

Just pass a list of items to the options keyword argument and True to the allowMultiple argument to allow multiple selections. E.g.

def initAlgorithm(self, config=None):
    
    self.addParameter(QgsProcessingParameterEnum(
        self.OPTIONS,
        self.tr("Select options"),
        options=['Steep', 'Intermediate', 'Gentle'],
        allowMultiple=True))

To retrieve the user selected options, use the following methods:

self.parameterAsEnum(parameters, self.OPTIONS, context)

for a single option which returns an integer or

self.parameterAsEnums(parameters, self.OPTIONS, context)

for multiple selections which returns a list of integers.

You can then use these integers as indexes to retrieve items from any iterable object. In the simple example below, I simply retrieved the string items from the original options list.

from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessingAlgorithm, QgsProcessingParameterEnum)
                  
class ExAlgo(QgsProcessingAlgorithm):
    OPTIONS = 'OPTIONS'
    option_list = ['Option 1',
                    'Option 2',
                    'Option 3',
                    'Option 4',
                    'Option 5']
 
    def __init__(self):
        super().__init__()
 
    def name(self):
        return "exalgo"
     
    def tr(self, text):
        return QCoreApplication.translate("exalgo", text)
         
    def displayName(self):
        return self.tr("Example script")
 
    def group(self):
        return self.tr("Examples")
 
    def groupId(self):
        return "examples"
 
    def shortHelpString(self):
        return self.tr("Example script with an Enum Parameter")
 
    def helpUrl(self):
        return "https://qgis.org"
         
    def createInstance(self):
        return type(self)()
   
    def initAlgorithm(self, config=None):
        
        self.addParameter(QgsProcessingParameterEnum(
            self.OPTIONS,
            self.tr("Select options"),
            options=self.option_list,
            allowMultiple=True))

 
    def processAlgorithm(self, parameters, context, feedback):
        
        # retrieve your input file parameter
        user_options = self.parameterAsEnums(parameters, self.OPTIONS, context)
        selected_items = [self.option_list[i] for i in user_options]
        
        return {self.OPTIONS: selected_items}

The resulting algorithm interface looks like this (click the enter image description here button to select):

enter image description here

Select one or more items:

enter image description here

Algorithm log:

enter image description here

Another option could be to create a custom widget wrapper inside your processing script and use a QListWidget with checkable items. An example of this is shown below:

from processing.gui.wrappers import WidgetWrapper
from qgis.PyQt.QtWidgets import QListWidget, QListWidgetItem
from qgis.PyQt.QtCore import QCoreApplication, QVariant, Qt
from qgis.core import (QgsProcessingAlgorithm, QgsProcessingParameterString)
                  
class ExAlgo(QgsProcessingAlgorithm):
    OPTIONS = 'OPTIONS'
 
    def __init__(self):
        super().__init__()
 
    def name(self):
        return "exalgo"
     
    def tr(self, text):
        return QCoreApplication.translate("exalgo", text)
         
    def displayName(self):
        return self.tr("Example script")
 
    def group(self):
        return self.tr("Examples")
 
    def groupId(self):
        return "examples"
 
    def shortHelpString(self):
        return self.tr("Example script with a custom widget")
 
    def helpUrl(self):
        return "https://qgis.org"
         
    def createInstance(self):
        return type(self)()
   
    def initAlgorithm(self, config=None):
        
        param = QgsProcessingParameterString(self.OPTIONS, 'Select options')
        param.setMetadata({'widget_wrapper': {'class': CheckableListWidget}})
        self.addParameter(param)

 
    def processAlgorithm(self, parameters, context, feedback):
        
        user_options = self.parameterAsString(parameters, self.OPTIONS, context)
        option_list = user_options.split('-')
        return {self.OPTIONS: option_list}
        
class CheckableListWidget(WidgetWrapper):

    def createWidget(self):
        self.lw = QListWidget()
        list_items = ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5']
        for i in list_items:
            li = QListWidgetItem(i)
            li.setFlags(li.flags() | Qt.ItemIsUserCheckable)
            li.setCheckState(Qt.Unchecked)
            self.lw.addItem(li)

        return self.lw

    def value(self):
        checked_items = []
        for n in range(self.lw.count()):
            i = self.lw.item(n)
            if i.checkState() == Qt.Checked:
                checked_items.append(i)
        string_list = [i.text() for i in checked_items]
        full_str = '-'.join(string_list)
        return full_str

Resulting UI and algorithm log shown below:

enter image description here

enter image description here

References:

Processing script template for QGIS3

Adding a custom widget to a QGIS Processing script