自定义脚本工具行为
您可以为脚本工具对话框提供自定义行为,如启用和禁用参数、提供默认值和更新字符串关键字等。要为脚本工具添加自定义行为,请右键单击脚本工具,单击属性,然后单击验证选项卡。在“验证”面板上,您可以提供用于实现名为 ToolValidator 的 Python 类的 Python 代码。通过添加 Python 代码,您可以
- 根据其他参数中包含的值来启用或禁用参数。
- 更新参数过滤器。您可以使用字段过滤器来创建 LONG 和 DOUBLE 等有效字段类型的列表。借助字符串过滤器,您可以设置有效关键字的列表,如下所示。共有六种过滤器类型:值列表、范围、要素类、文件、字段和工作空间。
- 提供参数的默认值,如栅格的单元大小。
- 出现在该对话框上的自定义警告和错误消息。
- 将参数放置在不同的类别中。
- 更新在模型构建器中使用的输出数据集的描述。
ToolValidator 的工作原理
ToolValidator 类是 Python 代码块,地理处理使用此代码块来控制工具对话框和 Python 窗口随用户输入所发生的变化。ToolValidator 类还用于描述工具的输出数据,这对建模而言十分重要。系统工具(ESRI 提供的工具)总是能够对用户输入作出响应,然后按照上述说明对工具对话框进行修改。
直到 ArcGIS 9.3,脚本工具还不具备此功能。当时的工具对话框是静止的,并且脚本工具的输出不包含更新的描述,因此很难在 ModelBuilder 中使用脚本工具。ToolValidator 类能够提供系统工具的所有功能。
尽管 ToolValidator 类是使用 Python 代码实现的,但您仍可使用任一脚本语言来执行工具的实际作业。
ToolValidator 和验证
验证是指检查所有工具参数是否正确,并在发现错误参数时提供有用的消息。验证由以下两部分组成:
- 你可以通过向 ToolValidator 类添加代码来实现的部分。
- ArcGIS 自动为您实现的部分。此验证部分被称为内部验证(或基本验证),因为此部分是地理处理在 ArcGIS 内部实现的基本验证。
首先,了解一下内部验证的作用:
- 如果某个参数为必填项,则检查它是否为空(尚未输入任何内容);如果该参数为空,则将“需要值”消息传递到工具对话框(绿色点而非红色 X)。
- 检查用户输入的值是否为正确类型(例如,输入栅格而非要素类,或输入字母字符而非数字)。
- 检查过滤器成员资格。即,如果您具有包含 RED、ORANGE 和 YELLOW 等关键字的值列表过滤器,而输入为 BLUE,则您将收到一条错误消息,因为无法在值列表过滤器中找到 BLUE。
- 检查输入数据集是否存在。
- 生成输出数据集的默认目录路径。
- 根据特殊对象、方案中包含的一组规则更新输出数据的描述。
- 根据 overwriteOutput 环境设置检查输出数据集是否存在。如果数据集存在且 overwriteOutput 为假,将生成一条错误;否则,将生成一条警告。
- 如果参数属于“字段”数据类型,则检查该字段是否存在于关联表中。
- 检查并确保输出数据集与输入数据集不相同(除非输出是派生值,如添加字段)。
- 对于包含线性和面积单位数据类型的参数,通过在 ArcMap 中检查相应值来设置它们的默认值(如果在 ArcMap 中运行)。
- 如果输出是 coverage、格网或 INFO 表,则检查这些数据集的 13 位字符文件名。
内部验证不执行以下操作(但您可以通过 ToolValidator 类完成):
- 根据与其他参数的交互作用更新过滤器。例如,如果您的用户在第一个参数中输入了一个点要素类,则您将需要工具对话框在第三个参数中显示 RED、ORANGE 和 YELLOW。如果您的用户输入了面要素类,则您将需要在第三个参数中显示 BLUE、INDIGO 和 VIOLET。
- 启用/禁用参数。
- 计算默认值。
- 执行任何特定于工具的参数交互。
您向 ToolValidator 类中添加的代码按如下方式与以下内部验证协同工作:
- 您可以提供一组供内部验证在更新输出数据集的描述时使用的规则。这些规则包含在方案对象中。
- 您可以在内部验证开始之前更新过滤器。根据以上示例,如果输入了一个点要素类,则您将更新过滤器以包含 RED、ORANGE 和 YELLOW。内部验证会根据在过滤器中找到的值对用户输入的值进行验证。
如前文所述,您可以通过 ToolValidator 来计算默认值、启用和禁用参数以及自定义消息。此类操作不会影响内部验证的结果,只会影响工具对话框的外观。
使用 ToolValidator 类来自定义工具对话框。
ToolValidator 是包含以下三种方法的 Python 类:initializeParameters(self)、updateParameters(self) 和 updateMessages(self)。它还包含标准的 Python 类初始化方法 __init__(self)。要查看和编辑 ToolValidator 类,请右键单击脚本工具,单击属性,然后单击验证选项卡。下图显示了包含默认 ToolValidator 类代码的验证选项卡。单击编辑按钮对代码进行编辑;编辑过程结束后,单击确定或应用以应用编辑内容。
方法 |
描述 |
---|---|
__init__ |
初始化 ToolValidator 类。导入所需的任何库并初始化对象(用户执行)。 |
initializeParameters |
在工具对话框第一次打开或第一次在命令行中使用工具时调用。 |
updateParameters |
在用户每次在工具对话框或命令行更改参数时调用。从 updateParameters 返回后,地理处理将调用它的内部验证例程。 |
updateMessages |
在从内部验证例程返回后调用。您可以检查在内部验证过程中创建的消息并根据需要进行更改。 |
请不要在 ToolValidator 中调用其他地理处理工具或打开数据集,因为 ToolValidator 类是在用户每次在工具对话框上更改内容时执行的。请使用您的脚本中的地理处理工具,而不要使用 ToolValidator 中的地理处理工具。
您必须实现这三种方法:initializeParameters(self)、updateParameters(self) 和 updateMessages(self)。它们除了执行返回操作之外不必执行任何操作,但必须为 ToolValidator 提供这三种方法,这样 ToolValidator 才能成为有效的 Python 类。
以下是 ToolValidator 代码的一些示例。要了解所有方法和更多示例的完整说明,请参阅编写 ToolValidator 类。
启用或禁用参数
本例取自热点分析工具。
def updateParameters(self): # If the option to use a weights file is selected (the user chose # "Get Spatial Weights From File", enable the parameter for specifying # the file, otherwise disable it # if self.params[3].value == "Get Spatial Weights From File": self.params[8].enabled = 1 else: self.params[8].enabled = 0
编码注释:设置已启用等布尔型变量时,可以使用以下语法:
self.params[8].enabled = 1 self.params[8].enabled = bool(1) self.params[8].enabled = True # Note upper case: "True", not "true"
将任何非零数字或值都视为真。
设置默认值
本例也取自热点分析工具。
def updateParameters(self): # Set the default distance threshold to 1/100 of the larger of the width # or height of the extent of the input features. Do not set if there is no # input dataset yet, or the user has set a specific distance (Altered is true). # import string if self.params[0].value: if not self.params[6].altered: extent = string.split(arcpy.Describe(self.params[0].value).extent, " ") width = float(extent[2]) - float(extent[0]) height = float(extent[3]) - float(extent[1]) if width > height: self.params[6].value = width / 100 else: self.params[6].value = height / 100 return
更新过滤器
以下是动态更新包含关键字选择列表的值列表过滤器的一个示例。如果用户在第二个参数中输入“OLD_FORMAT”,则第三个参数将包含“POINT、LINE 和 POLYGON”。如果输入“NEW_FORMAT”,则第三个参数将包含其他三个选项。
class ToolValidator: def __init__(self): import arcpy self.params = arcpy.GetParameterInfo() def initializeParameters(self): return def updateParameters(self): # Provide default values for "file format type" and # "feature type in file" # if not self.params[1].altered: self.params[1].value = "OLD_FORMAT" if not self.params[2].altered: self.params[2].value = "POINT" # Update the value list filter of the "feature type in file" parameter # depending on the type of file (old vs. new format) input # if self.params[1].value == "OLD_FORMAT": self.params[2].filter.list = ["POINT", "LINE", "POLYGON"] elif self.params[1].value == "NEW_FORMAT": self.params[2].filter.list = ["POINT", "LINE", "POLYGON", "POINT_WITH_ANNO", "LINE_WITH_ANNO", "POLYGON_WITH_ANNO"] return def updateMessages(self): return
以下是另一个示例,其中,第二个参数中的值列表过滤器会根据第一个参数中的形状类型“要素类”发生变化。
def updateParameters(self): # Update the value list filter in the second parameter based on the # shape type in the first parameter # stringFilter = self.params[1].filter fc = self.params[0].value if fc: shapetype = arcpy.Describe(fc).shapeType.lower() if shapetype == "point" or shapetype == "multipoint": stringFilter.list = ["RED", "GREEN", "BLUE"] elif shapetype == "polygon": stringFilter.list = ["WHITE", "GRAY", "BLACK"] else: stringFilter.list = ["ORANGE", "INDIGO", "VIOLET"] else: stringFilter.list = ["RED", "GREEN", "BLUE"] # If the user hasn't changed the keyword value, set it to the default value # (first value in the value list filter). # if not self.params[1].altered: self.params[1].value = stringFilter.list[0] return
自定义消息
def updateMessages(self): self.params[6].clearMessage() # Check to see if the threshold distance contains a value of zero and the user has # specified a fixed distance band. # if self.params[6].value <= 0: if self.params[3].value == "Fixed Distance Band": self.params[6].setErrorMessage("Zero or a negative distance is invalid \ when using a fixed distance band. Please \ use a positive value greater than zero." ) elif self.params[6].value < 0: self.params[6].setErrorMessage("A positive distance value is required \ when using a fixed distance band. \ Please specify a distance.") return
使用方案对象更新输出数据的描述
除了定义工具对话框的行为之外,还可以使用 ToolValidator 为模型构建器更新输出数据变量的描述。您可以简单地将模型构建器中的数据变量想像成数据集的简要描述,如下图所示。数据变量包含您使用 Python 中的描述功能访问到的每个属性。
要在模型构建器中使用,所有工具都应当更新它们的输出数据描述。通过更新描述,模型构建器中的后续进程可以在任何进程运行之前了解到要对数据进行的待决更改。以下两个示例显示了后续进程如何了解待决更改。
如下所示的第一个示例显示了一个包含添加字段工具和计算字段工具的模型。在添加字段中,输出数据变量 Parks (2) 被更新为包含新字段 TrackingID。由于输出被更新,因此计算字段对话框会在字段名称的列表中显示 TrackingID。
第二个示例是(未加图示)裁剪工具的输出被用作面转栅格工具的输入模型。由于裁剪工具只是使用“模具”方法来创建输入要素,因此,除了一个明显的特例“地理范围”之外,输出要素类具有的属性与输入要素类具有的属性完全相同。输出要素类的地理范围是输入要素范围和裁剪要素范围的几何交点。面转栅格工具使用新的地理范围来确定默认像元大小。
在 ToolValidator 类中,您可以使用方案对象为构建输出的描述设置规则。例如,您可以按如下方式设置规则:
- 创建输入数据集描述的副本,然后将新字段添加到字段的列表(如添加字段),或者添加固定字段的列表(如添加 XY 坐标)。
- 将输出字段的列表设置为数据集集合中的所有字段,或者,添加字段以包含数据集集合(例如 联合和相交)中的要素 ID。
- 将范围设置为另一个参数中的数据集的范围,或者设置为参数列表中数据集的联合或相交(如裁剪)。
- 设置特定的几何类型(点、线、面),或其设置为其他参数中的数据集的几何类型,或设置为参数列表中的最小类型或最大类型。最小和最大几何类型的定义为:点 = 0,折线 = 1,面 = 2。因此,集合 {点, 折线, 面} 中的最小几何是点,最大几何是面。
输出参数具有方案
方案对象是由地理处理为您创建的。每个类型为要素类、表、栅格或工作空间的输出参数都具有方案对象。仅要素类、表、栅格和工作空间输出数据类型具有方案,其他数据类型不具有方案。您可以通过参数对象访问此方案或为描述输出设置规则。从 updateParameters 返回时,内部验证例程会检查您设置的规则并更新输出的描述。
设置依从关系
无论何时创建规则(如“复制参数 3 中的数据集的字段,然后添加字段”),您都必须告知方案对象要从哪个参数进行复制(参数 3)。通过向参数对象添加依从关系可以完成操作。可添加多个依从关系。
def initializeParameters(self): # Set the dependencies for the output and its schema properties # self.params[2].parameterDependencies = [0, 1]
ParameterDependencies 采用 Python 列表。
如果您未曾使用过列表或列表的列表,则开始可能会将它们混淆,但您将很快熟悉它们并发现它们对各种事物都很有用。以下是一些用于说明列表和列表的列表的 Python 代码。这些示例在交互式模式(Python 窗口、PythonWin 中的交互窗口或 IDLE 中的 Python Shell)下显示,您可以从中输入代码并获取即时结果。
示例 1:在 Python 中,任何用方括号括起的变量或文本都将成为列表。打印列表时,将始终添加方括号。
>>> a = [1] >>> print a [1] >>> b = 2 >>> c = [b] >>> print c [2]
示例 2:一个列表可以包含任意数目的任何类型的元素。要访问列表中的某个元素,需使用包含该元素索引的括号。列表中的第一个元素始终为 [0]。
>>> a = [1, "two", 12.6] >>> print a [1, 'two', 12.6] >>> print a[0] 1
示例 3:一个简单的列表的列表
>>> listOfLists = [ [1,2,3], ["one", "two", "three"] ] >>> print listOfLists [[1, 2, 3], ['one', 'two', 'three']] >>> print listOfLists[0] [1, 2, 3] >>> print listOfLists[0][2] 3 >>> print listOfLists[1][2] three
示例 4:另一个列表的列表。请注意,成员列表不必具有相同的长度。
>>> listA = [1, 2, 3] >>> listB = ["a", "b", "C", "Z"] >>> listOfLists = [listA, listB] >>> print listOfLists [[1, 2, 3], ['a', 'b', 'C', 'Z']] >>> print listOfLists[1][3] Z
示例 5:创建一个空列表,然后添加并移除内容。
>>> a = [] >>> a.append("zero") >>> print a ['zero'] >>> b = [1, 2, 3] >>> a.append(b) >>> print a ['zero', [1, 2, 3]] >>> a.remove([1, 2, 3]) >>> print a ['zero']
有关 Python 列表(或有关 Python 的任何内容)的详细信息,请访问 http://docs.python.org/。
以下示例显示了依从关系的设置和使用。
设置依从关系示例:裁剪和添加字段
通过取消该裁剪来创建输入要素定义的副本,然后将范围设置为输入要素和裁剪要素的交点。以下示例介绍了如何在 ToolValidator 中实现此规则。(因为裁剪是一个内置工具而非脚本,因此它不使用 Python ToolValidator 类。内置工具通过使用原理上与 ToolValidator 相同的内部例程来执行各自的验证操作。但是,如果系统功能确实使用了 Python ToolValidator 类,则它与该类将具有相同的外观。)
def initializeParameters(self): # Set the dependencies for the output and its schema properties # self.params[2].parameterDependencies = [0, 1] # Feature type, geometry type, and fields all come from the first # dependent (parameter 0), the input features # self.params[2].schema.featureTypeRule = "FirstDependency" self.params[2].schema.geometryTypeRule = "FirstDependency" self.params[2].schema.fieldsRule = "FirstDependency" # The extent of the output is the intersection of the input features and # the clip features (parameter 1) # self.params[2].schema.extentRule = "Intersection" return def updateParameter(self): return
添加字段可复制输入参数的定义并添加用户指定的字段。以下链接介绍了如何在 ToolValidator 中实现添加字段。
在 initializeParameters 与 updateParameters 中设置方案
请注意,上述裁剪示例对 initializeParameters 中的方案对象进行了修改,但 updateParameters 只进行返回操作。另一方面,添加字段必须对 updateParameters 中的方案对象进行修改,因为它在用户提供信息(以及调用 updateParameters)之前不具有要添加的字段定义。
您可以将上述两种情况视为静态与动态。裁剪只依赖在依存参数中找到的数据集(静态行为),但添加字段需要检查字段名称和字段类型等其他非依存参数(动态行为)。
此静态和动态行为在调用 ToolValidator 类的方式上较为明显,例如:
- 当工具对话框首次打开时,会调用 initializeParameters。您为描述输出设置静态规则。此时不会创建任何输出描述,因为用户尚未指定任何参数的值。
- 无论用户以何种方式与工具对话框进行交互,都会调用 updateParameters。
- 考虑到无法根据参数依存关系确定的动态行为(如使用添加字段类添加新字段),updateParameters可以对方案进行修改。
- 从 updateParameters 获得返回值以后,会调用内部验证例程并通过应用方案对象中的规则来更新输出数据的描述。
- 然后会调用 updateMessages。您可检查内部验证可能已创建的警告消息和错误消息,然后修改它们或者添加警告和错误。
输出数据集名称:克隆派生输出与所需输出
将 Schema.Clone 属性设置为真时,您在指示地理处理为参数依存关系列表中的第一个依存参数中的描述创建精确副本(克隆)。通常,您会在 initializeParameters 中而非 updateParameters 中将“克隆”设置为真,因为它只需被设置一次。
如果输出参数的 ParameterType 被设置为“Derived”,则会创建精确副本。这是添加字段工具的行为。
如果 ParameterType 被设置为“Required”,仍会创建精确复本,但会更改数据集的目录路径。由于大多数工具都会创建新数据,因此这是最常见的行为。
了解更多信息
编写 ToolValidator 类提供了有关参数、方案和过滤器对象的详细信息并给出了代码示例。
基于脚本的所有系统工具(如多环缓冲区)都具有可供您检查和学习的 ToolValidator 代码。空间统计工具箱中的许多工具都是脚本工具并具有可供您检查的 ToolValidator 实现。
但是,您会在 ToolValidator 实现过程中出错(语法、运行时或逻辑错误)。调试 ToolValidator 类向您说明了地理处理如何捕捉和报告错误并为您提供用于调试的一些策略。