Maya动态窗口模块化开发:批量导入与分类标签实现问询
Hey Kenny, let's work through your two core challenges with your dynamic Maya menu—batch importing modules and organizing them into categories. This setup will keep your code clean, scalable, and easy to maintain. Here's how to do it:
1. Safe Batch Import of Modules in modList.py
We'll use Python's os and importlib modules to dynamically load all valid modules in the /modules folder, with error handling to prevent a single bad module from breaking the whole menu.
First, add this code to modList.py:
import os import importlib import maya.cmds as cmds # Global registry to store modules by their category module_registry = {} def load_modules(): """Dynamically load all valid modules in the same directory as modList.py""" # Get the path to the /modules folder (where this script lives) modules_dir = os.path.dirname(__file__) # Iterate over all files in the folder for filename in os.listdir(modules_dir): # Skip non-Python files, __init__.py, and this script itself if filename.endswith(".py") and filename not in ("__init__.py", "modList.py"): # Strip the .py extension to get the module name module_name = filename[:-3] try: # Dynamically import the module (adjust the package path if needed) # Assuming your /scripts/modularMenu is in Maya's script path module = importlib.import_module(f"modularMenu.modules.{module_name}") # Validate the module has required attributes (see section 2) if hasattr(module, "MODULE_CATEGORY") and hasattr(module, "build_ui"): # Add the module to the registry under its category if module.MODULE_CATEGORY not in module_registry: module_registry[module.MODULE_CATEGORY] = [] module_registry[module.MODULE_CATEGORY].append(module) else: print(f"Warning: Module '{module_name}' missing required attributes (MODULE_CATEGORY or build_ui)") except Exception as e: print(f"Failed to load module '{module_name}': {str(e)}")
2. Module Convention for Categorization
Each module (like mod1.py, mod2.py) needs to follow a simple, consistent convention so modList.py can recognize its category and render its UI. Here's a template for any module:
# mod1.py (example module) import maya.cmds as cmds # Required: Define the category this module belongs to MODULE_CATEGORY = "Modeling Tools" # Required: Define a function to build the module's UI elements def build_ui(parent_layout): """Build UI elements for this module, attached to the parent layout""" # Example UI: A button that triggers the module's functionality cmds.button( parent=parent_layout, label="Mesh Cleanup Tool", command=lambda _: run_mesh_cleanup() ) # Module-specific functionality def run_mesh_cleanup(): cmds.polyCleanup() print("Mesh cleanup completed!")
3. Populate the Window with Categorized Modules
Update your populateWindow() function in modList.py to use the module_registry and render UI by category:
def populateWindow(parent_layout): """Populate the main window layout with categorized modules""" # Sort categories alphabetically for consistency for category in sorted(module_registry.keys()): # Create a collapsible frame for each category frame = cmds.frameLayout( parent=parent_layout, label=category, collapsable=True, collapse=False, borderVisible=True ) # Create a layout inside the frame to hold module UI elements category_layout = cmds.columnLayout( parent=frame, adjustableColumn=True, rowSpacing=5 ) # Render each module's UI in the category for module in module_registry[category]: module.build_ui(category_layout) # Return to the parent layout to add the next category cmds.setParent(parent_layout)
4. Tie It All Together in modMenu.py
Make sure your menu window loads modules first, then populates the UI:
# modMenu.py import maya.cmds as cmds from modularMenu.modules import modList def show_modular_menu(): # Close existing window if it exists if cmds.window("modularMenuWindow", exists=True): cmds.deleteUI("modularMenuWindow") # Create the main window window = cmds.window( "modularMenuWindow", title="Dynamic Modular Menu", widthHeight=(400, 500), resizeToFitChildren=True ) main_layout = cmds.columnLayout(adjustableColumn=True, rowSpacing=10) # Load all modules first modList.load_modules() # Populate the window with categorized UI modList.populateWindow(main_layout) cmds.showWindow(window) # Run the menu when the script is executed directly if __name__ == "__main__": show_modular_menu()
Key Notes for Success
- Package Setup: Ensure
/scripts/modularMenuhas an empty__init__.pyfile to mark it as a Python package (required for importlib to find modules). - Maya Script Path: Make sure
/scriptsis in Maya's script path (you can check withcmds.internalVar(userScriptDir=True)). - Scalability: Adding new modules is as simple as dropping a new
.pyfile in/modulesthat follows theMODULE_CATEGORYandbuild_uiconvention—no changes needed tomodList.pyormodMenu.py.
Give this setup a spin, and you’ll have a robust, dynamic menu that organizes your tools automatically!
内容的提问来源于stack exchange,提问作者Kenny

