Selecting objects with Python

Selecting objects with Python

Kevin.Bell
Advisor Advisor
18,164 Views
17 Replies
Message 1 of 18

Selecting objects with Python

Kevin.Bell
Advisor
Advisor

Hi,

 

I'm looking to create a python script which will select objects based on their parameter values, the objects will then be the highlighted active selection in the Revit UI for the user to do something with.

 

To start this off, I'm writing a basic script to select an object. I'm writing this as a Python script within Dynamo.

 

So in Dynamo I use the 'Select Model Element' node which returns an object, I'm now trying to select that object in python using:

 

selob = Selection.SetElementIds(selobject.Id)

But when I run the script I get the error:

 

TypeError SetElementIds() takes exactly 2 arguements (1 given).

 

But looking at the API documentation for the Selection Class, the SetElementsIds method only appears to require one arguement.

 

http://www.revitapidocs.com/2015/cf8c11bb-f0c7-6d50-cbdf-41d0a010d9d6.htm

 

Am I missing something?

 

Thanks.

0 Likes
Accepted solutions (2)
18,165 Views
17 Replies
Replies (17)
Message 2 of 18

jeremytammik
Autodesk
Autodesk

I cannot answer all aspects of your question, but I can address two:

 

1. Why does your error message include a typo? It says "arguements"... I find that hard to believe.

 

2. You are passing in a single element id. The SetElementsIds method argument is a generic list of element ids, List<ElementId>. To pass in a single id, you can create an empty list, add the id to it, and pass in that.

 

Unfortunately I cannot say why the error message mentions two arguments... that may be a Python-specific quirk.

 

Do you want to start by trying to pass in the list instead of the single id on its own?

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 3 of 18

Kevin.Bell
Advisor
Advisor

Thanks for your response.

 

I amended the code to add a list:

 

import clr
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI.Selection import *

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager

import sys
pyt_path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
sys.path.append(pyt_path)

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
adoc = doc.ActiveView
uidoc = uiapp.ActiveUIDocument

#The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
selobject		= UnwrapElement(IN[0])	# Object to select

sellist = []
sellist.append(selobject.Id)

selob = Selection.SetElementIds(sellist)

#Assign your output to the OUT variable.
OUT = [selob]

But get the same error: (I've copied and pasted this from the error window)

 

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed.
Traceback (most recent call last):
File "<string>", line 39, in <module>
TypeError: SetElementIds() takes exactly 2 arguments (1 given)

 

 

Don't know if thats any help?

0 Likes
Message 4 of 18

jeremytammik
Autodesk
Autodesk

Thank!

 

Yup, helps.

 

I forwarded this to the Dynamo development team for help.

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 5 of 18

Kevin.Bell
Advisor
Advisor

Excellent, thanks.

0 Likes
Message 6 of 18

stever66
Advisor
Advisor

Give something like this a try:


        uidoc = self.ActiveUIDocument
        doc = self.ActiveUIDocument.Document
        app = self.Application
        
        # Select some elements in Revit before invoking this command
        # Get the element selection of current document.
        selectedIds = uidoc.Selection.GetElementIds()
        if 0 == selectedIds.Count:
             TaskDialog.Show("Revit","You haven't selected any elements.")
             
        else:
            TaskDialog.Show("Revit","Elements Selected.")

0 Likes
Message 7 of 18

thomas
Advocate
Advocate
Accepted solution

The exception you're getting is caused by calling a method on an invalid object. 

 

To get your code working you need to do the following:

 

1. Import the System.Collection.Generic library 

2. Create a ElementId List object and add the element id's to it - in IronPython the syntax is List[class]()

3. Get the active UI document then pass the ElementId list to the SetElementIds method

 

Here's a working example:

 

import clr

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from System.Collections.Generic import *

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

element = UnwrapElement(IN[0])

elementIdList = List[ElementId]()
elementIdList.Add(element.Id)

sel = uidoc.Selection.SetElementIds(elementIdList)

Also, you should post these questions on the Dynamo.org forum as you would get a quicker response.

 

HighlightModelElement.gif

Message 8 of 18

Kevin.Bell
Advisor
Advisor

MD - Briliant thanks!

 

I see the problem was the use of an 'ICollection', I've not come across one of those before.

 

Whats the difference between an ICollection and a list?

 

Cheers.

0 Likes
Message 9 of 18

BobbyC.Jones
Advocate
Advocate
Accepted solution

An ICollection is an interface that defines a small set of properties and methods that are useful for manipulating a collection of objects:  Count, Add(), Remove(), Clear(), etc...

 

A .net List is a class that contains a list of objects.  It implements the ICollection interface, as well as a couple of others.

 

I'm not familiar with python so I'm not sure what .net type, nor the interfaces it implements, this translates too:

 

 

sellist = []

 

 

But in thomas's example

 

elementIdList = List[ElementId]()
elmentIdList.Add(element.Id)

a new List object for holding ElementId's is instantiated and an ElementId is added to it.  Since the List object implements ICollection, it can be passed as an argument to the Selection.SetElementsIDs() method since it expects an ICollection as its argument.

 

 

 

 

--
Bobby C. Jones
0 Likes
Message 10 of 18

Kevin.Bell
Advisor
Advisor

Thanks Bobby!

0 Likes
Message 11 of 18

Anonymous
Not applicable

I tried this method and it works for me when i select a single element in revit, but i would like to select multiple elements instead...

 

Is that possible or the script doesn't work for multiple selection?

 

I thought it should because you make a list and just add all the id's to the list and it will select them all.

 

Kind Regards,

 

F Verwoert

0 Likes
Message 12 of 18

paolomod3nese
Enthusiast
Enthusiast

Thanks for this explanation Thomas!

ps. you might want to change point 1 in your explanation to make the word Collection plural.

 

Cheers!

Paolo

0 Likes
Message 13 of 18

asaleem.cem19
Participant
Participant

Hello i am currently having problem selecting multiple elements using python. Could you please help me with a code

0 Likes
Message 14 of 18

CWagnerLYWJP
Participant
Participant

Related to selection objects using python:

 

I want to use python using a hotkey in revit to take my active selection (probably grab the x,y?) and move it to a point that I select in a viewport,. such as another object. 

0 Likes
Message 15 of 18

Kevin.Bell
Advisor
Advisor

It really depends on how your running the Python code... if its in Dynamo, then you could use Dynamo player to do this... or you could try PyRevit (I've not used that) perhaps create a command, I'd suggest that C# would be the best method (if you know how to use that) as it would be easy to create a command.

 

Not sure you can assign a hot key in Dynamo player though, but in c# or PyRevit you can use the keyboard shortcuts to run your command.

 

Upon running, it would grab the current selection (using uidoc.Selection.GetElementIds() as per the above posts), then use ElementTransformUtils to move the elements to a new location.

 

https://www.revitapidocs.com/2015/3cf8c9dc-f4d1-12f0-d7a9-e126331cd858.htm

 

Hope thats of use!

0 Likes
Message 16 of 18

CWagnerLYWJP
Participant
Participant

Thanks for the suggestions.

 

I've decided to just start with grabbing the info or rather recognizing what elements I have selected when I run the graph in Dynamo.

 

Figured to start with the starting point haha

 

For whatever reason, Dynamo doesn't actually run the graph again or rather it doesnt refresh the data when I rerun it.

 

I get the list of elements I had selected when the graph was ran, but when I select something else or even simply have nothing selected, the output doesn't change.

 

I even added a random number generator just to see if it generates a new number when the graph is ran again and in fact it doesn't!

 

Here is my starting point. (Works but the output doesn't change when ran again.)

 

...btw I used chatGPT to generate the code haha.

 

CWagnerLYWJP_0-1684182941349.png

 

Message 17 of 18

Kevin.Bell
Advisor
Advisor

The reason that you can't rerun the graph is that Dynamo doesn't bother to run if nothing has changed... I've had this problem in the past...

 

The simplest way I managed to 'fix' the issue was to add a bool to the graph, it doesn't have to do anything, but by changing it Dynamo will rerun.

 

On the Python Script node, click the plus button to add a new input (you won't need to change your code as it doesn't have to do anything), add a Bool (i.e. True / False selector) to that. That should work, but you'll have to change the True / False each time...

 

Looking at the code, PRINT wont work as there is no where to print to...

 

Try this:

 

Before the for element in selected_Elements bit create a blank list called, say, results:

 

results = []

 

then change the PRINT statement to add the output to the results list:

 

results.append("Element ID" + element_id)

results.append("Element Name" + element_name)

 

Then add the results list to output, replace OUT = selected_elements with

 

OUT = results

 

 

Best of luck!

0 Likes
Message 18 of 18

CWagnerLYWJP
Participant
Participant

Yea the code needs to be cleaned up for sure.

What I want to do is use the Dynamo Player. The graph/code works now as is but again it can't be reran because Dynamo doesn't notice any changes.