
Introdução à Seleção de UI#
O Revit API oferece um conjunto robusto de ferramentas para permitir que usuários selecionem elementos interativamente em vez de coletá-los automaticamente. Esta é a diferença chave:
- FilteredElementCollector (artigo anterior) = Encontra elementos automaticamente com código
- UI Selection (este artigo) = O usuário clica nos elementos que quer processar
Quando usar seleção interativa:
- O usuário deve escolher visualmente o que modificar
- A seleção não pode ser automatizada com filtros
- Você quer confirmação visual antes de modificar elementos
- Precisa de flexibilidade — usuários diferentes selecionam coisas diferentes
Quando usar collectors:
- Os critérios de seleção são claros e automatizáveis ("todas as paredes do térreo")
- Precisa de velocidade — processar centenas de elementos automaticamente
- O workflow deve ser repetível sem intervenção manual
Este é o terceiro artigo de uma série de três partes sobre desenvolvimento com Revit API:
- Primeiros Passos com Automação BIM
- Coleta de Elementos com FilteredElementCollector
- Métodos de Seleção de UI (este artigo)
Bibliotecas e Configuração Necessárias#
A seleção de UI requer bibliotecas adicionais em relação à coleta automática:
1import clr2clr.AddReference('RevitAPIUI') # <-- Nota: adicionamos UI3import Autodesk4from Autodesk.Revit.UI import *5from Autodesk.Revit.UI.Selection import *6
7clr.AddReference('RevitServices')8import RevitServices9from RevitServices.Persistence import DocumentManager10
11# Obter o documento atual e o documento UI12doc = DocumentManager.Instance.CurrentDBDocument13uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocumentDiferença chave:
doc= O modelo Revit (dados)uidoc= A interface do usuário (o que o usuário vê)
Todos os métodos de seleção usam uidoc, não doc.
Nota Importante para Dynamo#
ATENÇÃO: A maioria dos exemplos neste artigo funcionam apenas em add-ins C#, não no Dynamo.
Dynamo não suporta diretamente métodos como PickObject() porque:
- Dynamo é projetado para programação visual, não interação via código
- Os nós Dynamo gerenciam input/output de forma diferente dos add-ins
Alternativas no Dynamo:
- Use nós como "Select Model Element" ou "Select Model Elements"
- Para seleções avançadas, crie um add-in C# separado
- Para prototipagem, use PyRevit (framework Python standalone para Revit)
Este artigo é útil se:
- Você está aprendendo Revit API para criar add-ins C# no futuro
- Quer entender como funcionam internamente os nós de seleção do Dynamo
- Usa PyRevit ou frameworks similares que suportam
uidoc.Selection
1. Seleção Básica de Elementos#
1.1 Selecionar um Único Elemento#
O método PickObject() é a base da seleção de elementos no Revit API. Ele solicita ao usuário que selecione um único elemento na interface do Revit.
1try:2 selected_reference = uidoc.Selection.PickObject(ObjectType.Element, "Selecione um elemento")3 element = doc.GetElement(selected_reference.ElementId)4 print(f"Elemento selecionado: {element.Name}")5 print(f"Categoria: {element.Category.Name}")6 print(f"ID: {element.Id}")7 8 # Obter alguns parâmetros básicos9 for param in element.Parameters:10 print(f"{param.Definition.Name}: {param.AsValueString()}")11except Exception as e:12 print(f"Seleção cancelada ou falhou: {str(e)}")Este exemplo não apenas seleciona um elemento, mas também recupera e imprime várias propriedades e parâmetros do elemento selecionado.
Exercício: Modifique o código para permitir seleção de uma categoria específica (ex: apenas paredes). Dica: Você precisará usar um ISelectionFilter personalizado.
1.2 Selecionar Múltiplos Elementos#
Quando você precisa selecionar múltiplos elementos, o método PickObjects() é útil:
1try:2 selected_references = uidoc.Selection.PickObjects(ObjectType.Element, "Selecione múltiplos elementos")3 elements = [doc.GetElement(ref.ElementId) for ref in selected_references]4 5 category_count = {}6 for elem in elements:7 category = elem.Category.Name8 category_count[category] = category_count.get(category, 0) + 19 10 print(f"Selecionados {len(elements)} elementos")11 for category, count in category_count.items():12 print(f"{category}: {count}")13except Exception as e:14 print(f"Seleção cancelada ou falhou: {str(e)}")Este exemplo seleciona múltiplos elementos e fornece um resumo dos elementos selecionados por categoria.
Exercício: Estenda o código para calcular e imprimir o volume total de todos os elementos selecionados que possuem um parâmetro de volume.
2. Técnicas Avançadas de Seleção#
2.1 Seleção por Retângulo#
O método PickElementsByRectangle() permite um processo de seleção mais visual, similar a arrastar uma caixa de seleção na interface do Revit:
1try:2 selected_elements = uidoc.Selection.PickElementsByRectangle("Selecione elementos por retângulo")3 4 levels = {}5 for elem_id in selected_elements:6 elem = doc.GetElement(elem_id)7 if hasattr(elem, 'Level'):8 level_name = elem.Level.Name if elem.Level else "Sem Nível"9 levels[level_name] = levels.get(level_name, 0) + 110 11 print(f"Selecionados {len(selected_elements)} elementos")12 for level, count in levels.items():13 print(f"Nível {level}: {count} elementos")14except Exception as e:15 print(f"Seleção cancelada ou falhou: {str(e)}")Este exemplo seleciona elementos dentro de um retângulo e os organiza por nível, fornecendo uma contagem de elementos em cada nível.
2.2 Pick Box#
O método PickBox() cria uma caixa de seleção baseada em dois pontos, útil para definir uma região 3D:
1from Autodesk.Revit.DB import BoundingBoxIntersectsFilter, Outline2
3try:4 box = uidoc.Selection.PickBox(PickBoxStyle.Enclosing, "Selecione a área")5 outline = Outline(box.Min, box.Max)6 bb_filter = BoundingBoxIntersectsFilter(outline)7 8 collector = FilteredElementCollector(doc).WherePasses(bb_filter)9 elements = list(collector)10 11 print(f"Encontrados {len(elements)} elementos dentro da caixa selecionada")12 category_count = {}13 for elem in elements:14 category = elem.Category.Name if elem.Category else "Sem Categoria"15 category_count[category] = category_count.get(category, 0) + 116 17 for category, count in category_count.items():18 print(f"{category}: {count}")19except Exception as e:20 print(f"Seleção cancelada ou falhou: {str(e)}")Este exemplo usa a caixa selecionada para criar um filtro de bounding box, então encontra todos os elementos que intersectam com essa caixa.
3. Filtros de Seleção Personalizados#
Filtros de seleção personalizados permitem controle refinado sobre quais elementos podem ser selecionados:
1class FiltroPersonalizado(ISelectionFilter):2 def __init__(self, nome_categoria, nome_parametro, valor_parametro):3 self.nome_categoria = nome_categoria4 self.nome_parametro = nome_parametro5 self.valor_parametro = valor_parametro6 7 def AllowElement(self, elem):8 if elem.Category and elem.Category.Name == self.nome_categoria:9 parameter = elem.LookupParameter(self.nome_parametro)10 if parameter and parameter.AsString() == self.valor_parametro:11 return True12 return False13 14 def AllowReference(self, reference, point):15 return False16
17try:18 filtro_personalizado = FiltroPersonalizado("Paredes", "Comentários", "Importante")19 selected_elements = uidoc.Selection.PickObjects(20 ObjectType.Element, 21 filtro_personalizado, 22 "Selecione paredes importantes"23 )24 25 print(f"Selecionadas {len(selected_elements)} paredes importantes")26 for ref in selected_elements:27 elem = doc.GetElement(ref.ElementId)28 print(f"ID da Parede: {elem.Id}, Nome: {elem.Name}")29except Exception as e:30 print(f"Seleção cancelada ou falhou: {str(e)}")Este exemplo cria um filtro personalizado que só permite seleção de paredes com um valor de comentário específico.
3.1 Filtro de Categoria#
Um filtro mais simples que só permite seleção de categorias específicas:
1class FiltroCategorias(ISelectionFilter):2 def __init__(self, nomes_categorias):3 self.nomes_categorias = nomes_categorias if isinstance(nomes_categorias, list) else [nomes_categorias]4 5 def AllowElement(self, elem):6 if elem.Category:7 return elem.Category.Name in self.nomes_categorias8 return False9 10 def AllowReference(self, reference, point):11 return False12
13# Uso: Selecionar apenas portas e janelas14filtro_portas_janelas = FiltroCategorias(["Portas", "Janelas"])15selected = uidoc.Selection.PickObjects(16 ObjectType.Element, 17 filtro_portas_janelas, 18 "Selecione portas ou janelas"19)4. Trabalhando com Vistas Selecionadas#
Recuperando e trabalhando com vistas selecionadas no navegador do projeto:
1def obter_vistas_selecionadas():2 selected_ids = uidoc.Selection.GetElementIds()3 selected_views = [4 doc.GetElement(id) for id in selected_ids 5 if doc.GetElement(id).GetType().Name.startswith("View")6 ]7 return selected_views8
9selected_views = obter_vistas_selecionadas()10print(f"Selecionadas {len(selected_views)} vistas")11
12for view in selected_views:13 print(f"Nome da Vista: {view.Name}, Tipo: {view.ViewType}")14 15 # Contar elementos visíveis em cada vista16 collector = FilteredElementCollector(doc, view.Id).WhereElementIsNotElementType()17 element_count = collector.GetElementCount()18 print(f" Elementos visíveis: {element_count}")19 20 # Verificar propriedades específicas da vista21 if hasattr(view, 'Scale'):22 print(f" Escala: 1:{view.Scale}")5. Seleção de Pontos#
A seleção de pontos é crucial para muitas operações, como criar novos elementos ou medir distâncias:
1from Autodesk.Revit.DB import XYZ2
3def selecionar_pontos(prompt, quantidade):4 pontos = []5 for i in range(quantidade):6 try:7 ponto = uidoc.Selection.PickPoint(8 ObjectSnapTypes.Endpoints, 9 f"{prompt} (Ponto {i+1}/{quantidade})"10 )11 pontos.append(ponto)12 except Exception as e:13 print(f"Seleção de ponto cancelada ou falhou: {str(e)}")14 return None15 return pontos16
17def distancia_entre_pontos(p1, p2):18 return p1.DistanceTo(p2)19
20pontos = selecionar_pontos("Selecione dois pontos para medir distância", 2)21if pontos and len(pontos) == 2:22 distancia = distancia_entre_pontos(pontos[0], pontos[1])23 print(f"Distância entre pontos: {distancia:.2f} pés")24 25 # Criar um elemento de linha entre os dois pontos26 try:27 linha = Line.CreateBound(pontos[0], pontos[1])28 doc.Create.NewDetailCurve(doc.ActiveView, linha)29 print("Criada uma linha de detalhe entre os pontos")30 except Exception as e:31 print(f"Falha ao criar linha de detalhe: {str(e)}")Este exemplo demonstra como selecionar múltiplos pontos, calcular a distância entre eles e criar uma linha de detalhe.
6. Interação com Usuário via TaskDialog#
Criar diálogos interativos melhora a experiência do usuário:
1def criar_task_dialog(titulo, instrucao_principal, conteudo, comandos, texto_verificacao=None):2 dialog = TaskDialog(titulo)3 dialog.MainInstruction = instrucao_principal4 dialog.MainContent = conteudo5 6 for comando in comandos:7 dialog.AddCommandLink(comando[0], comando[1])8 9 if texto_verificacao:10 dialog.VerificationText = texto_verificacao11 12 return dialog13
14# Exemplo de uso15comandos = [16 (TaskDialogCommandLinkId.CommandLink1, "Opção 1: Selecionar paredes"),17 (TaskDialogCommandLinkId.CommandLink2, "Opção 2: Selecionar portas"),18 (TaskDialogCommandLinkId.CommandLink3, "Opção 3: Cancelar operação")19]20
21dialog = criar_task_dialog(22 "Seleção de Elementos",23 "Escolha o que selecionar",24 "Sua escolha determinará quais elementos podem ser selecionados.",25 comandos,26 "Lembrar minha escolha"27)28
29resultado = dialog.Show()30
31if resultado == TaskDialogResult.CommandLink1:32 print("Usuário escolheu selecionar paredes")33 # Prosseguir com seleção de paredes34elif resultado == TaskDialogResult.CommandLink2:35 print("Usuário escolheu selecionar portas")36 # Prosseguir com seleção de portas37elif resultado == TaskDialogResult.CommandLink3:38 print("Usuário cancelou a operação")39
40if dialog.WasVerificationChecked():41 print("Usuário quer lembrar esta escolha")7. Seleção de Faces e Arestas#
Para seleção de geometria mais precisa:
1# Selecionar uma face2try:3 face_ref = uidoc.Selection.PickObject(ObjectType.Face, "Selecione uma face")4 element = doc.GetElement(face_ref.ElementId)5 face = element.GetGeometryObjectFromReference(face_ref)6 7 print(f"Face selecionada de: {element.Name}")8 print(f"Área da face: {face.Area:.2f} pés²")9except Exception as e:10 print(f"Seleção de face falhou: {str(e)}")11
12# Selecionar uma aresta13try:14 edge_ref = uidoc.Selection.PickObject(ObjectType.Edge, "Selecione uma aresta")15 element = doc.GetElement(edge_ref.ElementId)16 edge = element.GetGeometryObjectFromReference(edge_ref)17 18 print(f"Aresta selecionada de: {element.Name}")19 print(f"Comprimento da aresta: {edge.ApproximateLength:.2f} pés")20except Exception as e:21 print(f"Seleção de aresta falhou: {str(e)}")8. Definindo Pré-Seleção#
Você também pode definir programaticamente a seleção atual:
1from Autodesk.Revit.DB import ElementId2from System.Collections.Generic import List3
4# Coletar todas as paredes5paredes = FilteredElementCollector(doc).OfClass(Wall).ToElements()6
7# Criar uma lista de ElementIds8ids_paredes = List[ElementId]([parede.Id for parede in paredes])9
10# Definir a seleção11uidoc.Selection.SetElementIds(ids_paredes)12
13print(f"Pré-selecionadas {len(ids_paredes)} paredes")9. Exemplo Completo: Editor Interativo de Elementos#
Aqui está um exemplo abrangente que combina múltiplas técnicas de seleção:
1class EditorElementos:2 def __init__(self, doc, uidoc):3 self.doc = doc4 self.uidoc = uidoc5 6 def executar(self):7 # Passo 1: Mostrar diálogo para escolher ação8 dialog = TaskDialog("Editor de Elementos")9 dialog.MainInstruction = "O que você gostaria de fazer?"10 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Editar elemento único")11 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink2, "Editar múltiplos elementos")12 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink3, "Editar elementos em área")13 14 resultado = dialog.Show()15 16 if resultado == TaskDialogResult.CommandLink1:17 self.editar_unico()18 elif resultado == TaskDialogResult.CommandLink2:19 self.editar_multiplos()20 elif resultado == TaskDialogResult.CommandLink3:21 self.editar_em_area()22 23 def editar_unico(self):24 try:25 ref = self.uidoc.Selection.PickObject(ObjectType.Element, "Selecione elemento para editar")26 elemento = self.doc.GetElement(ref.ElementId)27 self.mostrar_info_elemento(elemento)28 except:29 print("Seleção cancelada")30 31 def editar_multiplos(self):32 try:33 refs = self.uidoc.Selection.PickObjects(ObjectType.Element, "Selecione elementos para editar")34 elementos = [self.doc.GetElement(ref.ElementId) for ref in refs]35 for elem in elementos:36 self.mostrar_info_elemento(elem)37 except:38 print("Seleção cancelada")39 40 def editar_em_area(self):41 try:42 elementos = self.uidoc.Selection.PickElementsByRectangle("Desenhe retângulo para selecionar")43 for elem_id in elementos:44 elem = self.doc.GetElement(elem_id)45 self.mostrar_info_elemento(elem)46 except:47 print("Seleção cancelada")48 49 def mostrar_info_elemento(self, elemento):50 print(f"\n--- {elemento.Name} ---")51 print(f"ID: {elemento.Id}")52 print(f"Categoria: {elemento.Category.Name if elemento.Category else 'N/A'}")53
54# Executar o editor55editor = EditorElementos(doc, uidoc)56editor.executar()Conclusão#
Este guia cobre uma ampla gama de métodos de seleção do Revit API, desde seleção básica de elementos até seleções filtradas avançadas e interações com usuário. A chave para dominar a seleção no Revit API é prática e experimentação.
Lembre-se:
- Use filtros personalizados para limitar o que os usuários podem selecionar
- Sempre envolva seleções em blocos try-except para tratamento gracioso de cancelamentos
- Combine métodos de seleção com FilteredElementCollector para workflows poderosos
- Forneça prompts claros para guiar os usuários
Próximos Passos#
Isso conclui nossa série de três partes sobre desenvolvimento com Revit API:
- Primeiros Passos com Automação BIM — Fundamentos e conceitos-chave
- Coleta de Elementos com FilteredElementCollector — Encontrando elementos programaticamente
- Métodos de Seleção de UI — Seleção interativa de usuário (este artigo)
Questions or Feedback?
I'd love to hear your thoughts on this article. Reach out directly and let's start a conversation.
Follow me on LinkedIn for more BIM tips and updates
