Getting value from Python Toolbox ValueList Parameter

4081
8
Jump to solution
10-20-2017 12:03 PM
JohnDye
Occasional Contributor III

I was slapping together a toolbox tool today and came across an interesting issue.

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 MessageBox(self, Title, Message, ButtonStyle=0, MessageboxType="NOICON"):
        """
        Raises a system-modal messagebox with the given title and message
        with the specified ButtonStyle and MessageboxType. Used to raise
        messageboxes from a Python Toolbox tool operating on a Background Thread.

        INPUTS:
            Title (String)
                Title of the messagebox
            Message (String)
                Message to be displayed in the messagebox
            ButtonStyle (Integer)
                Value:                   Buttons Shown:
                0                        OK (Default)
                1                        OK | Cancel
                2                        Abort | Retry | Ignore
                3                        Yes | No | Cancel
                4                        Yes | No
                5                        Retry | No
                6                        Cancel | Try Again | Continue
            MessageboxType (String)
                Value:                   Description:
                NOICON                   No icon is displayed in the Messagebox
                INFO                     An Information Icon is displayed
                QUESTION                 A Question Mark Icon is displayed
                WARNING                  A Warning Icon is displayed
                ERROR                    An Error Icon is displayed

        OUTPUTS:
            Button Clicked (Integer)
                Value returned indicates the buttonpressed by the user

                Return Value             Button Pressed
                1                        OK
                2                        Cancel
                3                        Abort
                4                        Retry
                5                        Ignore
                6                        Yes
                7                        No
                10                       Try Again
                11                       Continue
        """
        if MessageboxType == "NOICON":
            MB_STYLE = 0x00
        elif MessageboxType == "INFO":
            MB_STYLE = 0x40
        elif MessageboxType == "QUESTION":
            MB_STYLE = 0x20
        elif MessageboxType == "WARNING":
            MB_STYLE = 0x30
        elif MessageboxType == "ERROR":
            MB_STYLE = 0x10
        else:
            raise Exception("Invalid 'MessageboxType' value")

        if ButtonStyle not in range(0, 7):
            raise Exception("Invalid 'ButtonStyle' value")

        import ctypes
        buttonPressed = ctypes.windll.user32.MessageBoxA(0
                                            , Message
                                            , Title
                                            , ButtonStyle | MB_STYLE | 0x40000)
        return buttonPressed

    def getParameterInfo(self):
        """Define parameter definitions"""
        param0 = arcpy.Parameter(
            displayName="Input Features",
            name="in_features",
            datatype="GPString",
            parameterType="Required",
            direction="Input")
        param0.filter.type="ValueList"
        param0.filter.list=["Butter", "Milk", "Bread"]

        params = [param0]
        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:
            self.MessageBox("Selected Parameter", parameters[0].valueAsText)
        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."""
        arcpy.AddMessage("Parameter 0: " + parameters[0].valueAsText)
        return
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

There's nothing crazy going on here. Only thing out of the ordinary is that MessageBox function.

Here's the weird thing. My updateParameters function has some logic to raise a Messagebox that displays the value selected by the user in param0. Works fine except that for some reason, the value is being sliced - I'm only getting the first letter of the selected parameter.

I also added an AddMessage function to the execute function to print the selected parameter to the Results Window. That actually gives me the full value, so perhaps it is my Messagebox function that is slicing it but I don't think so.

Anyone have any insight?

0 Kudos
1 Solution

Accepted Solutions
JonathanQuinn
Esri Notable Contributor

Looks like your problem is described here:

https://stackoverflow.com/a/14656832

Cast the Message to string and then it works fine:

import ctypes
buttonPressed = ctypes.windll.user32.MessageBoxA(0
                                    , str(Message)
                                    , Title
                                    , ButtonStyle | MB_STYLE | 0x40000)
return buttonPressed‍‍‍‍‍‍

View solution in original post

8 Replies
DanPatterson_Retired
MVP Emeritus

coincidental that parameters[0] just happens to correspond with B (utter)... and I presume that you dropped the [0] on a lark to see if it was the slice (might return an error)... To even go further try [0:] to see if the parameters is treating every letter as an entry  (still need a python toolbox I see )

0 Kudos
JohnDye
Occasional Contributor III

Tried that about an hour ago.

'list' object has no attribute 'valueAsText'

0 Kudos
DanPatterson_Retired
MVP Emeritus

getting close then so it needed a slice... did you try [0:]

sometimes it depends on how the list was created.

a = list('Banana')
a[0]
B'


a = [['Banana']]
a[0]
['Banana']
0 Kudos
JohnDye
Occasional Contributor III

Maybe I'm missing something but that doesn't explain why parameters[0].valueAsText would return just the first character. You can see how the list is being created. It's a static list. There's no reason I should have to slice it. 
Having to slice the list would make the purpose of the valueAsText property meaningless since I'd never be able to determine the currently selected value from the ValueList

0 Kudos
JonathanQuinn
Esri Notable Contributor

FWIW, if you add the parameter value to the title, it's returned correctly, so there's no problem grabbing the correct value:

...

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:
            #self.MessageBox("Selected Parameter", parameters[0].valueAsText)
               self.MessageBox("Selected {} Parameter".format(parameters[0].valueAsText), parameters[0].valueAsText)
        return

...‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

0 Kudos
JonathanQuinn
Esri Notable Contributor

Looks like your problem is described here:

https://stackoverflow.com/a/14656832

Cast the Message to string and then it works fine:

import ctypes
buttonPressed = ctypes.windll.user32.MessageBoxA(0
                                    , str(Message)
                                    , Title
                                    , ButtonStyle | MB_STYLE | 0x40000)
return buttonPressed‍‍‍‍‍‍
JohnDye
Occasional Contributor III

Thanks Johnathan!

0 Kudos
curtvprice
MVP Esteemed Contributor

This approach is really at cross-purposes with the ArcGIS geoprocessing architecture, which is a client-server model designed to enable the tool to be run the desktop, in the background, or as a geoprocessing service on a server. 

0 Kudos