Grouping text as a whole object (eventually in FeaturePyhton)

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
nic
Posts: 136
Joined: Thu Apr 18, 2019 1:14 pm
Location: France

Grouping text as a whole object (eventually in FeaturePyhton)

Post by nic »

Hello,

Here is the script:
AC_grid.FCMacro
(2.79 KiB) Downloaded 29 times

I want to create a parametric "ruler" in a 3D view. So far, I managed to do that:



ruler.png
ruler.png (64.21 KiB) Viewed 2357 times
The Ruler Lines are grouped under a App::FeaturePython and is driven by parameters as expected.
My question concern the labels. They are made using :
text_code.png
text_code.png (132.29 KiB) Viewed 2357 times
Which leads to a bunch of labels in the tree. My question is how to group all those labels under the "Ruler" FeaturePython, such as I can drive all the labels with a single parameter (like font size, color, etc...)
labels_tree.png
labels_tree.png (44.57 KiB) Viewed 2357 times
nic
Posts: 136
Joined: Thu Apr 18, 2019 1:14 pm
Location: France

Re: Grouping text as a whole object (eventually in FeaturePyhton)

Post by nic »

nic wrote: Wed Nov 17, 2021 10:14 am My question is how to group all those labels under the "Ruler" FeaturePython, such as I can drive all the labels with a single parameter (like font size, color, etc...)
Some progress on this. Using This thread, I added ``App::GroupExtensionPython`` Extension.
AC_grid2.FCMacro
(5.28 KiB) Downloaded 24 times
It correctly groups my labels under a FeaturePython object. Youhou! I can even change the font size for all my labels by using the relevant parameter in "RulerLabels".
nested.png
nested.png (46.51 KiB) Viewed 2296 times
Unfortunately, this does not survive to serialisation, despite ``__setstate__``:

Code: Select all

class RulerLabel:
    # [...]   

    def __setstate__(self, data):
        obj.addExtension("App::GroupExtensionPython")
        
    # [...]
nic
Posts: 136
Joined: Thu Apr 18, 2019 1:14 pm
Location: France

Re: Grouping text as a whole object (eventually in FeaturePyhton)

Post by nic »

OK, I think that one of the problems is the serialization.

serializing label texts will work much better:

Code: Select all

class RulerLabel:
    def __init__(self, obj):
        obj.addProperty("App::PropertyLength", "yLoc", "Aspect", "Y loc")
        obj.addProperty("App::PropertyLength", "txtOffset", "Aspect", "text Offset")
        obj.addProperty("App::PropertyLength", "txtSize", "Aspect", "text Size")
        obj.addExtension("App::GroupExtensionPython")
        obj.yLoc = 5000  # mm
        obj.txtOffset = 500  # mm
        obj.txtSize = 400  # mm
        self.labels = []
        obj.Proxy = self

    def __getstate__(self):
        return self.labels 

    def __setstate__(self, data):
        label_objs = [App.ActiveDocument.getObjectsByLabel(txt)[0] for txt in data]
        for label_obj in label_objs:
            label_obj.LinkToParent = fp
        obj.addExtension("App::GroupExtensionPython")

    def execute(self, fp):
        for x, txt in GRID.items():
            # -----------------------------------------------------------------
            pl = App.Placement()
            # rotate 45°
            pl.Rotation.Q = (0.0, 0.0, 0.3826834323650898, 0.9238795325112867)
            # search if we already have this label
            objs = App.ActiveDocument.getObjectsByLabel(txt)
            pl.Base = App.Vector(x, fp.yLoc + fp.txtOffset, 0.0)
            if not objs:
                # create label
                _text_ = Draft.make_text([txt], placement=pl, screen=False)
                _text_.ViewObject.FontSize = fp.txtSize
                _text_.Label = txt
                _text_.addProperty("App::PropertyLink", "LinkToParent")
                _text_.LinkToParent = fp
                self.labels.append(txt)
            else:
                # update label
                _text_ = objs[0]
                _text_.ViewObject.FontSize = fp.txtSize
 
Now, next problem is that when I reopen my file, I have errors :

Code: Select all

17:16:34  <string>(1)<class 'AttributeError'>: Module __main__ has no class RulerLines
17:16:34  <string>(1)<class 'AttributeError'>: Module __main__ has no class RulerLabel
17:16:34  <string>(1)<class 'AttributeError'>: Module __main__ has no class ViewProviderRulerLines
17:16:34  <string>(1)<class 'AttributeError'>: Module __main__ has no class ViewProviderRulerLabel
Those errors make sense since Those Classes are defined in my macros... This is automatically solved with importing the Macro in Python namespace:

Code: Select all

import imp
AC_grid2 = imp.load_source("AC_grid2", "/home/nic/.FreeCAD/Macro/AC_grid2.FCMacro")
So, I think I solved my issue.

Now, I realize that GroupExtensionPython was maybe not what I needed, since I would like the whole Ruler to be a single object without subtree. I'm open to any idea...
TheMarkster
Veteran
Posts: 5513
Joined: Thu Apr 05, 2018 1:53 am

Re: Grouping text as a whole object (eventually in FeaturePyhton)

Post by TheMarkster »

As an alternative to the extension if you use claimChildren() in the view provider class you can return the objects as a list that you want to have inside the tree heirarchy.

Code: Select all

    def claimChildren(self):
        if you want to claim children:
            return [list of document objects]
        else:
            return []
If you don't want the objects appearing in the tree:

for obj in myobjects:
obj.ViewObject.ShowInTree = False

Just remember to also remove them if the user deletes your fp object, especially important if they are hidden in the tree. This can be done in onDelete() of the view provider. Care should be taken to always return True so the object itself can be deleted. Presuming you have the list of objects saved as a App::PropertyLinkList named Items, this should work (untested and might be better in try/except blocks so True can always be returned):

Code: Select all

    def onDelete(self, vobj, subelements):
        if vobj.Object.Items:
            for item in vobj.Object.Items:
                FreeCAD.ActiveDocument.remove(item.Name)
        return True
nic
Posts: 136
Joined: Thu Apr 18, 2019 1:14 pm
Location: France

Re: Grouping text as a whole object (eventually in FeaturePyhton)

Post by nic »

Yes, this looks promising. I almost have it done, but face some strange recomputes issues:
almost.png
almost.png (9.01 KiB) Viewed 2208 times

Code: Select all

...
21:46:19  689.982 <App> Document.cpp(3539): Sans_nom#Text012 still touched after recompute
21:46:19  689.982 <App> Document.cpp(3539): Sans_nom#Text013 still touched after recompute
...
AC_grid4.FCMacro
(5.08 KiB) Downloaded 22 times
Thanks for your help, TheMarkster
TheMarkster
Veteran
Posts: 5513
Joined: Thu Apr 05, 2018 1:53 am

Re: Grouping text as a whole object (eventually in FeaturePyhton)

Post by TheMarkster »

Creating document objects during execute() can be problematic. One trick can be to put the object creation in another function and call it with a singleshot, which gets executed after execute() has returned.

Code: Select all

def makeSomeObject(self):
    #make the object
    #recompute

def execute(self,fp):
    from PySide import QtCore
    QtCore.QTimer().singleShot(50, self.makeSomeObject)
If you need to access the fp object inside makeSomeObject() you can create a string variable in __init__():

Code: Select all

self.fpName = obj.Name
Then in makeSomeObject():

Code: Select all

fp = FreeCAD.ActiveDocument.getObject(self.fpName)
nic
Posts: 136
Joined: Thu Apr 18, 2019 1:14 pm
Location: France

Re: Grouping text as a whole object (eventually in FeaturePyhton)

Post by nic »

TheMarkster wrote: Wed Nov 17, 2021 10:08 pm One trick can be to put the object creation in another function and call it with a singleshot, which gets executed after execute() has returned.
Yes, this works very well.
AC_grid4.FCMacro
(5.3 KiB) Downloaded 23 times


The next point was to make labels invisible. Setting the `ShownInTree` attribute to False is working well, except for the last item which remains visible with an "eye" overlay. The Forum Tree View section doesn not talk about it, and I couldn't find references elsewhere.
eye_overlay.png
eye_overlay.png (41.91 KiB) Viewed 2097 times
TheMarkster
Veteran
Posts: 5513
Joined: Thu Apr 05, 2018 1:53 am

Re: Grouping text as a whole object (eventually in FeaturePyhton)

Post by TheMarkster »

I'm not sure why that last label is still showing up in the tree.

One issue is the object is constantly recomputing. This can be solved by adding a flag:

in init()
self.inhibitRecomputes = False

in execute()
if self.inhibitRecomputes:
self.inhibitRecomputes = False
return

in _execute()
self.inhibitRecomputes = True

I'll attach the file with these changes.

If you toggle App.ActiveDocument.ShowHidden = True, and then back to False again in the python console it hides the label, but doesn't seem to work in the script. But with some experimentation it might be made to work.
Attachments
AC_grid4.FCMacro
(5.48 KiB) Downloaded 24 times
nic
Posts: 136
Joined: Thu Apr 18, 2019 1:14 pm
Location: France

Re: Grouping text as a whole object (eventually in FeaturePyhton)

Post by nic »

TheMarkster wrote: Thu Nov 18, 2021 5:32 pm in init()
self.inhibitRecomputes = False

in execute()
if self.inhibitRecomputes:
self.inhibitRecomputes = False
return

in _execute()
self.inhibitRecomputes = True
Really nice tip! Many thanks.

This last item not hidden is driving me crazy since this morning...
Post Reply