Jump to content
Developer Wiki and Function Reference Links ×

Layer function creates new layer instead of activating the existing one


GioPet

Recommended Posts

Hi all, 

 

this is a 'back to basics' question.

 

Here is the problem I'm coming across: if the layer name ends with a number, the VS function  Layer creates a new layer by incrementing the last digit.

 

A simple example: 

layerName: 'Design Layer-1';
Layer(layerName);

this will generate a layer named 'Design Layer-2' instead of activating the existing layer.

 

I am using ForEachObject to parse a set of objects through particular function.

Through the function, I need to activate the layer of the referenced object so that I can edit some of its parameters - but this won't work where layers end with a digit.

 

Can anyone suggest a workaround to Activate the layer of an object in this situation??

is there any function to activate the layer through its handle or through a referenced object?

 

thank you!

Link to comment

I don’t think I’ve ever encountered this, but if Layer() is behaving as you describe, I think it’s a bug. 

 

Are you modifying objects via the script, or selecting them for user interaction?  If the former, just make sure you’re using handle-based functions, and the layer doesn’t need to be active. 

 

And the snarky answer would be, this is another good reason to always rename layers to something specific 😏

Link to comment

Hi Joshua, 

 

thank you for your reply.

I am modifying the objects through the script - amongst other things I need to Change the class of certain objects and realised that SetClass cannot retain the class of the objects within Groups!!


SetClassN would do the job but it's available only since VW2018.. 

 

To move a Group from a class to another (achieving the equivalent of SetClassN), my workaround is:

  1. Activate the Group's layer
  2. Activate the desired class
  3. Ungroup and Group

But the Ungroup function won't work when I parse the handle of Groups which are not on the active layer - so I tried to use the Layer function to switch to each layer and change the class, but I've hit the problem..

Can you think of any other approach to this??

 

I agree with your answer and I would always ensure layers are properly named, but I need to get this script to work in almost any scenario - including drawings by others..

 

 

Link to comment

GioPet,
I am not sure how you got that code snippet to run, but the first line is not syntactically correct.

 

layerName: 'Design  Layer-1';
should read:
layerName := 'Design Layer-1';

 

When your variable "layerName" has the value 'Design Layer-1', it will not create 'Design Layer-2' and it will either make 'Design Layer-1' active, or leave it active. BUT, if "layerName" has the empty string value '', it will create 'Design Layer-2'.

 

My guess is that your variable "layerName" is uninitialized when you pass it to the LAYER() procedure.

 

HTH,
Raymond

 

PS - be careful copying code from Safari (my browser), and potentially other browsers, so that you don't introduce INVISIBLE characters to your code. When I copied your two line example, and then copied pieces of it to embellish my answeer, I introduced about a dozen copies of unicode character 0xFEFF. This character is invisible, unless you know how to look for it. Always filter your code through a word processor that can show INVISIBLE characters.

Edited by MullinRJ
Link to comment

Hi Raymond, 

 

thank you for your response.

I am actually writing this in Python - but it's all using VS functions.

 

Here is a snippet of my code:

for item in ExtendedGroups:
	layHand = vs.GetLayer(item)
	layName = vs.GetLName(layHand)
	vs.Layer(layName)

   	vs.SetSelect(item)
	
   	vs.Ungroup()
	vs.NameClass(TargetClass)
	vs.Group()
	vs.DSelectAll()

This is a for loop that goes through the items (which are handles to Groups) in a list - equivalent to a DYNARRAY in VS.

 

So I actually never spell out the name of the layer in the code - but if I run this on a file with a layer named 'Design Layer-1', the vs.Layer() function does generate a new layer called 'Design Layer-2'.

 

The result of the script should be that it changes the Class of Groups in the file - instead it generates as many new 'Design Layer-x'  as the number of items found in ExtendedGroups.


I can't think of ways around this problem.. but I may be completely unaware of something I should know about this??

 

PS - thanks for the heads up with invisible characters! I use BBedit and turned on my Invisibles.

Link to comment

GioPet,

   The only way I know of that Layer(), or vs.Layer(), will create another numbered layer is if the name passed to the Layer() procedure is an empty string ( i.e., vs.Layer("") ) and that would occur if the handle variable 'item' is NIL. You should put a trap in your routine to test for 'item' being NIL. Here's one way, albeit an overly simple one.

for item in ExtendedGroups:
	if (item != vs.Handle()):
		layHand = vs.GetLayer(item)
		layName = vs.GetLName(layHand)
		vs.Layer(layName)

		vs.SetSelect(item)
	
		vs.Ungroup()
		vs.NameClass(TargetClass)
		vs.Group()
		vs.DSelectAll()
	else:
		vs.AlrtDialog("item == NIL")

Raymond

Link to comment

You should also check that ExtendedGroups is indeed a list of handles. You originally mentioned using ForEachObject, which doesn’t implicitly generate a list, so there is a chance for error there. 

 

Another way to skin the cat without changing the active layer:

 

create a new group

set the group to the layer of the existing group with SetParent()

set the class of the new group

set the parent of the old group to the new group

ungroup the old group with HUngroup()

 

Link to comment

Hi and thank you both!

I found the solution in both the problems you've pointed out.

 

for future reference, here are the steps i've gone through.

The following is to work around the lack of the function SetClassN in VW versions prior 2018:

  1. Create List (or Dynarray if in VS) of Handles to Groups in the file
  2. change the Class of each Group through a for loop that takes each item in the list
  3. If the Layer of the Group is different from the Active Layer, the target layer is activated
  4. The Group is Selected, Ungrouped, Re-Grouped in the TargetClass

 

The following code creates unwanted layers as well as unexpected Groups with different results.

The issue is caused by a NIL handle creeping into the ExtendedGroup list - although I haven't figured out why this happens and its behaviour generates always different results...

ExtendedGroups = []

def BuidlList(h):
	global ExtendedGroups
	GroupLayer = vs.GetLayer(h)
	if GroupLayer != vs.ActLayer():
		ExtendedGroups.append(h)


def Script():
  
  criteria = '(T=GROUP)'
  vs.ForEachObject(BuidlList, criteria)
  
  vs.NameClass('None') #the TargetClass is be specified as intended
  
  for item in ExtendedGroups:
    layName = vs.GetLName(item)
    if layName != vs.GetLName(vs.ActLayer()):
      vs.Layer(layName)
    
    # here follows is a set of function, e.g.
    vs.SetSelect(item)
    vs.Ungroup()
    vs.Group()
    vs.DSelectAll()

Script()

 

As per Raymond indication - my logic would follow to exclude NIL items from being passed on to the for loop, thus adding these:

for item in ExtendedGroups:
  if item != None:
    # all the functions to be performed - as above
  else:
    vs.AlrtDialog('Handle to Group is NIL!')

I may be wrong, but I can't figure out why this logic fails - yet this still leads to unwanted results and additional layers...

 

The only way I got it to work is to wrap the for loop in another loop that runs for each layer in the document:

#after collecting all layer names in the document in a list named 'LayerList'

for Lnames in LayerList:
	for item in ExtendedGroups:
      if item != None:
    	# all the functions to be performed - as above
        else:
          vs.AlrtDialog('Handle to Group is NIL!')

 

Thank you again for the suggestions!!

It had become a headache..

 

 

Link to comment

Not sure if I'm following these correctly, but are you trying to create a function that sets the class of a group together with its contents?

 

here's a custom function I created prior to 2018,

def SetClassGroup_Contents(handle_to_group, className:str, descend=False):
    if vs.GetTypeN(handle_to_group) == 11: # Only work on groups TypeGroup == 11

        if descend:  # if descend parameter set then cycle through each item in group, default is set to false
            def set_class_objs_in_group(h):
                vs.SetClass(h,className)

            vs.ForEachObjectInList(set_class_objs_in_group,0,1,vs.FInGroup(handle_to_group)) # See Documentation for parameter descriptions

        vs.SetClass(handle_to_group,className) # Set Class of overall group
        vs.ReDrawAll()  # Sometimes my machine needs this to show updated attributes
        vs.ResetObject(handle_to_group) # Updates Object Info Pallette

h = vs.FSActLayer()
SetClassGroup_Contents(h,'NEW CLASS') # Use for apply to group only
SetClassGroup_Contents(h,'NEW CLASS', True) # Use for apply to group and contents

 

I guess you could then use this on ForEachObject call for all the groups you've found.

 

criteria = "(T=GROUP)"

def apply_class(h):
    classNew = "NEW CLASS"
    SetClassGroup_Contents(h,classNew,True)

vs.ForEachObject(apply_class,criteria)

 

Also, I've never come across call vs.Layer('Design Layer-1') creating another 'Design Layer-2' layer. This has never happened to me. I use the vs.Layer() call all the time, especially in Project Sharing files

 

HTH,

Tui

 

Edited by twk
Link to comment

Tui,

   I just tried your function in VW 2017 and both versions (with descend=TRUE and descend=FALSE) convert the contents of the group to the new class. 

 

vs.SetClass(), when used with a GROUP handle always changes the container and all its contents to the new class name. Have you seen it do differently, and if so, where?

 

Thanks,

Raymond

Link to comment

Here I created a custom object class:

(tested and worked in VW2016)

# save work before using

def SetClassGroup_Contents(handle_to_group, className:str, descend=False):

    class CustomObject():
        def __init__(self, handle):
            self.handle = handle

            self.__old_class = vs.GetClass(self.handle)

        @property
        def old_class(self):
            return self.__old_class

        @old_class.setter
        def old_class(self, value):
            self.__old_class = value

        @property
        def obj_class(self):
            return vs.GetClass(self.handle)

        @obj_class.setter
        def obj_class(self, value):
            vs.SetClass(self.handle, value)

        def restore_old_class(self):
            self.obj_class = self.old_class

    if vs.GetTypeN(handle_to_group) == 11: # Only work on groups TypeGroup == 11

        if not descend:  # if descend parameter set then cycle through each item in group, default is set to false
            stored_objects = [] #type: list[CustomObject]

            def set_class_objs_in_group(h):
                stored_objects.append(CustomObject(h))

            vs.ForEachObjectInList(set_class_objs_in_group,0,1,vs.FInGroup(handle_to_group)) # See Documentation for parameter descriptions

            vs.SetClass(handle_to_group,className) # Set Class of overall group

            for object in stored_objects:
                object.restore_old_class()

        else:
            vs.SetClass(handle_to_group, className)  # Set Class of overall group


        vs.ReDrawAll()  # Sometimes my machine needs this to show updated attributes
        vs.ResetObject(handle_to_group) # Updates Object Info Pallette
h = vs.FSActLayer()
SetClassGroup_Contents(h,'NewClass1') # Use for apply to group only
# SetClassGroup_Contents(h,'NEW CLASS', True) # Use for apply to group and contents

 

Link to comment
  • 1 year later...

Using part of twk's script I have tried to create a script that will sort sheet layers and their objects classes. 

 

The goal is to have all objects in the sheet layer in the following classes

       Borders, Veiwports, Groups and other objects on sheet layer = 'SheetClass'

       Viewport Annotations including components of groups with in the annotations = 'Annotations'

       Drawing Label  = 'Drawing Labels'

 

Everything works accept the components of groups within the annotations of a Viewport.

 

Any suggestions?

 

Python Script

#collect handles of selected VPs on active layer
def GetHandle(h):
	vs.SetClass(h,'SheetClass')
	if vs.GetTypeN(h) == 122:
		if vs.GetParent(h) == vs.ActLayer():
			hVP.append(h)
		
hVP = []
vs.ForEachObjectInLayer( GetHandle,0,2,0 )

#Traverse into the annotations group of selected VPs set classes
for VP in hVP:
	anno = vs.GetVPGroup(VP, 2)
	h = vs.FInGroup(anno)
	objs = [h]
	h = vs.NextObj(h)
	while h != vs.Handle(0):
		objs.append(h)
		h = vs.NextObj(h)
	for obj in objs:
		if vs.GetObjectVariableString(obj,1166) == 'Drawing Label':
			vs.SetClass(obj,'Drawing Labels')
		else:
			def SetClassGroup_Contents(handle_to_group, className:str, descend=False):

				class CustomObject():
					def __init__(self, handle):
						self.handle = handle

						self.__old_class = vs.GetClass(self.handle)

					@property
					def old_class(self):
						return self.__old_class

					@old_class.setter
					def old_class(self, value):
						self.__old_class = value

					@property
					def obj_class(self):
						return vs.GetClass(self.handle)

					@obj_class.setter
					def obj_class(self, value):
						vs.SetClass(self.handle, value)

					def restore_old_class(self):
						self.obj_class = self.old_class
			if vs.GetTypeN(handle_to_group) == 11: # Only work on groups TypeGroup == 11

				if not descend:  # if descend parameter set then cycle through each item in group, default is set to false
					stored_objects = [] #type: list[CustomObject]

					def set_class_objs_in_group(h):
						stored_objects.append(CustomObject(h))

					vs.ForEachObjectInList(set_class_objs_in_group,0,1,vs.FInGroup(obj)) # See Documentation for parameter descriptions

					vs.SetClass(handle_to_group,'annotation') # Set Class of overall group

					for object in stored_objects:
						object.restore_old_class()
			else:
				vs.SetClass(obj,'annotation') 

 

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...