@ferdinand
Just a quick update that using an event message to force update the view after creating the menus is working great.
c4d.EventAdd(c4d.EVMSG_CHANGE)
@ferdinand
Just a quick update that using an event message to force update the view after creating the menus is working great.
c4d.EventAdd(c4d.EVMSG_CHANGE)
@alexandre-dj
Here is my code. I created a BuildBufferedMenus class inheriting from threading.Thread and starting a counter running for 3 seconds.
Everytime a C4DPL_BUILDMENU message is emitted, I reset the counter to 0.
When the counter reaches 3 seconds, it builds the menus.
However, as discussed, the c4d.gui.UpdateMenus() call in my exit() function updates the menus but does not update the view. I cannot see them until I change the layout (minimize the window, change layout, or the like).
In my latest version, I added the menus_updated property flag to let the main thread know that my menus are built and that I need the layout to update. Hence my previous question about sending a message to the main thread or checking in any method occuring regularly that my menus need an update.
class BuildBufferedMenus(threading.Thread):
""" Build c4d menus introducing a delay to deal with multiple builds (R26) """
def __init__(self, max_time=3):
super().__init__()
self.max_time = max_time
self.current_time = 0
self.is_running = False
self._menus_updated = False
def build_menus(self):
""" Method called from the plugin message to start or reset the timer """
# start timer if thread not running
if not self.is_running:
self.start()
# reset timer if thread is running
else:
self.reset()
def run(self):
""" Timer loop """
self.is_running = True
while self.current_time < self.max_time:
self.current_time += 1
time.sleep(1)
# reinit timer variables and exit thread at the end
self.is_running = False
self.current_time = 0
self.exit()
def reset(self):
""" Reset Timer """
self.current_time = 0
def exit(self):
""" Exit timer """
enhanceMainMenu() # adds my custom menus
c4d.gui.UpdateMenus()
self._menus_updated = True
@property
def menus_updated(self):
return self._menus_updated
@menus_updated.setter
def menus_updated(self, value):
if not isinstance(value, bool):
raise ValueError(f'{value} should be of type bool (True or False)')
self._menus_updated = value
# create class instance
buffered_menus = BuildBufferedMenus()
def myPluginMessage(id, data):
if id==c4d.C4DPL_BUILDMENU:
buffered_menus.build_menus()
Thank you Ferdinand and sorry about breaking the forum's rules. I will be more careful in the future and open a new ticket if needed.
@ferdinand Thanks again for your help.
I managed to build our menus using a simple timer in the end, so it is waiting for the last c4d.C4DPL_BUILDMENU message before triggering the build.
I am however using a separate thread for this, and I encounter the issue you are mentionning in your answer, that is my menus are built but not showing up, as I am calling c4d.gui.UpdateMenus() from that separate thread, whereas it needs to be called from the main thread.
Is there a c4d method to send code to execute int he main thread? I can't find anything like this in the documentation. Or can I simply trigger a menu update (using a simple flag set to true when the side thread is done) from the main thread? There must be an Update() function somewhere that is run every few seconds?
edit: forked from building-menus-with-c4dpl_buildmenu-in-s26 by @ferdinand due to being off topic.
Hello Ferdinant. I'm following up on this ticket that I opened last November.
First of all thank you for your help. I am running some tests to make sure that our custom menus are built only once when starting R26. If possible, I would like to still use the C4DPL_BUILDMENU event and simply check if my menus already exist. I know all menus in C4D have their own id, so this should be an easy check.
However, I encouter a first issue:
When firing c4d.gui.GetMenuResource("M_EDITOR") to Get the whole menu of Cinema 4D (as you mention in your code here) I get a different address every time:
>>> c4d.gui.GetMenuResource("M_EDITOR")
<c4d.BaseContainer object at 0x000001B406C86580>
>>> c4d.gui.GetMenuResource("M_EDITOR")
<c4d.BaseContainer object at 0x000001B406CA6A40>
>>> c4d.gui.GetMenuResource("M_EDITOR")
<c4d.BaseContainer object at 0x000001B406C88C80>
So when I use c4d.gui.SearchMenuResource(main_menu_ressource, my_custom_menu) to check if my custom menu is part of the main menu, this always return False, as the address of the main_menu object changes.
Could you please enlighten me on this?