Jump to content

What is a handle ?


FranAJA

Recommended Posts

It is just a weekend to understand the basic of python script in VW.
I am struggling to understand the concept of how commands are processed inside a python script and what a handle is

 

I have this very simple example (just for study purposes I am not doing a script that i use):

 

I do a rectangle, with parameters, then the rectangle get extruded, then the extrusion should be filled red as fill attribute..
the process logic works pretty linear as list of instructions.. until:

vs.SetFillFore(H,(255, 0, 0))

asks for a "Handle" (H) as first parameter 


with Marionette is pretty simple, the handle is basically the object input in portIN. 
but with python script i do not really understand how to select a handle, or how a handle can be called. 
It is really important also if I have a couple of objects and I want to call one instead of another, i need to understand which is the logic behind in scripting to works with different kind of geometries inside the same script. 
Sadly the examples in the developer wiki are really complex for me.
 

import vs

def execute():
    Lenght = vs.PLenght
    Height = vs.PHeight
    Extrusion = vs.PExtrusion

    vs.BeginXtrd(0, Extrusion)
    rect = vs.Rect(0, 0, Lenght, Height)
    vs.EndXtrd()
    vs.SetFillFore(H,(255, 0, 0))

 

 

Link to comment
  • Marionette Maven

Handles are Vectorworks' identifiers for objects. You can use vs.GetObject(name of object) to get an object by name; sometimes functions to create objects will return the handle to an object (or you can use vs.LNewObj() to return the handle to the last created object); or there are some other functions that return handles to objects as well.

 

Let me know if you want more examples of functions that return handles or if you have a specific way you'd like to determine the handle to an object. 

  • Like 1
Link to comment

Vectorworks loads the entire drawing into memory, and a handle is essentially a variable that can hold the location of each object in memory. That means each handle points to a unique object, but it is not a persistent object identifier — every time you open a file, objects load into different memory blocks, and memory might also get re-used if you delete an object. 
An empty handle means it is not currently holding the memory location of any object. 
Once you have a handle to an object, out can think of it as an alias to the object (hey compiler, look here and do x with this object). 

You can get handles to objects by creating new objects or by traversing the document’s structure, which is organized in a tree. 
In addition, Vectorworks also keeps an index of handles for all objects, so you can retrieve a handle via object name or UUID.  

  • Like 2
Link to comment

Thank you both for the explaination, my big struggling is how call a handle inside a python script.. if you have some example propably i can understand better. 
say for istance the example i have made above, after the extrusion has been created, how to call this handle inside the vs.SetFillFore. ? (if possible of course) 
This is just an example to understand how to call or define handle inside the script (if they can be called or definable). 

 

I have tried this but i'm actually guessing... probably a very simple example even if does not regard my script can be really helpful
 

import vs

def execute():
    Lenght = vs.PLenght
    Height = vs.PHeight
    Extrusion = vs.PExtrusion

    vs.BeginXtrd(0, Extrusion)
    rect = vs.Rect(0, 0, Lenght, Height)
    vs.EndXtrd()
    
    handle = vs.LNewObj()
    vs.SetFillFore(handle,(255, 0, 0))

 

 

Edited by FranAJA
Link to comment

Thank you Josh, let's forget just for a moment about the color issue, is not really that the point. 


I would like just to understand what put as Handle parameter, or define it when a Handle is required in an function. 
If my definition is building this extrusion, which is the hadle of this extrusion to be called in SetFill ? 
How can the script tell to the function: "This is the object that you have to point to" ?
This script is basically a custom plugin "Point Object".

vs.SetFillFore(h, (65535, 0, 39321)) it is just a random one picked as example to explain myself.

If i do not define "H" in some way:
NameError: name "h" is not defined.

image.png.f377430f5687e8c94df7331fab8728e3.png
 

Link to comment

Most function in Vectorscript/Python either operate on the Selected Objects OR on a single object that you need to have a handle to.

 

In your example above, you are using vs.LNewObj() to get a handle to the object that you just created.

 

As Marissa said, you can use the Name of an object to get a Handle to an object.  Or you can use some set of criteria to get a Handle.  One of the ones that I use a lot is vs.FSActLayer() which will get you a handle to the First Selected Object on the Active Layer.  Look in the Vectorscript Function Reference in the Document List Handling section for a number of other routines that will return the Handle to different objects.

 

In the USA, we used to have Card Catalogs in the library.  You would look through the card catalog for the book you want and on that card the actual physical location the book was at was listed.

 

Handles are similar.  The actual object exists somewhere in the computer memory, but you don't have to worry about where. You just have to know the Handle to the object and then let the compiler figure out exactly were that object is in memory so it can be modified.

 

Also, just as an aside, your spelling of Length in your variable names is not the standard English spelling. You end in ht (Lenght) instead of th (Length).  Since there are functions that are named Length also, you probably don't want to be using that as a variable name.

 

I am assuming that you are writing this as part of a Plug-in Object?  The pVariableName is normally only used in a PIO to specify something that is stored in the Parameter record.  It will probably be easier to play in a plain script to figure out handles instead of trying to deal with the PIO aspects also.

 

It is also easier for us to help with a specific example of what you are trying to do. Your script above seems to do that and looks like it should run.  Handle should be set to the Extrusion created by the BeginXtrd/EndXtrd and you are setting the Fill Fore color.  It might be that you actually need to use FillBack as the color for a solid fill.

 

HTH.

 

 

  • Like 1
Link to comment

Thank you PAT, 
It is just an exercise to understand more about vectorworks python scripting. My knowledge is very little about, i did not find many resources to study, so i try to exercise with little scripts to understand better the concepts. 


Handle is referred to an object, can be a name, can be a selection with some criteria. 
It is just odd that i can not give a "name" to this extrusion, and then call it  in the fill function rather than use vs.LNewObj()

 

If have two different solids how do I understands what solid i am referring to, do i have to give them a "handle" after every creation ?

ps: sorry about mispelling, english is not my first language. I will correct now the script..

EDIT :

I probably understood the concept trying to use multiple geometry and give to them different "handle" name.


 

import vs

def execute():
    Length = vs.PLength
    Height = vs.PHeight
    Extrusion = vs.PExtrusion

    vs.BeginXtrd(0, Extrusion)
    rect = vs.Rect(0, 0, Length, Height)
    vs.EndXtrd()

    #Box 1 Handle + Fill
    j = vs.LNewObj()
    vs.SetFillBack(j, 129)

    vs.Duplicate(1000,0)

    #Box 2 Handle + Fill
    h = vs.LNewObj()
    vs.SetFillBack(h,255)

    #Box 1 - Move 3D
    vs.Move3DObj(j,0,0,1000)

 

 

this is the result and actually worked..

image.png.a119cbdcfc15544f96a133db1705fe8f.png

Edited by FranAJA
Link to comment

@FranAJA Again, I think you are over-thinking things.

 

Handles are how Vectorworks tracks every element the drawing, and as such, every object already has a handle. The handle gets assigned to each object read from the saved file into memory and to every new object you create. You never have to "give" an object a handle -- you can only query Vectorworks to tell you the handle for the object you want.

 

1 hour ago, FranAJA said:

Handle is referred to an object, can be a name, can be a selection with some criteria. 

 

I think this is what is confusing you. The handle is the memory address where you can find the object. All the functions that return a handle aren't creating the handle, they are helping you find a handle that already exists. Functions that require a handle need to know where to find that object in memory.

 

vs.LNewObj() is the equivalent of "What is the memory address of the handle I just created"

 

Even though each object has a unique handle, because it is a memory address, you would never want to store the value of the handle anywhere, as it will change every time you load the file.

 

###

 

Here's my analogy. Imagine that the Vectorworks drawing is a crowded bakery, and the handle is the number each customer takes as they enter. The numbers are all unique, but even if a group of regular customers returns to the bakery every day, their numbers will be different.

 

We have a lot of ways we can find out which customer has each number. We can ask the first person or last person in line what number they have. Asking the last person is the equivalent to vs.LNewObj().

 

We can point at a customer and ask them what their ticket number is. This is similar to vs.FSActLayer(), which gives us the first selected object on the active layer.

 

If we ask each customer to also put their name on a list as they enter, we can call out their name and ask their number. This is the equivalent of vs.GetObject(). Of course, if the customer doesn't add their name, we can't use the list of names to find their ticket number. Objects in Vectorworks can, but are not required to have names.

 

We can also require each customer scan their government ID as they take a number, and use that list to ask the group what ticket number matches an ID. This is the equivalent of vs.GetObjectByUuid().

 

Another thing we can do is ask all the customers with red shirts what their ticket numbers are. This would be the equivalent of criteria functions that return handles.

 

Finally, if a customer leaves the bakery without being served, and gives their number to a new customer walking in, that ticket number now refers to a new customer. This is equivalent to deleting an object and creating a new one, and an example of why storing handles as data is never a good idea.

 

HTH

  • Like 3
Link to comment

Thank you J, now it is clear what handles are as theory. 
However, I just do not get which can be a good practice to refer to an object that I create inside the script, as i do not have any example to study. 
Using your analogy:

#Make bread for Client 1
Client 1 = vs.Rect(0,0,100,100)

(i would like to memorize this client to use in the future, how ?)

"We have a lot of ways we can find out which customer has each number"


#Lots of client, days.. lines in the script...

#I want to come back to the geometry i have done for client 1 and use 
vs.SetFillBack(h,255)

"h" is a handle, of client 1 who came days ago which i memorized before.  
I do not understand:
- how to memorize a Client (UUId, name etc), even using one of the methods you said before.
- How to call later in the script this (UUId,name,etc) 

watching for example: vs.GetObjectUuid(h) , this needs a handle as well. 

Probably i am misunderstanding how the process works... 
but if someone can provide a very simple a short code example it will be really helpful.

Edited by FranAJA
Link to comment

You might have to be more specific, as you have a working code snippet above. 
 

You seem to be asking about how to use handles for the duration of your script. In your example, h and j are handles, and you can use them as many times as you like for any function that asks for a handle. 
 

You seem to be creating a plug-in object. Every time a plug-in draws, it recreates the objects, so storing any identifier between runs doesn’t really make sense.  
 

32 minutes ago, FranAJA said:

Client 1 = vs.Rect(0,0,100,100)

Variables can’t have a space in the name, so let’s call it Client_1

 

34 minutes ago, FranAJA said:

#I want to come back to the geometry i have done for client 1 and use 
vs.SetFillBack(h,255)

vs.SetFillBack( Client_1, 255)

 

Client_1 is the variable holding the handle to the rectangle you created. 
 

38 minutes ago, FranAJA said:

h" is a handle, of client 1 who came days ago which i memorized before.  
I do not understand:
- how to memorize a Client (UUId, name etc), even using one of the methods you said before.
- How to call later in the script this (UUId,name,etc) 


This is not a simple question to answer. Storing names or UUIDs is only necessary if you want to do things like link two plug-in objects together. You would have to describe exactly what your are trying to do. If you’re just trying to refer to objects within the same script none of this is necessary. 
 

If you did want to retrieve the UUID of the rectangle and store it to a database field, you would call:

rectangleUUID = vs.GetObjectUuid(Client_1)

 

Here’s a simple script using a handle

#get the handle of the first selected drawing object and store it to a variable, h

h = vs.FSActLayer()

#Move the object 6 units to the right 

vs.HMove( h, 6, 0 )

#Change the object’s line color

vs.SetPenFore( h, 42 )

 

For the duration of the script, h will point to that selected object until you either delete the object or assign h to another object via a function that returns a handle. 
 

If you are confused about the concept of variables and scope in general, you can try starting here: https://www.w3schools.com/python/python_scope.asp

  • Like 1
Link to comment

One other thing, which I know can be confusing, is that some functions that create objects return handles, and some don’t. vs.Rect(), for example, does not return a handle, so you have to call vs.LNewObj() to retrieve the handle. That will always return the handle to the last object created. 
Other functions like MakePolygon() will return a handle. You just have to consult the function reference to know when you need to use LNewObj

  • Like 1
Link to comment

Sorry, one more point of clarification.

 

LNewObj is short for Last New Object. The object creation call, vs.Rect() in the example above, creates the handle. vs.LNewObj() just asks VW to tell us what handle points to the object we just created, it doesn't actually create anything, and you only need to call it if you want to store that object's handle for later (the handle still exists, but if you create another new object, LNewObj() will point to the latest created object).

  • Like 1
Link to comment

Thank J. I think now it is very clear, especially after your examples. 
It looks like, more or less a selection as when i draw in vectorworks two rectangles, I have to select again the first rectangle to operate on it. Even if in the meanwhile i have drew other different objects.. 
I was getting confused about the part:

Quote

"This is equivalent to deleting an object and creating a new one, and an example of why storing handles as data is never a good idea."


I though that If assign a handle to a variable like h = vs.FSActLayer() or h = vs.LNewObj was not a good procedure, but i think i just misunderstood what you were saying. 

Link to comment

Hi Floring,  they are parameters set inside the plugin (Plug-in Manager -> Edit Definitions -> Parameters)
I am using an external python script writing it in pycharm, then i am importing with "import _main" inside the script editor VW. 
To call parameters set in the plugin i am using vs.PParameterName. When there is "P" in front of the exact name of the parameter you can reference inside your IDE.
If you are writing your script directly in VW script editor you do not need to put P, just the name of the parameter.. 

I am still at beginning but hope this help.

  • Like 1
Link to comment

Which reminds me of another thing we ran across a long time ago.

 

DON'T use variable names that start with the letter P.  At least not if you ever intend to convert the script into a PIO.  The complier/interpreter will look for all variables that start with P to be Parameters instead of variables and the script that worked fine won't work properly as a PIO.

 

And saying and knowing this, my favorite variable name in small test scripts is my initials, PTS.  But I have been bitten a couple of time trying to convert scripts with that variable name into PIOs.

Link to comment

It's not quite so precarious — standard namespace rules still apply.

 

When you have a script for objects with parameters, before running the script, Vectorworks will create a constant that uses the name of the parameter prepended with a "P."

 

In python, these are all in the vs namespace, so you can access the parameter length with vs.Plength. Original Vectorscript has everything in the same namespaces, which is where Pat's example comes from. In python, you can have vs.PTS as distinct from PTS. And even in Vectorscript, you would only run into trouble if you also have a parameter named "TS."

 

Note that all the vs.P… variables are constant. You can read a parameter value, but you can not write back to that variable and have it updated the object. For that you would have to use vs.SetRField()

 

PrevObj is a method of vs (that returns a handle, which you can assign to a variable). As such, you would always call the method using parentheses:

h = vs.PrevObj()

 

vs.PrevObj refers to the method as an object, and something you would only do if, say, you had a function that took another function as a parameter. That's a fairly advanced coding concept.

 

I suppose that you could get into trouble if you have an object parameter named "revObj," as Vectorworks would try to create a constant "PrevObj" in addition to the existing method. That would lead to either a compilation error or for PrevObj() to be re-defined. 

Link to comment

I agree with most of what @JBenghiat says.

 

27 minutes ago, JBenghiat said:

Note that all the vs.P… variables are constant. You can read a parameter value, but you can not write back to that variable and have it updated the object. For that you would have to use vs.SetRField()

 This is where we need a little more clarification.  Joshua is correct that P... Variables don't change during the execution of the script.  But you can change the value (using SetRField(Parameter_Record,Parameter_Name)) from inside the script and it will be stored and used during the next execution of the script.  

 

What doesn't work is changing the value and trying to read back that value during the current execution. For that as J says, read the value into a variable and use that during the current execution. Then store the final value back to the parameter at the end of the script.

Link to comment
  • 4 weeks later...

Hi all, thanks for the excellent explanation! Instead of get single object(handle) through vs.FSActLayer() or vs.LNewObj(), are there any ways to batch get objects(handles) using api? For instance, like get all wall objects or door/window objets from model, so I'm able to batch processing the elements.

Link to comment

You can use the ForEachObject family of calls. There are four – ForEachObject(), ForEachObjectAtPoint(), ForEachObjectInLayer(), and ForEachObjectInList().

 

ForEachObject() takes criteria statements. The others work across Layers, with Lists, or at a Point. They take a  little time to get proficient with them, but they are very powerful. If you search the forum for these commands you should find quite a few examples.

 

Raymond

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...