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?
Solved! Go to Solution.
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
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 )
Tried that about an hour ago.
'list' object has no attribute 'valueAsText'
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']
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
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
...
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
Thanks Johnathan!
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.