Voltar ao Blog
RevitAPIPythonInterface de UsuárioSeleção

Métodos de Seleção de UI no Revit API — Seleção Interativa de Elementos

Paulo Giavoni

Paulo Giavoni

Engenheiro & Especialista BIM

5 janeiro 202610 min read
Métodos de Seleção de UI no Revit API — Seleção Interativa de Elementos

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:

  1. Primeiros Passos com Automação BIM
  2. Coleta de Elementos com FilteredElementCollector
  3. 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:

Python
1import clr
2clr.AddReference('RevitAPIUI') # <-- Nota: adicionamos UI
3import Autodesk
4from Autodesk.Revit.UI import *
5from Autodesk.Revit.UI.Selection import *
6
7clr.AddReference('RevitServices')
8import RevitServices
9from RevitServices.Persistence import DocumentManager
10
11# Obter o documento atual e o documento UI
12doc = DocumentManager.Instance.CurrentDBDocument
13uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

Diferenç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:

  1. Dynamo é projetado para programação visual, não interação via código
  2. 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.

Python
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ásicos
9 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:

Python
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.Name
8 category_count[category] = category_count.get(category, 0) + 1
9
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:

Python
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) + 1
10
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:

Python
1from Autodesk.Revit.DB import BoundingBoxIntersectsFilter, Outline
2
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) + 1
16
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:

Python
1class FiltroPersonalizado(ISelectionFilter):
2 def __init__(self, nome_categoria, nome_parametro, valor_parametro):
3 self.nome_categoria = nome_categoria
4 self.nome_parametro = nome_parametro
5 self.valor_parametro = valor_parametro
6
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 True
12 return False
13
14 def AllowReference(self, reference, point):
15 return False
16
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:

Python
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_categorias
8 return False
9
10 def AllowReference(self, reference, point):
11 return False
12
13# Uso: Selecionar apenas portas e janelas
14filtro_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:

Python
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_views
8
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 vista
16 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 vista
21 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:

Python
1from Autodesk.Revit.DB import XYZ
2
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 None
15 return pontos
16
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 pontos
26 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:

Python
1def criar_task_dialog(titulo, instrucao_principal, conteudo, comandos, texto_verificacao=None):
2 dialog = TaskDialog(titulo)
3 dialog.MainInstruction = instrucao_principal
4 dialog.MainContent = conteudo
5
6 for comando in comandos:
7 dialog.AddCommandLink(comando[0], comando[1])
8
9 if texto_verificacao:
10 dialog.VerificationText = texto_verificacao
11
12 return dialog
13
14# Exemplo de uso
15comandos = [
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 paredes
34elif resultado == TaskDialogResult.CommandLink2:
35 print("Usuário escolheu selecionar portas")
36 # Prosseguir com seleção de portas
37elif 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:

Python
1# Selecionar uma face
2try:
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 aresta
13try:
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:

Python
1from Autodesk.Revit.DB import ElementId
2from System.Collections.Generic import List
3
4# Coletar todas as paredes
5paredes = FilteredElementCollector(doc).OfClass(Wall).ToElements()
6
7# Criar uma lista de ElementIds
8ids_paredes = List[ElementId]([parede.Id for parede in paredes])
9
10# Definir a seleção
11uidoc.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:

Python
1class EditorElementos:
2 def __init__(self, doc, uidoc):
3 self.doc = doc
4 self.uidoc = uidoc
5
6 def executar(self):
7 # Passo 1: Mostrar diálogo para escolher ação
8 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 editor
55editor = 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:

  1. Primeiros Passos com Automação BIM — Fundamentos e conceitos-chave
  2. Coleta de Elementos com FilteredElementCollector — Encontrando elementos programaticamente
  3. Métodos de Seleção de UI — Seleção interativa de usuário (este artigo)
Share:

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