revit-api - pyRevit WPF 非模态问题
问题描述
所以我刚刚开始在 pyRevit 中涉足 WPF。我尝试像这样实现 pyrevit.forms.WPFWindow 类:
# -*- coding: UTF-8 -*-
"""
Third-Party software credits:
pyRevit: repository at https://github.com/eirannejad/pyRevit
"""
import System, clr, json, sys
clr.AddReference("System.Windows.Forms")
clr.AddReference('IronPython.Wpf')
import wpf
from Autodesk.Revit.DB import *
from pyrevit import revit, script, forms
class FactorySettings(forms.WPFWindow):
def __init__(self):
forms.WPFWindow.__init__(self, script.get_bundle_file('settings.xaml'))
def something_click(self, A, B):
plantings = FilteredElementCollector(revit.doc) \
.WhereElementIsElementType() \
.OfCategory(BuiltInCategory.OST_Planting)
ui = FactorySettings()
ui.show()
这是我的 xaml:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
ShowInTaskbar="False" ResizeMode="CanResize"
WindowStartupLocation="CenterScreen"
HorizontalContentAlignment="Center"
Title="Set worksets" Width="300" SizeToContent="Height"
>
<StackPanel Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Button Content="Do something" Name="something" Click="something_click"/>
</StackPanel>
</Window>
def show(self, modal=False):
由于类功能,这将打开一个非模式窗口。对我来说,问题是即使我的点击功能只调用一个FilteredElementCollector
对象,Revit 也会崩溃。如果我这样做ui.show(modal=True)
,它会起作用,但是我无法在 Revit UI 中做任何事情。我真正想要的是这样做:
def something_click(self, A, B):
if self.PHfamSymbol != None:
with forms.WarningBar(title='Place an instance of the placeholder object.'):
revit.uidoc.PromptForFamilyInstancePlacement(self.PHfamSymbol)
这将不起作用,因为焦点仍然在 UI 上。我试过这个:
def something_click(self, A, B):
if self.PHfamSymbol != None:
self.Close()
with forms.WarningBar(title='Place an instance of the placeholder object.'):
try:
revit.uidoc.PromptForFamilyInstancePlacement(self.PHfamSymbol)
except:
pass
这可行,但我需要在完成后创建一个新的 UI 实例。是否有可能使用 pyRevit 提供非模态 UI?
解决方案
您需要使用ExternalEvent在非模态窗口中与 Revit 交互。您在pyRevitMEP中有许多示例。我在这里做了一个可重用的类。我在Element3DRotation等许多 pyRevitMEP 脚本中使用它。您也可以查看我的旧博客[Revit API] Simple Modeless Form (External Event Handler) in pyRevit post,其中引用了更多资源并有更多评论。
样本
脚本
"""
Copyright (c) 2017 Cyril Waechter
Python scripts for Autodesk Revit
This file is part of pypevitmep repository at https://github.com/CyrilWaechter/pypevitmep
pypevitmep is an extension for pyRevit. It contain free set of scripts for Autodesk Revit:
you can redistribute it and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
See this link for a copy of the GNU General Public License protecting this package.
https://github.com/CyrilWaechter/pypevitmep/blob/master/LICENSE
"""
from Autodesk.Revit.UI import IExternalEventHandler, ExternalEvent
from Autodesk.Revit.DB import Transaction
from Autodesk.Revit.Exceptions import InvalidOperationException
import rpw
from pyrevit.forms import WPFWindow
doc = rpw.revit.doc
uidoc = rpw.revit.uidoc
__doc__ = "A simple modeless form sample"
__title__ = "Modeless Form"
__author__ = "Cyril Waechter"
__persistentengine__ = True
# Simple function we want to run
def delete_elements():
with rpw.db.Transaction("Delete selection"):
for elid in uidoc.Selection.GetElementIds():
doc.Delete(elid)
# Create a subclass of IExternalEventHandler
class SimpleEventHandler(IExternalEventHandler):
"""
Simple IExternalEventHandler sample
"""
# __init__ is used to make function from outside of the class to be executed by the handler. \
# Instructions could be simply written under Execute method only
def __init__(self, do_this):
self.do_this = do_this
# Execute method run in Revit API environment.
def Execute(self, uiapp):
try:
self.do_this()
except InvalidOperationException:
# If you don't catch this exeption Revit may crash.
print "InvalidOperationException catched"
def GetName(self):
return "simple function executed by an IExternalEventHandler in a Form"
# Now we need to make an instance of this handler. Moreover, it shows that the same class could be used to for
# different functions using different handler class instances
simple_event_handler = SimpleEventHandler(delete_elements)
# We now need to create the ExternalEvent
ext_event = ExternalEvent.Create(simple_event_handler)
# A simple WPF form used to call the ExternalEvent
class ModelessForm(WPFWindow):
"""
Simple modeless form sample
"""
def __init__(self, xaml_file_name):
WPFWindow.__init__(self, xaml_file_name)
self.simple_text.Text = "Hello World"
self.Show()
def delete_click(self, sender, e):
# This Raise() method launch a signal to Revit to tell him you want to do something in the API context
ext_event.Raise()
# Let's launch our beautiful and useful form !
modeless_form = ModelessForm("ModelessForm.xaml")
xml 文件
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Delete things:" Height="150" Width="300" ShowInTaskbar="False" Topmost="True"
WindowStartupLocation="CenterScreen" ScrollViewer.VerticalScrollBarVisibility="Disabled" HorizontalContentAlignment="Center">
<StackPanel Margin="20" HorizontalAlignment="Stretch">
<TextBlock x:Name="simple_text" Text="" Grid.Column="0" HorizontalAlignment="Center" FontWeight="Bold"/>
<Button Content="Delete selected elements" Height="30" Margin="10,10" Click="delete_click"/>
</StackPanel>
</Window>
推荐阅读
- ios - 在 iOS 12 版全纵向应用程序中以横向播放 AVKit 全屏视频
- arduino - “StaticJsonBuffer”未在此范围内声明
- python - 无法将 InMemoryUploadedFile 写入线程中的本地文件 - Python
- python - 使用 SelectMultiple 呈现的 Django ArrayField 未将所选选项显示为“已选择”
- java - 为什么将ftp java dsl配置引入spring集成核心时过滤器行为发生变化
- java - 如果 URI 路径不符合 Jax-RS 中的正则表达式怎么办
- gmail - 我可以使用 SES 发送电子邮件但已经在 Route53 中注册了 GSuite MX 记录吗
- python - 熊猫数据框按年绘制。需要代码来生成附加的图像
- r - 计算逐行最小二乘
- c# - 扩展 Asp.net 身份实体 AspNetUserRole 和 AspNetRole