Maya工具箱安装器模板
这个模板提供了一个通用的Maya工具箱安装器,可以轻松地为你的Maya插件创建安装和卸载功能。
文件目录放在maya能访问的任意位置,不需要进行多余的拷贝工作,只需要将安装文件拖拽到maya视图即可。
说明
文件结构
└─ YourToolbox/
│
├── Install.mel
├── Install.py
│
├── Scripts/
│ └── YourToolmain.py
│
└── Icons/ (可选)
└── MainUI.png
使用步骤
复制
install.mel
和install.py
模板文件到你的工具箱目录。在
install.mel
中:- 将
$gToolboxName
这个全局变量的YourToolboxName
改为你的工具箱名称,例如BinTool
。
- 将
在
install.py
中:- 修改
TOOLBOX_NAME
为你的工具箱名称。 - 修改
TOOLBOX_VERSION
为你的工具箱版本。 - 修改
TOOLBOX_ICON
为你的工具箱图标名称。 - 修改
TOOLBOX_MAIN_MODULE
为你的工具箱主模块名称。 - 修改
TOOLBOX_HELP_URL
为你的工具箱帮助文档URL。 (QTUI模板)
- 修改
确保你的主脚本(如
YourToolmain.py
)位于Scripts
文件夹中。如果你有自定义图标,将其放在
Icons
文件夹中,并命名为MainUI.png
。
示例:
# 工具箱配置
TOOLBOX_NAME = "BinTool" # 工具箱名称
TOOLBOX_VERSION = "1.0" # 工具箱版本
TOOLBOX_ICON = "MainUI.png" # 工具箱主图标
TOOLBOX_MAIN_MODULE = "BinTool_main" # 工具箱主模块名称
TOOLBOX_HELP_URL = "https://github.com/" # 工具箱帮助文档URL (QTUI模板)
安装过程
- 下载工具包放在任意可访问位置
- 将
Install.mel
拖拽到Maya视图中。 - MEL脚本会自动执行并调用Python脚本。
- Python脚本创建安装对话框,用户可以选择安装或卸载。
- 安装过程会:
- 创建.mod文件
- 创建Maya架子(shelf)和按钮
自定义
你可以根据需要修改install.py
中的以下部分:
create_mod_file()
: 自定义.mod文件的内容install_toolbox()
: 添加额外的安装步骤uninstall_toolbox()
: 添加额外的卸载步骤InstallDialog
: 自定义安装对话框的外观和行为
注意事项
- 确保所有路径使用正斜杠(/)而不是反斜杠(\)。
- 测试安装和卸载过程,确保它们在不同的Maya版本中都能正常工作。
- 考虑添加错误处理和日志记录,以便于调试。
示例使用
- 将模板文件复制到你的工具箱目录。
- 按照上述步骤进行必要的修改。
- 将修改后的
Install.mel
拖拽到Maya中以启动安装过程。
这个模板提供了一个良好的起点,你可以根据你的具体需求进行进一步的定制和扩展。
脚本功能概述
这个脚本的主要功能包括:
- 创建.mod文件,使Maya能够识别和加载插件。
- 设置必要的路径和环境。
- 在Maya中创建一个新的架子(shelf)和按钮,用于启动工具箱。
- 提供安装和卸载功能。
- 创建一个用户界面,让用户可以选择安装或卸载。
特殊Maya相关函数说明
一些可能看起来奇怪的部分包括:
mel.eval('$tmpVar=$gShelfTopLevel')
:
这是使用MEL(Maya嵌入式语言)来获取顶级架子布局的引用。使用f-string创建的
command
字符串:
这是一个多行字符串,包含了在Maya中执行工具箱的Python代码。cmds.shelfButton()
:
这个函数用于在Maya的架子上创建一个新按钮。
这些部分可能看起来有些奇怪,但它们是与Maya API交互所必需的。
安装器模板代码
以下是安装器的核心代码模板。这些模板提供了基本的安装、卸载和用户界面功能。您可以根据自己的需求进行修改和扩展。
提供了两种风格的安装窗口
// UTF-8
// Encoding: UTF-8
// 全局变量定义工具名称
global string $gToolboxName = "HUGTools";
global string $gInstallProcName;
global proc string getInstallProcName()
{
global string $gToolboxName;
return "install" + $gToolboxName;
}
global proc installHUGTools()
{
global string $gInstallProcName;
$gInstallProcName = getInstallProcName();
string $scriptPath = `whatIs $gInstallProcName`;
string $dirPath = `substring $scriptPath 25 (size($scriptPath))`;
$dirPath = `dirname $dirPath`;
string $pythonPath = $dirPath + "/install.py";
$pythonPath = substituteAllString($pythonPath, "\\", "/");
python("import os, sys; sys.path.append(os.path.dirname(r'" + $pythonPath + "')); exec(open(r'" + $pythonPath + "', encoding='utf-8').read())");
}
// 设置安装过程名称
$gInstallProcName = getInstallProcName();
// 使用全局变量调用函数
eval($gInstallProcName + "()");
import os
import sys
import maya.cmds as cmds
import maya.mel as mel
# 常量
TOOLBOX_NAME = "YourToolboxName" # 按钮工具名称
TOOLBOX_VERSION = "1.0" # 版本号
TOOLBOX_ICON = "MainUI.png" # 创建按钮的图标
TOOLBOX_MAIN_MODULE = "YourToolmain" # 主模块名称
def get_script_path():
# 使用 MEL 命令获取脚本路径
mel_command = f'whatIs "{TOOLBOX_NAME}"'
result = mel.eval(mel_command)
if result.startswith("Mel procedure found in: "):
return os.path.dirname(result.split(": ", 1)[1])
# 如果 MEL 方法失败,尝试通过 Python 路径查找
for path in sys.path:
possible_path = os.path.join(path, "install.py")
if os.path.exists(possible_path):
return os.path.dirname(possible_path)
# 如果都失败,返回当前工作目录
return os.getcwd()
def create_mod_file():
current_path = get_script_path()
maya_app_dir = cmds.internalVar(userAppDir=True)
modules_dir = os.path.join(maya_app_dir, "modules")
if not os.path.exists(modules_dir):
os.makedirs(modules_dir)
mod_content = f"""+ {TOOLBOX_NAME} {TOOLBOX_VERSION} {current_path}
scripts: {os.path.join(current_path, "Scripts")}
"""
mod_file_path = os.path.join(modules_dir, f"{TOOLBOX_NAME}.mod")
# 检查是否已存在相同内容的 mod 文件
if os.path.exists(mod_file_path):
with open(mod_file_path, 'r') as f:
existing_content = f.read()
if existing_content.strip() == mod_content.strip():
print(f"已存在正确的 {TOOLBOX_NAME}.mod 文件,无需更新")
return
# 创建或更新 mod 文件
with open(mod_file_path, "w") as f:
f.write(mod_content)
print(f"已创建/更新 {TOOLBOX_NAME}.mod 文件")
def clean_existing_buttons():
if cmds.shelfLayout(TOOLBOX_NAME, exists=True):
buttons = cmds.shelfLayout(TOOLBOX_NAME, query=True, childArray=True) or []
for btn in buttons:
if cmds.shelfButton(btn, query=True, exists=True):
label = cmds.shelfButton(btn, query=True, label=True)
if label == TOOLBOX_NAME:
cmds.deleteUI(btn)
print(f"已删除现有的 {TOOLBOX_NAME} 按钮: {btn}")
def install_toolbox(new_shelf=True):
current_path = get_script_path()
scripts_path = os.path.join(current_path, "Scripts")
create_mod_file()
if not os.path.exists(scripts_path):
os.makedirs(scripts_path)
main_script = os.path.join(scripts_path, f"{TOOLBOX_NAME}_main.py")
if not os.path.exists(main_script):
cmds.error(f"错误:{TOOLBOX_NAME}_main.py 文件不存在于 {main_script}")
return
if scripts_path not in sys.path:
sys.path.insert(0, scripts_path)
shelf_layout = mel.eval('$tmpVar=$gShelfTopLevel')
if new_shelf:
if not cmds.shelfLayout(TOOLBOX_NAME, exists=True):
cmds.shelfLayout(TOOLBOX_NAME, parent=shelf_layout)
parent = TOOLBOX_NAME
else:
current_shelf = cmds.tabLayout(shelf_layout, query=True, selectTab=True)
parent = current_shelf
clean_existing_buttons()
# 修改图标路径的部分
icon_path = os.path.join(current_path, "Icons", TOOLBOX_ICON)
if not os.path.exists(icon_path):
print(f"警告:自定义图标文件 '{icon_path}' 不存在,将使用默认图标。")
icon_path = "commandButton.png"
else:
print(f"使用自定义图标: {icon_path}")
command = f"""
import sys
import os
current_path = r'{current_path}'
scripts_path = os.path.join(current_path, 'Scripts')
if scripts_path not in sys.path:
sys.path.insert(0, scripts_path)
os.chdir(scripts_path)
try:
import {TOOLBOX_NAME}_main
{TOOLBOX_NAME}_main.show()
except ImportError as e:
print("Error importing {TOOLBOX_NAME}:", str(e))
print("Current path:", current_path)
print("Scripts path:", scripts_path)
print("sys.path:", sys.path)
print("Contents of Scripts folder:", os.listdir(scripts_path))
"""
cmds.shelfButton(
parent=parent,
image1=icon_path,
label=TOOLBOX_NAME,
command=command,
sourceType="python",
annotation=f"{TOOLBOX_NAME} v{TOOLBOX_VERSION}",
noDefaultPopup=True,
style="iconOnly"
)
cmds.confirmDialog(title="安装成功", message=f"{TOOLBOX_NAME} 已成功安装!", button=["确定"])
# 验证安装- 导入 main.py
try:
import_module = __import__(TOOLBOX_MAIN_MODULE)
print(f"{TOOLBOX_NAME} 模块导入成功")
except ImportError as e:
print(f"无法导入 {TOOLBOX_NAME} 模块: {e}")
print("sys.path:", sys.path)
print("Scripts 文件夹内容:", os.listdir(scripts_path))
def uninstall_toolbox():
maya_app_dir = cmds.internalVar(userAppDir=True)
mod_file_path = os.path.join(maya_app_dir, "modules", f"{TOOLBOX_NAME}.mod")
if os.path.exists(mod_file_path):
os.remove(mod_file_path)
print(f"已删除 {TOOLBOX_NAME}.mod 文件")
if cmds.shelfLayout(TOOLBOX_NAME, exists=True):
cmds.deleteUI(TOOLBOX_NAME, layout=True)
print(f"已删除 {TOOLBOX_NAME} 工具架")
# 检查所有工具架,删除任何 YourToolboxName 按钮
all_shelves = cmds.shelfTabLayout("ShelfLayout", query=True, childArray=True)
for shelf in all_shelves:
shelf_buttons = cmds.shelfLayout(shelf, query=True, childArray=True) or []
for btn in shelf_buttons:
if cmds.shelfButton(btn, query=True, exists=True):
label = cmds.shelfButton(btn, query=True, label=True)
if label == TOOLBOX_NAME:
cmds.deleteUI(btn)
print(f"已删除 {TOOLBOX_NAME} 按钮: {btn}")
# 从 sys.path 中移除 Scripts 路径
current_path = get_script_path()
scripts_path = os.path.join(current_path, "Scripts")
if scripts_path in sys.path:
sys.path.remove(scripts_path)
print(f"已从 sys.path 中移除 {scripts_path}")
cmds.confirmDialog(title="卸载成功", message=f"{TOOLBOX_NAME} 已成功卸载!", button=["确定"])
class InstallDialog(object):
def __init__(self):
self.window = f"{TOOLBOX_NAME}Installer"
self.title = f"{TOOLBOX_NAME} 安装程序"
self.size = (350, 150) # 增加高度以容纳新的选项
if cmds.window(self.window, exists=True):
cmds.deleteUI(self.window, window=True)
self.window = cmds.window(self.window, title=self.title, widthHeight=self.size)
cmds.columnLayout(adjustableColumn=True)
# 添加复选框
self.new_shelf_checkbox = cmds.checkBox(label="创建新工具架", value=True)
cmds.button(label=f"安装 {TOOLBOX_NAME}", command=self.install)
cmds.button(label=f"卸载 {TOOLBOX_NAME}", command=self.uninstall)
cmds.showWindow()
def install(self, *args):
new_shelf = cmds.checkBox(self.new_shelf_checkbox, query=True, value=True)
result = cmds.confirmDialog(
title="确认安装",
message=f"确定要安装 {TOOLBOX_NAME} 吗?" + ("(将创建新工具架)" if new_shelf else "(将添加到当前工具架)"),
button=['是', '否'],
defaultButton='是',
cancelButton='否',
dismissString='否'
)
if result == '是':
cmds.deleteUI(self.window, window=True)
install_toolbox(new_shelf)
def uninstall(self, *args):
result = cmds.confirmDialog(
title="确认卸载",
message=f"确定要卸载 {TOOLBOX_NAME} 吗?",
button=['是', '否'],
defaultButton='是',
cancelButton='否',
dismissString='否'
)
if result == '是':
cmds.deleteUI(self.window, window=True)
uninstall_toolbox()
if __name__ == "__main__":
InstallDialog()
import os
import sys
import maya.cmds as cmds
import maya.mel as mel
from PySide2 import QtWidgets, QtGui, QtCore
import maya.OpenMayaUI as omui
from shiboken2 import wrapInstance
import webbrowser
# 工具箱配置
TOOLBOX_NAME = "YourToolboxName" # 工具箱名称
TOOLBOX_VERSION = "1.0" # 工具箱版本
TOOLBOX_ICON = "MainUI.png" # 工具箱主图标
TOOLBOX_MAIN_MODULE = "YourToolmain" # 工具箱主模块名称
TOOLBOX_HELP_URL = "https://github.com/" # 工具箱帮助文档URL
def maya_main_window():
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
class RoundedButton(QtWidgets.QPushButton):
def __init__(self, text):
super(RoundedButton, self).__init__(text)
self.setStyleSheet(
"""
QPushButton {
background-color: #D0D0D0;
color: #303030;
border-radius: 10px;
padding: 5px;
font-weight: bold;
}
QPushButton:hover {
background-color: #E0E0E0;
}
QPushButton:pressed {
background-color: #C0C0C0;
}
"""
)
class InstallDialog(QtWidgets.QDialog):
def __init__(self, parent=maya_main_window()):
super(InstallDialog, self).__init__(parent)
self.setWindowTitle(f"{TOOLBOX_NAME} 安装程序")
self.setFixedSize(220, 120)
self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowContextHelpButtonHint)
# 设置窗口图标
icon_path = os.path.join(get_script_path(), "Icons", TOOLBOX_ICON)
if os.path.exists(icon_path):
self.setWindowIcon(QtGui.QIcon(icon_path))
else:
print(f"警告:图标文件 '{icon_path}' 不存在。")
self.create_widgets()
self.create_layouts()
self.create_connections()
def create_widgets(self):
self.new_shelf_toggle = QtWidgets.QCheckBox("创建新工具架")
self.new_shelf_toggle.setChecked(False) # 默认不选中
self.install_button = RoundedButton("安装 " + TOOLBOX_NAME)
self.uninstall_button = RoundedButton("卸载 " + TOOLBOX_NAME)
def create_layouts(self):
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setContentsMargins(10, 2, 10, 5)
main_layout.setSpacing(5)
toggle_layout = QtWidgets.QHBoxLayout()
toggle_layout.setSpacing(5)
# 创建开关按钮
self.toggle_button = QtWidgets.QPushButton()
self.toggle_button.setCheckable(True)
self.toggle_button.setChecked(False) # 默认不选中
self.toggle_button.setFixedSize(20, 20)
self.toggle_button.setStyleSheet(
"""
QPushButton {
border: none;
background-image: url(:/UVTkVerticalToggleOn.png);
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
QPushButton:checked {
background-image: url(:/UVTkVerticalToggleOff.png);
}
"""
)
label = QtWidgets.QLabel("创建新工具架")
label.setStyleSheet("font-size: 11px; padding: 0px; margin: 0px;")
toggle_layout.addWidget(self.toggle_button)
toggle_layout.addWidget(label)
toggle_layout.addStretch()
main_layout.addLayout(toggle_layout)
main_layout.addWidget(self.install_button)
main_layout.addWidget(self.uninstall_button)
self.install_button.setFixedHeight(30)
self.uninstall_button.setFixedHeight(30)
def create_connections(self):
self.install_button.clicked.connect(self.install)
self.uninstall_button.clicked.connect(self.uninstall)
def event(self, event):
if event.type() == QtCore.QEvent.EnterWhatsThisMode:
QtWidgets.QWhatsThis.leaveWhatsThisMode()
self.open_help_url()
return True
return QtWidgets.QDialog.event(self, event)
def open_help_url(self):
webbrowser.open(TOOLBOX_HELP_URL)
QtWidgets.QApplication.restoreOverrideCursor() # 恢复正常的鼠标光标
def closeEvent(self, event):
# 直接调用父类的closeEvent
super(InstallDialog, self).closeEvent(event)
# 添加一个新方法来处理帮助请求
def helpEvent(self, event):
self.open_help_url()
event.accept()
def create_styled_message_box(self, title, text):
msg_box = QtWidgets.QMessageBox(self)
msg_box.setWindowTitle(title)
msg_box.setText(text)
msg_box.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
# 设置按钮样式
button_style = """
QPushButton {
background-color: #B0B0B0;
color: #303030;
border-radius: 10px;
padding: 5px;
font-weight: bold;
min-width: 80px;
}
QPushButton:hover {
background-color: #C0C0C0;
}
QPushButton:pressed {
background-color: #A0A0A0;
}
"""
for button in msg_box.buttons():
button.setStyleSheet(button_style)
return msg_box
def install(self):
new_shelf = self.toggle_button.isChecked()
msg_box = self.create_styled_message_box(
"确认安装",
f"确定要安装 {TOOLBOX_NAME} 吗?" + ("(将创建新工具架)" if new_shelf else "(将添加到当前工具架)")
)
result = msg_box.exec_()
if result == QtWidgets.QMessageBox.Yes:
self.close()
install_toolbox(new_shelf)
def uninstall(self):
msg_box = self.create_styled_message_box(
"确认卸载",
f"确定要卸载 {TOOLBOX_NAME} 吗?"
)
result = msg_box.exec_()
if result == QtWidgets.QMessageBox.Yes:
self.close()
uninstall_toolbox()
def get_script_path():
# 使用 MEL 命令获取脚本路径
mel_command = f'whatIs "{TOOLBOX_NAME}"'
result = mel.eval(mel_command)
if result.startswith("Mel procedure found in: "):
return os.path.dirname(result.split(": ", 1)[1])
# 如果 MEL 方法失败,尝试通过 Python 路径查找
for path in sys.path:
possible_path = os.path.join(path, "install.py")
if os.path.exists(possible_path):
return os.path.dirname(possible_path)
# 如果都失败,返回当前工作目录
return os.getcwd()
def create_mod_file():
current_path = get_script_path()
maya_app_dir = cmds.internalVar(userAppDir=True)
modules_dir = os.path.join(maya_app_dir, "modules")
if not os.path.exists(modules_dir):
os.makedirs(modules_dir)
mod_content = f"""+ {TOOLBOX_NAME} {TOOLBOX_VERSION} {current_path}
scripts: {os.path.join(current_path, "Scripts")}
"""
mod_file_path = os.path.join(modules_dir, f"{TOOLBOX_NAME}.mod")
# 检查是否已存在相同内容的 mod 文件
if os.path.exists(mod_file_path):
with open(mod_file_path, 'r') as f:
existing_content = f.read()
if existing_content.strip() == mod_content.strip():
print(f"已存在正确的 {TOOLBOX_NAME}.mod 文件,无需更新")
return
# 创建或更新 mod 文件
with open(mod_file_path, "w") as f:
f.write(mod_content)
print(f"已创建/更新 {TOOLBOX_NAME}.mod 文")
def clean_existing_buttons():
if cmds.shelfLayout(TOOLBOX_NAME, exists=True):
buttons = cmds.shelfLayout(TOOLBOX_NAME, query=True, childArray=True) or []
for btn in buttons:
if cmds.shelfButton(btn, query=True, exists=True):
label = cmds.shelfButton(btn, query=True, label=True)
if label == TOOLBOX_NAME:
cmds.deleteUI(btn)
print(f"已删除现有的 {TOOLBOX_NAME} 按钮: {btn}")
def install_toolbox(new_shelf=True):
current_path = get_script_path()
scripts_path = os.path.join(current_path, "Scripts")
create_mod_file()
if not os.path.exists(scripts_path):
os.makedirs(scripts_path)
main_script = os.path.join(scripts_path, f"{TOOLBOX_NAME}_main.py")
if not os.path.exists(main_script):
cmds.error(f"错误:{TOOLBOX_NAME}_main.py 文件不存在于 {main_script}")
return
if scripts_path not in sys.path:
sys.path.insert(0, scripts_path)
shelf_layout = mel.eval('$tmpVar=$gShelfTopLevel')
if new_shelf:
if not cmds.shelfLayout(TOOLBOX_NAME, exists=True):
cmds.shelfLayout(TOOLBOX_NAME, parent=shelf_layout)
parent = TOOLBOX_NAME
else:
current_shelf = cmds.tabLayout(shelf_layout, query=True, selectTab=True)
parent = current_shelf
clean_existing_buttons()
# 更新图标路径
icon_path = os.path.join(current_path, "Icons", TOOLBOX_ICON)
if not os.path.exists(icon_path):
print(f"警告:自定义图标文件 '{icon_path}' 不存在,将使用默认图标。")
icon_path = "commandButton.png"
else:
print(f"使用自定义图标: {icon_path}")
command = f"""
import sys
import os
current_path = r'{current_path}'
scripts_path = os.path.join(current_path, 'Scripts')
if scripts_path not in sys.path:
sys.path.insert(0, scripts_path)
os.chdir(scripts_path)
try:
import {TOOLBOX_NAME}_main
{TOOLBOX_NAME}_main.show()
except ImportError as e:
print("Error importing {TOOLBOX_NAME}:", str(e))
print("Current path:", current_path)
print("Scripts path:", scripts_path)
print("sys.path:", sys.path)
print("Contents of Scripts folder:", os.listdir(scripts_path))
"""
cmds.shelfButton(
parent=parent,
image1=icon_path,
label=TOOLBOX_NAME,
command=command,
sourceType="python",
annotation=f"{TOOLBOX_NAME} v{TOOLBOX_VERSION}",
noDefaultPopup=True,
style="iconOnly"
)
# 创建安装成功的消息框
msg_box = QtWidgets.QMessageBox()
msg_box.setWindowTitle("安装成功")
msg_box.setText(f"{TOOLBOX_NAME} 已成功安装!")
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
# 设置按钮样式
button_style = """
QPushButton {
background-color: #B0B0B0;
color: #303030;
border-radius: 10px;
padding: 5px;
font-weight: bold;
min-width: 80px;
}
QPushButton:hover {
background-color: #C0C0C0;
}
QPushButton:pressed {
background-color: #A0A0A0;
}
"""
for button in msg_box.buttons():
button.setStyleSheet(button_style)
msg_box.exec_()
# 验证安装
try:
import_module = __import__(TOOLBOX_MAIN_MODULE)
print(f"{TOOLBOX_NAME} 模块导入成功")
except ImportError as e:
print(f"无法导入 {TOOLBOX_NAME} 模块: {e}")
print("sys.path:", sys.path)
print("Scripts 文件夹内容:", os.listdir(scripts_path))
def uninstall_toolbox():
maya_app_dir = cmds.internalVar(userAppDir=True)
mod_file_path = os.path.join(maya_app_dir, "modules", f"{TOOLBOX_NAME}.mod")
if os.path.exists(mod_file_path):
os.remove(mod_file_path)
print(f"已删除 {TOOLBOX_NAME}.mod 件")
if cmds.shelfLayout(TOOLBOX_NAME, exists=True):
cmds.deleteUI(TOOLBOX_NAME, layout=True)
print(f"删除 {TOOLBOX_NAME} 工具架")
# 检查所有工具架,删除任何 YourToolboxName 按钮
all_shelves = cmds.shelfTabLayout("ShelfLayout", query=True, childArray=True)
for shelf in all_shelves:
shelf_buttons = cmds.shelfLayout(shelf, query=True, childArray=True) or []
for btn in shelf_buttons:
if cmds.shelfButton(btn, query=True, exists=True):
label = cmds.shelfButton(btn, query=True, label=True)
if label == TOOLBOX_NAME:
cmds.deleteUI(btn)
print(f"已删除 {TOOLBOX_NAME} 按钮: {btn}")
# 从 sys.path 中移除 Scripts 路径
current_path = get_script_path()
scripts_path = os.path.join(current_path, "Scripts")
if scripts_path in sys.path:
sys.path.remove(scripts_path)
print(f"已从 sys.path 中移除 {scripts_path}")
# 创建卸载成功的消息框
msg_box = QtWidgets.QMessageBox()
msg_box.setWindowTitle("卸载成功")
msg_box.setText(f"{TOOLBOX_NAME} 已成功卸载!")
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
# 设置按钮样式
button_style = """
QPushButton {
background-color: #B0B0B0;
color: #303030;
border-radius: 10px;
padding: 5px;
font-weight: bold;
min-width: 80px;
}
QPushButton:hover {
background-color: #C0C0C0;
}
QPushButton:pressed {
background-color: #A0A0A0;
}
"""
for button in msg_box.buttons():
button.setStyleSheet(button_style)
msg_box.exec_()
if __name__ == "__main__":
try:
install_dialog.close()
install_dialog.deleteLater()
except:
pass
install_dialog = InstallDialog()
# 移除这行,因为我们不再使用helpRequested信号
# install_dialog.helpRequested.connect(install_dialog.helpRequested)
install_dialog.show()
如何添加新工具
创建新工具文件
要添加新工具,请按照以下步骤操作:
比如你有一个新工具,这个工具名称叫 NewTool.py ,并且在scripts文件夹下,文件结构如下:
└─YourToolbox/
│
├── Install.mel
├── Install.py
│
├── Scripts/
│ └── NewTool/
│ └── NewTool.py
│ └── more/ (可选)
│ └── xxxxx.py
│ └── YourToolmain.py
│
└── Icons/ (可选)
└── MainUI.png
准备新工具的UI类
NewTool.py 文件内容如下:
使用QT api创建的UI
# 导入api
import maya.cmds as cmds
from PySide2 import QtWidgets, QtCore, QtGui
# =============== NewTool-UI ===============
class NewToolUI(QtWidgets.QWidget):
def __init__(self, parent=None):
super(NewToolUI, self).__init__(parent)
#按钮
self.btn = QtWidgets.QPushButton("按钮")
#布局-实际显示的按钮布局
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.btn)
#函数与按钮的连接
self.btn.clicked.connect(self.btn_click)
#功能函数
def btn_click(self):
print("按钮被点击了")
# UI函数
def show():
global tool_window_ui
try:
tool_window_ui.close()
tool_window_ui.deleteLater()
except:
pass
tool_window_ui = NewToolUI()
tool_window_ui.show()
if __name__ == "__main__":
show()
在主窗口中集成新工具
以下是一个简化的主窗口示例,展示了一个基本的工具窗口:
import importlib
import maya.cmds as cmds
from PySide2 import QtWidgets, QtCore, QtGui
# 在文件顶部导入新工具模块如果有文件夹则在前方加文件夹路径如下
import Scripts.NewTool as NewTool #导入上文创建的NewTool.py
# =============== MainWindow - UI===============
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setWindowTitle("工具箱")
self.setMinimumWidth(200)
# 创建按钮
self.tool1_btn = QtWidgets.QPushButton("工具1")
self.tool2_btn = QtWidgets.QPushButton("工具2")
# 创建布局
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tool1_btn)
layout.addWidget(self.tool2_btn)
# 连接信号
self.tool1_btn.clicked.connect(self.open_tool1)
self.tool2_btn.clicked.connect(self.open_tool2)
# 创建的函数来打开新工具
def open_tool1(self):
importlib.reload(NewTool) # 重新加载NewTool新工具模块
NewTool.show() # 调用文件顶部导入的NewTool.py新工具的show函数. 格式为 名称+show()函数
def open_tool2(self):
print("打开工具2")
def show():
global main_window # 声明全局变量以管理主窗口实例
try:
main_window.close() # 尝试关闭已存在的窗口
main_window.deleteLater() # 删除旧的窗口实例,释放资源
except:
pass # 如果窗口不存在,则忽略错误
main_window = MainWindow() # 创建新的主窗口实例
main_window.show() # 显示新创建的主窗口
if __name__ == "__main__":
show() # 如果直接运行此脚本,则显示主窗口
故障排除和常见问题
问题:安装后无法在Maya中看到工具架
- 解决方案:
- 确保Maya的脚本路径正确设置
- 重启Maya
- 解决方案:
问题:安装过程中出现权限错误
- 解决方案:
- 以管理员身份运行Maya
- 检查文件夹权限设置
- 解决方案:
问题:工具在某些Maya版本中不工作
- 解决方案:
- 检查代码兼容性
- 针对不同版本进行代码调整
- 解决方案:
问题:卸载后仍有残留文件
- 解决方案:
- 手动检查并删除.mod文件
- 清理Maya用户目录中的相关文件
- 解决方案:
如遇到其他问题,请检查Maya的脚本编辑器输出,可能会提供有用的错误信息。