I’m formulating a way to create a window tag. I’m getting my wires a little crossed with how attributes work. I’m used to AutoCAD’s attributes. In that case I’m able to leverage things such as an attribute having a preset. I’m not sure how to associate a text field with the block definition (not block instances). A bonus would be that the field is accessible similar to the BlockName and other properties.
I’m thinking up a few convoluted work-arounds but wondering if there’s an easy avenue to making this happen?
You can set and get user text key/value pairs for block definitions programmatically - but AFAIK there is no way to view or reference the values in a Rhino document outside of further coding.
Here’s an example of a basic setter which allows you to select a block instance and adds user text to its definition:
#! python3
import Rhino
import scriptcontext
def InstanceDefinitionSetUserString():
rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select instance", False, Rhino.DocObjects.ObjectType.InstanceReference)
if rc != Rhino.Commands.Result.Success: return
iref = objref.Object()
if iref:
idef = iref.InstanceDefinition
if idef:
idef.SetUserString("Paul", "Paulie")
if __name__=="__main__":
InstanceDefinitionSetUserString()
and a basic getter:
#! python3
import Rhino
import scriptcontext
def InstanceDefinitionGetUserString():
rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select instance", False, Rhino.DocObjects.ObjectType.InstanceReference)
if rc != Rhino.Commands.Result.Success: return
iref = objref.Object()
if iref:
idef = iref.InstanceDefinition
if idef:
print(idef.GetUserString("Paul"))
if __name__=="__main__":
InstanceDefinitionGetUserString()
If you need to see some user text related to blocks in Rhino then you could add instance user text with a default value when creating the block and just accept the default each time you add an instance - but you are then relying on individual instances not being altered subsequently and making life difficult if you do want to make consistent changes across all instances of a block…
The live updating would be nice but it’s not that important for what I’m doing. And I realize that maybe I could create some sort of table or take advantage of the user document text.
In AutoLISP if I don’t want to create a reactor (event) I conjure up some sort of a database sweep. Sometimes I make a counter so like very 10th time a command runs… so instead of ‘live’ updating the system would just catch up with itself.
The BlockDescription might actually do what I want but it’s not working. For example, if I use ObjectName it works. If I use BlockInstanceCount it works. BlockName also works. Just BlockDescription is not working.
I’m checking pretty thoroughly because I really want it to work. This would just wipe out so many steps. I think it’s a bug (or ready in waiting and just not plugged in).
I’m solving the block/text issue by combining everything into a group instead. The tag symbol itself will be a block, but the text will be just grouped with the block. That way it can adapt to changing parameters.
I’m guessing that your problem is setting the value of the Description property, like the documentation says. That doesn’t work: you can only get the value from the property. Instead you have to use the InstanceDefinitionTable.Modify() method to update the definition you want to change.
#! python3
import Rhino
from scriptcontext import doc
def InstanceDefinitionSetDescription():
rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select instance", False, Rhino.DocObjects.ObjectType.InstanceReference)
if rc != Rhino.Commands.Result.Success: return
iref = objref.Object()
if iref:
idef = iref.InstanceDefinition
if idef:
oldDesc = idef.Description
name = idef.Name
doc.InstanceDefinitions.Modify(idef, name, "Widget 421a", True)
newDesc = idef.Description
print("Old description is {0}\nNew description is {1}".format(oldDesc, newDesc))
if __name__=="__main__":
InstanceDefinitionSetDescription()
Note that this method modifies the Name and Description, so capture the Name and rewrite it. SetBlockDescription.py (711 Bytes)
I left a bit out of my last post (tired plus excited = bad combo haha). The code you posted is going to help me immensely as my Python is extremely rusty. I’m actually just trying to exploit the actual text field:
I realized that if I use a group, I can take advantage of the fields. Programmatically I only need the object’s ID:
As you’ll see I’m currently using the Name instead of the Block Description. This actually works 90% as good as the description because it’s easy enough to select all blocks at once through the block manager. Basically all I’m doing is creating a way to tag objects.
Maybe the problem is that I’m grabbing the ID from an instance but the BlockDescription needs the ID from the definition?
The result is just “####” so I don’t think my hunch was correct.
To be honest I’ve basically gotten something completely useable thanks to your help. I can tag things almost as effectively as I can in Revit. The Description would just allow me to set the tag in a single place where the Name property just means I have to select all the objects at once through the block manager. That isn’t that bad.
Both are associated with the definition though. Unfortunately the UrlDescription doesn’t appear to be accessible to text fields, but the Description is:
For completeness, for the benefit of anyone wanting to set UrlDescription programatically, I’ll add that you can set that field by assigning a value to the property. The field will change but the new value will not display in the Block Manager unless you close and reopen it. (Or maybe write some code to refresh it - I haven’t explored that far.)
Once I get the code cleaned up I’ll also post it. Having the references is super helpful. I’ve been all over old posts while trying to get back into Rhino scripting.