Torna al Blog
RevitAPIPythonInterfaccia UtenteSelezione

Metodi di Selezione UI nel Revit API — Selezione Interattiva degli Elementi

Paulo Giavoni

Paulo Giavoni

Ingegnere & Specialista BIM

5 gennaio 20269 min read
Metodi di Selezione UI nel Revit API — Selezione Interattiva degli Elementi

Introduzione alla Selezione UI#

Il Revit API offre un robusto set di strumenti per permettere agli utenti di selezionare elementi interattivamente invece di raccoglierli automaticamente. Questa è la differenza chiave:

  • FilteredElementCollector (articolo precedente) = Trova elementi automaticamente con il codice
  • UI Selection (questo articolo) = L'utente clicca sugli elementi che vuole processare

Quando usare la selezione interattiva:

  • L'utente deve scegliere visualmente cosa modificare
  • La selezione non può essere automatizzata con filtri
  • Vuoi conferma visiva prima di modificare elementi
  • Serve flessibilità — utenti diversi selezionano cose diverse

Quando usare i collector:

  • I criteri di selezione sono chiari e automatizzabili ("tutti i muri del piano terra")
  • Serve velocità — processare centinaia di elementi automaticamente
  • Il workflow deve essere ripetibile senza intervento manuale

Questo è il terzo articolo di una serie in tre parti sullo sviluppo con Revit API:

  1. Primi Passi con l'Automazione BIM
  2. Raccolta Elementi con FilteredElementCollector
  3. Metodi di Selezione UI (questo articolo)

Librerie e Setup Richiesti#

La selezione UI richiede librerie aggiuntive rispetto alla raccolta automatica:

Python
1import clr
2clr.AddReference('RevitAPIUI') # <-- Nota: aggiungiamo 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# Ottieni il documento corrente e il documento UI
12doc = DocumentManager.Instance.CurrentDBDocument
13uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

Differenza chiave:

  • doc = Il modello Revit (dati)
  • uidoc = L'interfaccia utente (cosa vede l'utente)

Tutti i metodi di selezione usano uidoc, non doc.


Nota Importante per Dynamo#

ATTENZIONE: La maggior parte degli esempi in questo articolo funzionano solo in add-in C#, non in Dynamo.

Dynamo non supporta direttamente metodi come PickObject() perché:

  1. Dynamo è progettato per programmazione visuale, non interazione via codice
  2. I nodi Dynamo gestiscono input/output in modo diverso dagli add-in

Alternative in Dynamo:

  • Usa nodi come "Select Model Element" o "Select Model Elements"
  • Per selezioni avanzate, crea un add-in C# separato
  • Per prototipazione, usa PyRevit (framework Python standalone per Revit)

Questo articolo è utile se:

  • Stai imparando Revit API per creare add-in C# in futuro
  • Vuoi capire come funzionano internamente i nodi di selezione Dynamo
  • Usi PyRevit o framework simili che supportano uidoc.Selection

1. Selezione Base degli Elementi#

1.1 Selezionare un Singolo Elemento#

Il metodo PickObject() è la base della selezione elementi nel Revit API. Richiede all'utente di selezionare un singolo elemento nell'interfaccia Revit.

Python
1try:
2 selected_reference = uidoc.Selection.PickObject(ObjectType.Element, "Seleziona un elemento")
3 element = doc.GetElement(selected_reference.ElementId)
4 print(f"Elemento selezionato: {element.Name}")
5 print(f"Categoria: {element.Category.Name}")
6 print(f"ID: {element.Id}")
7
8 # Ottieni alcuni parametri base
9 for param in element.Parameters:
10 print(f"{param.Definition.Name}: {param.AsValueString()}")
11except Exception as e:
12 print(f"Selezione annullata o fallita: {str(e)}")

Questo esempio non solo seleziona un elemento, ma recupera e stampa anche varie proprietà e parametri dell'elemento selezionato.

Esercizio: Modifica il codice per permettere la selezione di una categoria specifica (es: solo muri). Suggerimento: Dovrai usare un ISelectionFilter personalizzato.


1.2 Selezionare Elementi Multipli#

Quando devi selezionare più elementi, il metodo PickObjects() è utile:

Python
1try:
2 selected_references = uidoc.Selection.PickObjects(ObjectType.Element, "Seleziona più elementi")
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"Selezionati {len(elements)} elementi")
11 for category, count in category_count.items():
12 print(f"{category}: {count}")
13except Exception as e:
14 print(f"Selezione annullata o fallita: {str(e)}")

Questo esempio seleziona più elementi e fornisce un riepilogo degli elementi selezionati per categoria.

Esercizio: Estendi il codice per calcolare e stampare il volume totale di tutti gli elementi selezionati che hanno un parametro volume.


2. Tecniche Avanzate di Selezione#

2.1 Selezione per Rettangolo#

Il metodo PickElementsByRectangle() permette un processo di selezione più visuale, simile al trascinamento di una casella di selezione nell'interfaccia Revit:

Python
1try:
2 selected_elements = uidoc.Selection.PickElementsByRectangle("Seleziona elementi per rettangolo")
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 "Nessun Livello"
9 levels[level_name] = levels.get(level_name, 0) + 1
10
11 print(f"Selezionati {len(selected_elements)} elementi")
12 for level, count in levels.items():
13 print(f"Livello {level}: {count} elementi")
14except Exception as e:
15 print(f"Selezione annullata o fallita: {str(e)}")

Questo esempio seleziona elementi all'interno di un rettangolo e li organizza per livello, fornendo un conteggio degli elementi per ogni livello.


2.2 Pick Box#

Il metodo PickBox() crea una casella di selezione basata su due punti, utile per definire una regione 3D:

Python
1from Autodesk.Revit.DB import BoundingBoxIntersectsFilter, Outline
2
3try:
4 box = uidoc.Selection.PickBox(PickBoxStyle.Enclosing, "Seleziona area")
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"Trovati {len(elements)} elementi dentro la box selezionata")
12 category_count = {}
13 for elem in elements:
14 category = elem.Category.Name if elem.Category else "Nessuna 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"Selezione annullata o fallita: {str(e)}")

Questo esempio usa la box selezionata per creare un filtro bounding box, poi trova tutti gli elementi che intersecano con questa box.


3. Filtri di Selezione Personalizzati#

I filtri di selezione personalizzati permettono un controllo fine su quali elementi possono essere selezionati:

Python
1class FiltroPersonalizzato(ISelectionFilter):
2 def __init__(self, nome_categoria, nome_parametro, valore_parametro):
3 self.nome_categoria = nome_categoria
4 self.nome_parametro = nome_parametro
5 self.valore_parametro = valore_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.valore_parametro:
11 return True
12 return False
13
14 def AllowReference(self, reference, point):
15 return False
16
17try:
18 filtro_personalizzato = FiltroPersonalizzato("Muri", "Commenti", "Importante")
19 selected_elements = uidoc.Selection.PickObjects(
20 ObjectType.Element,
21 filtro_personalizzato,
22 "Seleziona muri importanti"
23 )
24
25 print(f"Selezionati {len(selected_elements)} muri importanti")
26 for ref in selected_elements:
27 elem = doc.GetElement(ref.ElementId)
28 print(f"ID Muro: {elem.Id}, Nome: {elem.Name}")
29except Exception as e:
30 print(f"Selezione annullata o fallita: {str(e)}")

Questo esempio crea un filtro personalizzato che permette solo la selezione di muri con un valore di commento specifico.


3.1 Filtro per Categoria#

Un filtro più semplice che permette solo la selezione di categorie specifiche:

Python
1class FiltroCategorie(ISelectionFilter):
2 def __init__(self, nomi_categorie):
3 self.nomi_categorie = nomi_categorie if isinstance(nomi_categorie, list) else [nomi_categorie]
4
5 def AllowElement(self, elem):
6 if elem.Category:
7 return elem.Category.Name in self.nomi_categorie
8 return False
9
10 def AllowReference(self, reference, point):
11 return False
12
13# Uso: Seleziona solo porte e finestre
14filtro_porte_finestre = FiltroCategorie(["Porte", "Finestre"])
15selected = uidoc.Selection.PickObjects(
16 ObjectType.Element,
17 filtro_porte_finestre,
18 "Seleziona porte o finestre"
19)

4. Lavorare con le Viste Selezionate#

Recuperare e lavorare con le viste selezionate nel browser di progetto:

Python
1def ottieni_viste_selezionate():
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 = ottieni_viste_selezionate()
10print(f"Selezionate {len(selected_views)} viste")
11
12for view in selected_views:
13 print(f"Nome Vista: {view.Name}, Tipo: {view.ViewType}")
14
15 # Conta elementi visibili in ogni vista
16 collector = FilteredElementCollector(doc, view.Id).WhereElementIsNotElementType()
17 element_count = collector.GetElementCount()
18 print(f" Elementi visibili: {element_count}")
19
20 # Controlla proprietà specifiche della vista
21 if hasattr(view, 'Scale'):
22 print(f" Scala: 1:{view.Scale}")

5. Selezione Punti#

La selezione punti è cruciale per molte operazioni, come creare nuovi elementi o misurare distanze:

Python
1from Autodesk.Revit.DB import XYZ
2
3def seleziona_punti(prompt, quantita):
4 punti = []
5 for i in range(quantita):
6 try:
7 punto = uidoc.Selection.PickPoint(
8 ObjectSnapTypes.Endpoints,
9 f"{prompt} (Punto {i+1}/{quantita})"
10 )
11 punti.append(punto)
12 except Exception as e:
13 print(f"Selezione punto annullata o fallita: {str(e)}")
14 return None
15 return punti
16
17def distanza_tra_punti(p1, p2):
18 return p1.DistanceTo(p2)
19
20punti = seleziona_punti("Seleziona due punti per misurare la distanza", 2)
21if punti and len(punti) == 2:
22 distanza = distanza_tra_punti(punti[0], punti[1])
23 print(f"Distanza tra i punti: {distanza:.2f} piedi")
24
25 # Crea un elemento linea tra i due punti
26 try:
27 linea = Line.CreateBound(punti[0], punti[1])
28 doc.Create.NewDetailCurve(doc.ActiveView, linea)
29 print("Creata una linea di dettaglio tra i punti")
30 except Exception as e:
31 print(f"Creazione linea di dettaglio fallita: {str(e)}")

Questo esempio dimostra come selezionare più punti, calcolare la distanza tra loro e creare una linea di dettaglio.


6. Interazione Utente con TaskDialog#

Creare dialoghi interattivi migliora l'esperienza utente:

Python
1def crea_task_dialog(titolo, istruzione_principale, contenuto, comandi, testo_verifica=None):
2 dialog = TaskDialog(titolo)
3 dialog.MainInstruction = istruzione_principale
4 dialog.MainContent = contenuto
5
6 for comando in comandi:
7 dialog.AddCommandLink(comando[0], comando[1])
8
9 if testo_verifica:
10 dialog.VerificationText = testo_verifica
11
12 return dialog
13
14# Esempio di uso
15comandi = [
16 (TaskDialogCommandLinkId.CommandLink1, "Opzione 1: Seleziona muri"),
17 (TaskDialogCommandLinkId.CommandLink2, "Opzione 2: Seleziona porte"),
18 (TaskDialogCommandLinkId.CommandLink3, "Opzione 3: Annulla operazione")
19]
20
21dialog = crea_task_dialog(
22 "Selezione Elementi",
23 "Scegli cosa selezionare",
24 "La tua scelta determinerà quali elementi possono essere selezionati.",
25 comandi,
26 "Ricorda la mia scelta"
27)
28
29risultato = dialog.Show()
30
31if risultato == TaskDialogResult.CommandLink1:
32 print("L'utente ha scelto di selezionare muri")
33 # Procedi con selezione muri
34elif risultato == TaskDialogResult.CommandLink2:
35 print("L'utente ha scelto di selezionare porte")
36 # Procedi con selezione porte
37elif risultato == TaskDialogResult.CommandLink3:
38 print("L'utente ha annullato l'operazione")
39
40if dialog.WasVerificationChecked():
41 print("L'utente vuole ricordare questa scelta")

7. Selezione Facce e Spigoli#

Per selezione geometrica più precisa:

Python
1# Seleziona una faccia
2try:
3 face_ref = uidoc.Selection.PickObject(ObjectType.Face, "Seleziona una faccia")
4 element = doc.GetElement(face_ref.ElementId)
5 face = element.GetGeometryObjectFromReference(face_ref)
6
7 print(f"Faccia selezionata da: {element.Name}")
8 print(f"Area faccia: {face.Area:.2f} piedi²")
9except Exception as e:
10 print(f"Selezione faccia fallita: {str(e)}")
11
12# Seleziona uno spigolo
13try:
14 edge_ref = uidoc.Selection.PickObject(ObjectType.Edge, "Seleziona uno spigolo")
15 element = doc.GetElement(edge_ref.ElementId)
16 edge = element.GetGeometryObjectFromReference(edge_ref)
17
18 print(f"Spigolo selezionato da: {element.Name}")
19 print(f"Lunghezza spigolo: {edge.ApproximateLength:.2f} piedi")
20except Exception as e:
21 print(f"Selezione spigolo fallita: {str(e)}")

8. Impostare Pre-Selezione#

Puoi anche impostare programmaticamente la selezione corrente:

Python
1from Autodesk.Revit.DB import ElementId
2from System.Collections.Generic import List
3
4# Raccogli tutti i muri
5muri = FilteredElementCollector(doc).OfClass(Wall).ToElements()
6
7# Crea una lista di ElementIds
8ids_muri = List[ElementId]([muro.Id for muro in muri])
9
10# Imposta la selezione
11uidoc.Selection.SetElementIds(ids_muri)
12
13print(f"Pre-selezionati {len(ids_muri)} muri")

9. Esempio Completo: Editor Interattivo Elementi#

Ecco un esempio completo che combina più tecniche di selezione:

Python
1class EditorElementi:
2 def __init__(self, doc, uidoc):
3 self.doc = doc
4 self.uidoc = uidoc
5
6 def esegui(self):
7 # Step 1: Mostra dialogo per scegliere azione
8 dialog = TaskDialog("Editor Elementi")
9 dialog.MainInstruction = "Cosa vorresti fare?"
10 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Modifica elemento singolo")
11 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink2, "Modifica elementi multipli")
12 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink3, "Modifica elementi nell'area")
13
14 risultato = dialog.Show()
15
16 if risultato == TaskDialogResult.CommandLink1:
17 self.modifica_singolo()
18 elif risultato == TaskDialogResult.CommandLink2:
19 self.modifica_multipli()
20 elif risultato == TaskDialogResult.CommandLink3:
21 self.modifica_in_area()
22
23 def modifica_singolo(self):
24 try:
25 ref = self.uidoc.Selection.PickObject(ObjectType.Element, "Seleziona elemento da modificare")
26 elemento = self.doc.GetElement(ref.ElementId)
27 self.mostra_info_elemento(elemento)
28 except:
29 print("Selezione annullata")
30
31 def modifica_multipli(self):
32 try:
33 refs = self.uidoc.Selection.PickObjects(ObjectType.Element, "Seleziona elementi da modificare")
34 elementi = [self.doc.GetElement(ref.ElementId) for ref in refs]
35 for elem in elementi:
36 self.mostra_info_elemento(elem)
37 except:
38 print("Selezione annullata")
39
40 def modifica_in_area(self):
41 try:
42 elementi = self.uidoc.Selection.PickElementsByRectangle("Disegna rettangolo per selezionare")
43 for elem_id in elementi:
44 elem = self.doc.GetElement(elem_id)
45 self.mostra_info_elemento(elem)
46 except:
47 print("Selezione annullata")
48
49 def mostra_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# Esegui l'editor
55editor = EditorElementi(doc, uidoc)
56editor.esegui()

Conclusione#

Questa guida copre un'ampia gamma di metodi di selezione del Revit API, dalla selezione base degli elementi alle selezioni filtrate avanzate e interazioni utente. La chiave per padroneggiare la selezione nel Revit API è pratica e sperimentazione.

Ricorda:

  • Usa filtri personalizzati per limitare cosa gli utenti possono selezionare
  • Avvolgi sempre le selezioni in blocchi try-except per gestione elegante delle annullazioni
  • Combina metodi di selezione con FilteredElementCollector per workflow potenti
  • Fornisci prompt chiari per guidare gli utenti

Prossimi Passi#

Questo conclude la nostra serie in tre parti sullo sviluppo con Revit API:

  1. Primi Passi con l'Automazione BIM — Fondamenti e concetti chiave
  2. Raccolta Elementi con FilteredElementCollector — Trovare elementi programmaticamente
  3. Metodi di Selezione UI — Selezione interattiva utente (questo articolo)
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