我正在尝试实现动态模型更新器作为 pyRevit 扩展的一部分。但是,我无法从更新程序的
Execute
方法实例化类、调用函数或引用常量。
作为示例,我们假设制作一个执行此脚本的按钮:
from pyrevit import HOST_APP, DB
from System import Guid
from Autodesk.Revit.UI import TaskDialog
def do_thing(wall):
TaskDialog.Show('ExampleUpdater', 'Updating {}'.format(wall.Id.IntegerValue))
class ExampleUpdater(DB.IUpdater):
def __init__(self, addin_id):
self.id = DB.UpdaterId(addin_id, Guid("70f3be2d-b524-4798-8baf-5b249c2f31c4"))
def GetUpdaterId(self):
return self.id
def GetUpdaterName(self):
return "Example Updater"
def GetAdditionalInformation(self):
return "Just an example"
def GetChangePriority(self):
return DB.ChangePriority.Views
def Execute(self, data):
doc = data.GetDocument()
for id in data.GetModifiedElementIds():
wall = doc.GetElement(id)
try:
do_thing(wall)
except Exception as err:
wall.ParametersMap["Comments"].Set("{}: {}".format(err.__class__.__name__, err))
updater = ExampleUpdater(HOST_APP.addin_id)
if DB.UpdaterRegistry.IsUpdaterRegistered(updater.GetUpdaterId()):
DB.UpdaterRegistry.UnregisterUpdater(updater.GetUpdaterId())
DB.UpdaterRegistry.RegisterUpdater(updater)
wall_filter = DB.ElementCategoryFilter(DB.BuiltInCategory.OST_Walls)
change_type = DB.Element.GetChangeTypeAny()
DB.UpdaterRegistry.AddTrigger(updater.GetUpdaterId(), wall_filter, change_type)
如果我移动一面墙(当然是在单击按钮注册更新程序之后),则会引发异常并将其存储在墙的注释属性中:
NameError: name 'do_thing' is not defined
。当我尝试调用 TaskDialog.Show
等最初未在 Python 中定义的函数时,也会引发类似的异常。
但是,如果我在 RevitPythonShell 中注册相同的更新程序,它会按预期工作:
from System import Guid
from Autodesk.Revit.UI import TaskDialog
def do_thing(wall):
TaskDialog.Show('ExampleUpdater', 'Updating {}'.format(wall.Id.IntegerValue))
class ExampleUpdater(IUpdater):
def __init__(self, addin_id):
self.id = UpdaterId(addin_id, Guid("c197ee15-47a9-4cf7-b12c-43b863497826"))
def GetUpdaterId(self):
return self.id
def GetUpdaterName(self):
return "Example Updater"
def GetAdditionalInformation(self):
return "Just an example"
def GetChangePriority(self):
return ChangePriority.Views
def Execute(self, data):
doc = data.GetDocument()
for id in data.GetModifiedElementIds():
wall = doc.GetElement(id)
try:
do_thing(wall)
except Exception as err:
wall.ParametersMap["Comments"].Set("{}: {}".format(err.__class__.__name__, err))
updater = ExampleUpdater(__revit__.Application.ActiveAddInId)
if UpdaterRegistry.IsUpdaterRegistered(updater.GetUpdaterId()):
UpdaterRegistry.UnregisterUpdater(updater.GetUpdaterId())
UpdaterRegistry.RegisterUpdater(updater)
wall_filter = ElementCategoryFilter(BuiltInCategory.OST_Walls)
change_type = Element.GetChangeTypeAny()
UpdaterRegistry.AddTrigger(updater.GetUpdaterId(), wall_filter, change_type)
允许更新程序在 RevitPythonShell 中工作但不能在 pyRevit 中工作的两种环境有何区别?
Revit 2019、pyRevit 4.7.4、IronPython 2.7.7
根据 @Callum 的建议,我能够通过保存对更新程序的
__init__
方法中所需的导入资源的引用来解决该问题。我的示例更新程序现在看起来像这样:
from pyrevit import HOST_APP, DB
from System import Guid
from Autodesk.Revit.UI import TaskDialog
class ExampleUpdater(DB.IUpdater):
def __init__(self, addin_id):
self.id = DB.UpdaterId(addin_id, Guid("70f3be2d-b524-4798-8baf-5b249c2f31c4"))
self.TaskDialog = TaskDialog
def GetUpdaterId(self):
return self.id
def GetUpdaterName(self):
return "Example Updater"
def GetAdditionalInformation(self):
return "Just an example"
def GetChangePriority(self):
return DB.ChangePriority.Views
def Execute(self, data):
doc = data.GetDocument()
for id in data.GetModifiedElementIds():
wall = doc.GetElement(id)
try:
self.do_thing(wall)
except Exception as err:
wall.ParametersMap["Comments"].Set("{}: {}".format(err.__class__.__name__, err))
def do_thing(self, wall):
self.TaskDialog.Show('ExampleUpdater', 'Updating {}'.format(wall.Id.IntegerValue))
简单地使
do_thing
成为 ExampleUpdater
的方法是不够的,保存对 do_thing
函数的引用(即通过在 self.do_thing = do_thing
中添加 __init__
)也不起作用。在这两种情况下,更新者都会提出 NameError
表示 global name 'TaskDialog' is not defined
。
使用持久引擎制作捆绑包就达到了目的:
engine:
persistent: true