5

I would like to be able to create a Python toolbox tool (or a Python script tool) where a choice made from the first parameter (Category in the images below) changes the Display Name of other parameters (which initialize as Sub Category 1 and Sub Category 2 in the images below).

These images are mockups.

enter image description here

After opening the tool I choose Category B for Category.

enter image description here

I would like that choice to change the Display Names of:

  • Sub Category 1 to Sub Category B1 (choosing Category A would set Sub Category A1)
  • Sub Category 2 to Sub Category B2 (choosing Category A would set Sub Category A2)

Something like below (where I have mocked up the Display Name changes) but with the first parameter green rather than red.

enter image description here

I tried tool validation of a Python script tool first, but seemed to be blocked by the read-only Display Name there. I then moved to a Python Toolbox tool instead because that adds some extra functionality and I was hoping might remove the read-only Display Name limitation.

My attempt to code this as a Python Toolbox tool is below, but it seems not to be working because displayName is read-only there too.

Is there any ArcPy way to meet the requirement that I describe above?

import arcpy


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

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


class Tool(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Tool"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""
        # First parameter
        param0 = arcpy.Parameter(
            displayName="Category",
            name="category",
            datatype="String",
            parameterType="Required",
            direction="Input")
        param0.filter.list = ['Category A', 'Category B']

        # Second parameter
        param1 = arcpy.Parameter(
            displayName="Sub Category 1",
            name="subcategory_1",
            datatype="String",
            parameterType="Required",
            direction="Input")

        # Third parameter
        param2 = arcpy.Parameter(
            displayName="Sub Category 2",
            name="subcategory_2",
            datatype="String",
            parameterType="Required",
            direction="Input")

        params = [param0,param1,param2]
        return params

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

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        if parameters[0].value == "Category A":
            parameters[1].displayName = "Sub Category A1"
            parameters[2].displayName = "Sub Category A2"
        elif parameters[0].value == "Category B":
            parameters[1].displayName = "Sub Category B1"
            parameters[2].displayName = "Sub Category B2"
        return

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        return

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

I am using ArcGIS 10.2.2 for Desktop.

  • Is that script in the Validator of the tool? help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//… I know you can use that to set the choices on box B based on what's in box A but not sure if you can change the parameter labels... be nice if you could though, I can think of a couple of examples where that would come in really handy! – Michael Stimson Dec 17 '14 at 0:19
  • 1
    @MichaelMiles-Stimson That is not the right help section for this type of toolbox. Python toolboxes were added in 10.1, and this is the relevant help topic: resources.arcgis.com/en/help/main/10.2/index.html#//… – blah238 Dec 17 '14 at 0:24
  • @MichaelMiles-Stimson I tried tool validation of a Python script tool first, and hit the read-only Display Name there too. I've moved to a Python Toolbox tool because that adds some extra functionality and I was hoping might remove the read-only Display Name limitation. I'm starting to experiment with Value Tables (which are only available to Python Toolboxes) because I think that might be the next biggest stick to hit this requirement with. – PolyGeo Dec 17 '14 at 0:30
  • 1
    @MichaelMiles-Stimson C#/VB.net are out of scope for me - I plan to remain an ArcPy/Python only developer because it's the best thing since AML (and in most respects surpasses it). – PolyGeo Dec 17 '14 at 0:46
  • 1
    @MichaelMiles-Stimson If I exhaust ArcPy options then I think I am more likely to go to Tkinter or wxPython to gain the extra functionality than QT or PyWin. The comparatively easy writing for ArcPy carries a lot of weight when I choose how to develop so that any code I write stays easy to maintain. – PolyGeo Dec 17 '14 at 1:15
2

You know, anything is probably possible but that doesn't mean it is worth the effort. UpdateParameters is meant to update parameter values dynamically. Not parameter display names.

If I were trying to do this, I would create a Python Toolbox with two tools in it, ToolA for Category A and ToolB for Category B, each tool having the appropriate DisplayNames for its parameters.

To make the tool selection pretty simple for a user, I would then create a Python Add-in with two buttons (Category A and Category B). Then save the Python Toolbox into the Install Folder of your Python Add-in. When the user clicks the Category A button, launch ToolA from the Python Toolbox, when they click the Category B button on the Python Add-In, launch the ToolB from the Python Toolbox.

You can accomplish this using the pythonaddins.GPToolDialog function like so:

import os  
import arcpy  
import pythonaddins  
relPath = os.path.dirname(__file__)

class CAT_A(object):  
    """Implementation for Project_addin.CategoryA (Button)"""  
    def __init__(self):  
        self.enabled = True  
        self.checked = False  
    def onClick(self):  
        PythonTBX = relPath + r"\YourToolBox.pyt"  
        pythonaddins.GPToolDialog(PythonTBX, "ToolA")

class CAT_B(object):  
    """Implementation for Project_addin.CategoryB (Button)"""  
    def __init__(self):  
        self.enabled = True  
        self.checked = False  
    def onClick(self):  
        PythonTBX = relPath + r"\YourToolBox.pyt"  
        pythonaddins.GPToolDialog(PythonTBX, "ToolB")  

There's a couple of advantages to this approach.

  1. Stupid simple deployment of the Toolbox through a Python Add-in
  2. A user can then access the tools through a simple button on a toolbar rather than through a series of nested menus in a toolbox in their Catalog Window and doesn't have to create a Catalog Connection to the location where the toolbox is hosted on their system.
  3. An end user who wanted to alter the source code of the toolbox or tools is going to need to step up their game a little bit as they'll need to figure out that to get to the source code of the toolbox, they have to find the assembly cache where the addin is loaded. It's not obvious where this is located and the end user will not see this toolbox in their my toolboxes in catalog. The only way to access it will be through the Add-in unless they create a Catalog Connection to the assembly cache.
  4. You can restrict the Addin Manager to only install Trusted (Signed) Addins, then Sign the addin with your signing certificate. If anyone does manage to locate and modify the source code, the signature will become invalid and the Addin will uninstall automagically.
  • I'll need to test before I accept, so for now I have just upvoted. I have come up with another, simpler way to more or less meet my requirement, that I plan to post as an alternative answer. However, what you describe sounds like it should work and is a closer match to my requirements. – PolyGeo Jan 3 '15 at 9:11
  • I'm curious PolyGeo, what was the other way you discovered to meet this requirement? – MrBubbles Jan 24 '15 at 19:42
  • I must apologize for not getting back to this and accepting your answer sooner. The piece of work that I was doing my "proof of concept" for has not yet eventuated so I have only tested enough of your solution to be confident that it should work. I've just added my alternate solution as an answer even though I do not plan to use it. – PolyGeo Jan 24 '15 at 22:48
  • I ended up implementing this for a tool that has been used in production by my client for at least three years. – PolyGeo Mar 13 at 12:29
1

The way I came up with has the drawback that it places twice as many parameters on the tool dialog as the answer (which I prefer) by @MrBubbles but I will record it here any way.

The pictures below show its tool dialog in operation. The choice of the first parameter (e.g. Category A) triggers every second other parameter to be updated (via tool validation) to provide "headings". The values in the alternate fields are then modified to their appropriate defaults by the tool validation.

The tool validation is:

import arcpy
class ToolValidator(object):
  """Class for validating a tool's parameter values and controlling
  the behavior of the tool's dialog."""

  def __init__(self):
    """Setup arcpy and the list of tool parameters."""
    self.params = arcpy.GetParameterInfo()

  def initializeParameters(self):
    """Refine the properties of a tool's parameters.  This method is
    called when the tool is opened."""
    self.params[1].value = ""
    self.params[1].enabled = 0
    self.params[2].value = ""
    self.params[3].value = ""
    self.params[3].enabled = 0
    self.params[4].value = ""
    return

  def updateParameters(self):
    """Modify the values and properties of parameters before internal
    validation is performed.  This method is called whenever a parameter
    has been changed."""
    if self.params[0].value == "Category A":
        self.params[1].value = "Sub Category A1"
        self.params[2].value = "Average"
        self.params[2].enabled = 1
        self.params[3].value = "Sub Category A1"
        self.params[4].value = "Average"
        self.params[4].enabled = 1
    elif self.params[0].value == "Category B":
        self.params[1].value = "Sub Category B1"
        self.params[2].value = "Bad"
        self.params[2].enabled = 1
        self.params[3].value = "Sub Category B1"
        self.params[4].value = "Bad"
        self.params[4].enabled = 1
    return

  def updateMessages(self):
    """Modify the messages created by internal validation for each tool
    parameter.  This method is called after internal validation."""
    return

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

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.