4

I am creating a Python toolbox with 5 parameters. One of the parameters is a Boolean/checkbox, which checks if the user wants to edit the labels of a shapefile. What I would hope to do is if the user enables this checkbox, then change the parameter type of two of my other parameters to be required.

Is there a simple way to do this?

For the time being, my toolbox looks like the following:

enter image description here

If "Edit Labels?" is checked, I would like Label Font Size and Bold Font to be changed to be required inputs. I tried to do this within the updateParameters() method, but it seems like that is only used once the "OK" button is hit.


Here is the code that I have been working on:

import arcpy

class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name
        the.pyt file).
        """
        self.label = "CCDT Toolbox"
        self.alias = ""

        # List of tool classes associated with this toolbox
        self.tools = [applyMultipleLayerFeatures]

class applyMultipleLayerFeatures(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Apply Multiple Layer Features"
        self.description = "Applies features to multiple layers. Customize a single layer and use it as a source layer in the tool then select layers to be modified by the tool"
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""

        # First parameter = layer with customized features
        param0 = arcpy.Parameter(
            displayName = "Source layer with customized features",
            name = "source",
            datatype = "Feature Layer",
            parameterType = "Required",
            direction = "Input")

        # Second parameter = layers to which customized features will be applied
        param1 = arcpy.Parameter(
            displayName = "Layers with features to be updated",
            name = "updlayers",
            datatype = "GPValueTable",
            parameterType = "Required",
            direction = "Input")

        param2 = arcpy.Parameter(
            displayName = "Edit labels?",
            name = "enableLabels",
            datatype = "GPBoolean",
            parameterType = "Required",            
            direction = "Input")             

        param3 = arcpy.Parameter(
            displayName = "Label Font Size",
            name = "labelFontSize",
            datatype = "GPDouble",
            parameterType = "Required",            
            direction = "Input")

        param4 = arcpy.Parameter(
            displayName = "Bold Font:",
            name = "labelBoldFont",
            datatype = "GPBoolean",
            parameterType = "Required",            
            direction = "Input")            

        param1.columns = [['Feature Layer', 'Features']]       

        params = [param0, param1, param2, param3, param4]

        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        if parameters[2].value:
            parameters[3].parameterType = "Required"
            parameters[4].parameterType = "Required"
        else:
            parameters[3].parameterType = "Optional"
            parameters[4].parameterType = "Optional"
        return       

    def execute(self, parameters, messages):
        """The source code of the tool."""

        #Get Inputs

        for input in parameters:
            arcpy.AddMessage("This is part of the parameters list:" + input.name)

        updlayers = parameters[1].values
        enableLabels = parameters[2].value
        labelFontSize = parameters[3].value
        labelBoldFont = parameters[4].value       

        if enableLabels == True:        
            for layers in updlayers:
                for labels in layers:
                    labels.showLabels = True
                    if labelBoldFont == True:
                        for a in labels.labelClasses:
                            a.expression = '"%s" + [Name] + "%s"' %  ("<BOL><FNT name='Arial' size='" + str(labelFontSize) + "'>","</FNT></BOL>")
                    else:
                        for a in labels.labelClasses:
                            a.expression = '"%s" + [Name] + "%s"' %  ("<FNT name='Arial' size='" + str(labelFontSize) + "'>","</FNT>")

        source = parameters[0].valueAsText
        updlayers = parameters[1].valueAsText.split(";")

        for app in updlayers:
            arcpy.ApplySymbologyFromLayer_management(app.strip("'"),source)

        arcpy.RefreshTOC
        arcpy.RefreshActiveView
        return
2

updateParameters() is called whenever any parameter's value is changed. You should be able to use a function like the following:

def updateParameters(self, parameters):
    if parameters[2].value:
        parameters[3].parameterType = 'Required'
        parameters[4].parameterType = 'Required'
    else:
        parameters[3].parameterType = 'Optional'
        parameters[4].parameterType = 'Optional'
    return

EDIT: It turns out that parameterType is a read-only property. Given that, I'm not sure that what you're asking is actually possible. Perhaps it's best to initialize them with parameterType='Required', set default values for the parameters after initialization (e.g. param3.value=0 and param4.value=False), and then simply ignore them if the box is unchecked.

Another option would be to initialize the parameters as required, then enable/disable them based on the checkbox value. I haven't tested for myself whether an unspecified disabled required parameter will give you an error, but the code to try would be:

def updateParameters(self, parameters):
    if parameters[2].value:
        parameters[3].enabled = True
        parameters[4].enabled = True
    else:
        parameters[3].enabled = False
        parameters[4].enabled = False
    return
  • I tried doing something along those lines, but it didn't seem to work. I've included my code in the original question, maybe that will point out something that I am doing wrong. . . – coolDude Oct 8 '14 at 20:24
  • @coolDude see the edit to my answer for a possible alternative. – nmpeterson Oct 8 '14 at 21:06
  • 1
    That's actually exactly what I ended up trying on my own as well. Glad to hear that I was on the same page for this, thank you for your input! – coolDude Oct 8 '14 at 21:56
  • 1
    "...whether an unspecified disabled required parameter will give you an error..." Yes it does. – Cindy Jayakumar May 6 '15 at 13:30
7

I was trying to do the same thing and found that you can accomplish this indirectly by setting the following error message in the updateMessages(self) function of the ToolValidator class. It's not ideal, since "optional" will still appear next to the parameter label in the toolbox, but instead of putting the usual error icon of a red hexagon with a big X in it, the toolbox will put the green dot it uses for other required parameters:

def updateParameters(self, parameters):
        if parameters[2].value:
            if self.params[3].altered == 0:
                self.params[3].setErrorMessage("add explanation here")
            if self.params[4].altered == 0:
                self.params[4].setErrorMessage("add explanation here")

Alternatively, you can also use if not self.params[3].altered. If the user tries to hit OK without inputting these parameters, the tool will not execute and your error message text will appear in the error dialogue. This works with 10.2.2, not sure if the tool behavior would be the same in earlier versions of ArcGIS.

Edit: I forgot to mention that I disabled these parameters by default and only enabled them if the conditional parameter has a value. This helps avoid confusion by disabling the parameter unless you're requiring a value from the user. You can place self.params[3].enabled = 0 self.params[4].enabled = 0 in the initializeParameters function of the ToolValidator class, then place the following in the updateParameters function:

if self.params[2].value:
    self.params[3].enabled = 1
    self.params[4].enabled = 1
  • 2
    I'd suggest params[x].setIDMessage("ERROR", 735, params[x].displayName) which is the error message used when you attempt to execute a GP tool with a missing parameter which is required. – Paul Oct 27 '16 at 22:21
1

I am not sure if this is your problem, but in a typical ToolValidator the method signature for updateParameters is:

def updateParameters(self):

Since yours is different with the inclusion of the parameters argument, it might be confusing ToolValidator behind the scenes.

Try assigning parameters as a class member and then use self.parameters in the updateParameters method so the method signatures match, perhaps.

  • I don't quite follow what you're saying, would you be able to provide some sample code for your explanation? Also, what is a ToolValidator method? I am not familiar with this at all. . . – coolDude Oct 8 '14 at 20:57
  • Esri supplies parameters as a, well, parameter in their .pyt template – nmpeterson Oct 8 '14 at 21:01
  • 1
    Ah, I wasn't aware of that template. I was guessing based off individual python scripts, I haven't personally used the python toolboxes themselves. @coolDude I was referring to the ToolValidator class which works with individual python scripts. (Under the validation tab in a script's properties). It has similar functionality for an individual script as the python toolbox code does for multiple. – navigator_ Oct 8 '14 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.