Hi,
Use MenuInitString() change checked/unchecked state of menu item,
how to get checked/unchecked state?
Thanks for any help!
Solved How to Get checked/unchecked state of menu item?
相信我,可以的!
Hello @chuanzhen,
Thank you for reaching out to us. There is no mechanism to get the state of a menu item as they are not meant to be the data layer of your app. You must store and track these values yourself; properties are a good pattern to solve such things, as you can encapsulate the GUI-DATA bindings in a very clean way with them. See end of my posting for a small example.
Cheers,
Ferdinand
An example output:
MY_DIALOG.IsFiles = False
MY_DIALOG.IsFolders = False
self._isFiles = True
self._isFolders = True
self._isFiles = False
self._isFolders = False
self._isFiles = True
The code:
"""Provides a simple example for handling checkable menu items and their state with properties
inside a GeDialog instance.
"""
import c4d
class MyDialog (c4d.gui.GeDialog):
"""Implements a dialog which encapsulates menu item states in properties.
"""
ID_MENU_DATA_FILES: int = 1000 # The ID for the "Files" menu item.
ID_MENU_DATA_FOLDERS: int = 1001 # The ID for the "Folders" menu item.
def __init__(self) -> None:
"""Initializes the dialog.
"""
self._isFiles: bool = False # The internal field for the IsFiles property.
self._isFolders: bool = False # The internal field for the IsFolders property.
super().__init__()
def CreateLayout(self) -> bool:
"""Called by Cinema 4D to populate the dialog with gadgets.
"""
# We build a very simply menu with the structure:
# Data
# +-- Files
# +-- Folders
self.MenuSubBegin("Data")
self.MenuAddString(MyDialog.ID_MENU_DATA_FILES, "Files")
self.MenuAddString(MyDialog.ID_MENU_DATA_FOLDERS, "Folders")
self.MenuSubEnd()
self.MenuFinished()
return super().CreateLayout()
def Command(self, cid: int, data: c4d.BaseContainer) -> bool:
"""Called by Cinema 4D when a gadget, including menus, has been invoked.
"""
# When one of the menu items has been invoked, we simply toggle the matching property.
if cid == MyDialog.ID_MENU_DATA_FILES:
self.IsFiles = not self.IsFiles
if cid == MyDialog.ID_MENU_DATA_FOLDERS:
self.IsFolders = not self.IsFolders
return super().Command(cid, data)
# --- The menu items realized as properties ----------------------------------------------------
@property
def IsFiles(self) -> bool:
"""Gets the "Files" state.
We just get the value from the private field.
"""
return self._isFiles
@IsFiles.setter
def IsFiles(self, value: bool) -> None:
"""Sets the "Files" state.
The setter also updates the GUI via GeDialog.MenuInitString, making sure that the properties
are always correctly reflected. In this case we also print out the new value to demonstrate
how the dialog works.
"""
if not isinstance(value, bool):
raise TypeError(value)
if self._isFiles == value:
return
self._isFiles = value
self.MenuInitString(MyDialog.ID_MENU_DATA_FILES, enabled=True, value=self._isFiles)
print (f"{self._isFiles = }")
@property
def IsFolders(self) -> bool:
"""Gets the "Folders" state.
"""
return self._isFolders
@IsFolders.setter
def IsFolders(self, value: bool) -> None:
"""Sets the "Folders" state.
"""
if not isinstance(value, bool):
raise TypeError(value)
if self._isFolders == value:
return
self._isFolders = value
self.MenuInitString(MyDialog.ID_MENU_DATA_FOLDERS, enabled=True, value=self._isFolders)
print (f"{self._isFolders = }")
# Attribute deceleration for a MyDialog instance used by main().
MY_DIALOG: MyDialog
def main():
"""Runs the example.
"""
# We are using here the global attribute hack to make the dialog work in async mode in a Script
# Manager script. Please do not use this hack in a production environment, Script Manger scripts
# should not open async dialogs, they are restricted to plugins as they can properly manage the
# lifetime of the dialog.
global MY_DIALOG
MY_DIALOG = MyDialog()
# Open the dialog in asynchronous mode.
MY_DIALOG.Open(c4d.DLG_TYPE_ASYNC, defaultw=200, defaulth=100)
# We can now either directly read and write the properties of the dialog ...
print (f"\n{MY_DIALOG.IsFiles = }")
print (f"{MY_DIALOG.IsFolders = }\n")
MY_DIALOG.IsFiles = True
# or interact via GeDialog.Command with the dialog to toggle the properties and their GUI.
MY_DIALOG.Command(MY_DIALOG.ID_MENU_DATA_FOLDERS, c4d.BaseContainer())
if __name__ == "__main__":
main()
MAXON SDK Specialist
developers.maxon.net
Hello @chuanzhen,
Thank you for reaching out to us. There is no mechanism to get the state of a menu item as they are not meant to be the data layer of your app. You must store and track these values yourself; properties are a good pattern to solve such things, as you can encapsulate the GUI-DATA bindings in a very clean way with them. See end of my posting for a small example.
Cheers,
Ferdinand
An example output:
MY_DIALOG.IsFiles = False
MY_DIALOG.IsFolders = False
self._isFiles = True
self._isFolders = True
self._isFiles = False
self._isFolders = False
self._isFiles = True
The code:
"""Provides a simple example for handling checkable menu items and their state with properties
inside a GeDialog instance.
"""
import c4d
class MyDialog (c4d.gui.GeDialog):
"""Implements a dialog which encapsulates menu item states in properties.
"""
ID_MENU_DATA_FILES: int = 1000 # The ID for the "Files" menu item.
ID_MENU_DATA_FOLDERS: int = 1001 # The ID for the "Folders" menu item.
def __init__(self) -> None:
"""Initializes the dialog.
"""
self._isFiles: bool = False # The internal field for the IsFiles property.
self._isFolders: bool = False # The internal field for the IsFolders property.
super().__init__()
def CreateLayout(self) -> bool:
"""Called by Cinema 4D to populate the dialog with gadgets.
"""
# We build a very simply menu with the structure:
# Data
# +-- Files
# +-- Folders
self.MenuSubBegin("Data")
self.MenuAddString(MyDialog.ID_MENU_DATA_FILES, "Files")
self.MenuAddString(MyDialog.ID_MENU_DATA_FOLDERS, "Folders")
self.MenuSubEnd()
self.MenuFinished()
return super().CreateLayout()
def Command(self, cid: int, data: c4d.BaseContainer) -> bool:
"""Called by Cinema 4D when a gadget, including menus, has been invoked.
"""
# When one of the menu items has been invoked, we simply toggle the matching property.
if cid == MyDialog.ID_MENU_DATA_FILES:
self.IsFiles = not self.IsFiles
if cid == MyDialog.ID_MENU_DATA_FOLDERS:
self.IsFolders = not self.IsFolders
return super().Command(cid, data)
# --- The menu items realized as properties ----------------------------------------------------
@property
def IsFiles(self) -> bool:
"""Gets the "Files" state.
We just get the value from the private field.
"""
return self._isFiles
@IsFiles.setter
def IsFiles(self, value: bool) -> None:
"""Sets the "Files" state.
The setter also updates the GUI via GeDialog.MenuInitString, making sure that the properties
are always correctly reflected. In this case we also print out the new value to demonstrate
how the dialog works.
"""
if not isinstance(value, bool):
raise TypeError(value)
if self._isFiles == value:
return
self._isFiles = value
self.MenuInitString(MyDialog.ID_MENU_DATA_FILES, enabled=True, value=self._isFiles)
print (f"{self._isFiles = }")
@property
def IsFolders(self) -> bool:
"""Gets the "Folders" state.
"""
return self._isFolders
@IsFolders.setter
def IsFolders(self, value: bool) -> None:
"""Sets the "Folders" state.
"""
if not isinstance(value, bool):
raise TypeError(value)
if self._isFolders == value:
return
self._isFolders = value
self.MenuInitString(MyDialog.ID_MENU_DATA_FOLDERS, enabled=True, value=self._isFolders)
print (f"{self._isFolders = }")
# Attribute deceleration for a MyDialog instance used by main().
MY_DIALOG: MyDialog
def main():
"""Runs the example.
"""
# We are using here the global attribute hack to make the dialog work in async mode in a Script
# Manager script. Please do not use this hack in a production environment, Script Manger scripts
# should not open async dialogs, they are restricted to plugins as they can properly manage the
# lifetime of the dialog.
global MY_DIALOG
MY_DIALOG = MyDialog()
# Open the dialog in asynchronous mode.
MY_DIALOG.Open(c4d.DLG_TYPE_ASYNC, defaultw=200, defaulth=100)
# We can now either directly read and write the properties of the dialog ...
print (f"\n{MY_DIALOG.IsFiles = }")
print (f"{MY_DIALOG.IsFolders = }\n")
MY_DIALOG.IsFiles = True
# or interact via GeDialog.Command with the dialog to toggle the properties and their GUI.
MY_DIALOG.Command(MY_DIALOG.ID_MENU_DATA_FOLDERS, c4d.BaseContainer())
if __name__ == "__main__":
main()
MAXON SDK Specialist
developers.maxon.net