705 lines
25 KiB
Python
705 lines
25 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Tool - Module Reload Tool
|
||
提供插件的模块重载功能,支持热更新
|
||
|
||
用法说明:
|
||
1. 在Maya中直接运行:
|
||
import scripts.ReloadModules
|
||
scripts.ReloadModules.main()
|
||
|
||
2. 从命令行重新加载所有模块:
|
||
import scripts.ReloadModules
|
||
scripts.ReloadModules.reload_all()
|
||
|
||
3. 重新加载特定模块:
|
||
import scripts.ReloadModules
|
||
scripts.ReloadModules.ModuleReloader.reload_module('module_name')
|
||
|
||
4. 在开发过程中使用:
|
||
- 当修改了代码后,运行此模块可以热更新所有更改
|
||
- 无需重启Maya即可测试新功能
|
||
- 支持UI和命令行两种方式
|
||
|
||
注意事项:
|
||
- 某些深度依赖的模块可能需要手动重启Maya
|
||
- 如果遇到导入错误,请检查模块路径是否正确
|
||
- 重新加载可能不会影响已经创建的对象实例
|
||
"""
|
||
|
||
#===================================== 导入模块 =====================================
|
||
import maya.cmds as cmds
|
||
import pymel.core as pm
|
||
import maya.mel as mel
|
||
from maya import OpenMayaUI as omui
|
||
import webbrowser
|
||
import subprocess
|
||
import importlib
|
||
import traceback
|
||
import sys
|
||
import os
|
||
import pkgutil
|
||
|
||
try:
|
||
from Qt import QtWidgets, QtCore, QtGui
|
||
from Qt.QtCompat import wrapInstance
|
||
HAS_QT = True
|
||
print("成功导入Qt模块 (使用Qt.py兼容层)")
|
||
except ImportError:
|
||
HAS_QT = False
|
||
print("警告: 无法导入Qt模块,UI功能将不可用")
|
||
|
||
#===================================== 公共函数 =====================================
|
||
def clean_pycache(root_dir):
|
||
"""
|
||
删除给定根目录下的所有 __pycache__ 目录和 .pyc 文件
|
||
|
||
Args:
|
||
root_dir (str): 要搜索 __pycache__ 文件夹和 .pyc 文件的根目录
|
||
|
||
Returns:
|
||
int: 已删除的 __pycache__ 目录和 .pyc 文件数量
|
||
"""
|
||
count = 0
|
||
try:
|
||
# 首先确保目录存在
|
||
if not os.path.exists(root_dir) or not os.path.isdir(root_dir):
|
||
print(f"警告: 目录不存在或不是一个目录: {root_dir}")
|
||
return count
|
||
|
||
print(f"清理目录中的 __pycache__: {root_dir}")
|
||
|
||
# 收集所有需要删除的路径,避免在遍历时修改目录结构
|
||
pycache_dirs = []
|
||
pyc_files = []
|
||
|
||
# 首先收集所有 __pycache__ 目录和 .pyc 文件
|
||
for root, dirs, files in os.walk(root_dir):
|
||
# 收集 __pycache__ 目录
|
||
if "__pycache__" in dirs:
|
||
pycache_path = os.path.join(root, "__pycache__")
|
||
pycache_dirs.append(pycache_path)
|
||
|
||
# 收集 .pyc 文件
|
||
for file in files:
|
||
if file.endswith(".pyc"):
|
||
file_path = os.path.join(root, file)
|
||
pyc_files.append(file_path)
|
||
|
||
# 删除 __pycache__ 目录和 .pyc 文件
|
||
for pycache_path in pycache_dirs:
|
||
try:
|
||
if os.path.exists(pycache_path):
|
||
for root, dirs, files in os.walk(pycache_path, topdown=False):
|
||
for file in files:
|
||
os.remove(os.path.join(root, file))
|
||
for dir in dirs:
|
||
os.rmdir(os.path.join(root, dir))
|
||
os.rmdir(pycache_path)
|
||
count += 1
|
||
except Exception as e:
|
||
print(f"无法删除 {pycache_path}: {str(e)}")
|
||
|
||
# 删除 .pyc 文件
|
||
for file_path in pyc_files:
|
||
try:
|
||
if os.path.exists(file_path):
|
||
os.remove(file_path)
|
||
count += 1
|
||
except Exception as e:
|
||
print(f"无法删除 {file_path}: {str(e)}")
|
||
|
||
except Exception as error:
|
||
print(f"清理 __pycache__ 目录时出错: {str(error)}")
|
||
traceback.print_exc()
|
||
|
||
return count
|
||
|
||
|
||
# 获取 Maya 主窗口函数
|
||
def getMayaMainWindow():
|
||
"""获取 Maya 主窗口"""
|
||
if HAS_QT:
|
||
mainWindowPtr = omui.MQtUtil.mainWindow()
|
||
return wrapInstance(int(mainWindowPtr), QtWidgets.QWidget)
|
||
return None
|
||
|
||
#===================================== 导入模块 =====================================
|
||
# 本地化
|
||
try:
|
||
from scripts.ui import localization
|
||
LANG = localization.LANG
|
||
except ImportError:
|
||
LANG = {}
|
||
print("警告: 无法导入本地化模块,将使用默认语言")
|
||
|
||
# 设置工具路径
|
||
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
if TOOL_PATH not in sys.path:
|
||
sys.path.insert(0, TOOL_PATH)
|
||
|
||
# 设置脚本路径
|
||
SCRIPTS_PATH = os.path.dirname(os.path.abspath(__file__))
|
||
if SCRIPTS_PATH not in sys.path:
|
||
sys.path.insert(0, SCRIPTS_PATH)
|
||
|
||
#===================================== IMPORT MODULES =====================================
|
||
# 导入主配置 - 简化版
|
||
def import_main_config():
|
||
"""尝试导入主配置文件"""
|
||
global TOOL_NAME, TOOL_VERSION, TOOL_AUTHOR, TOOL_PATH, SCRIPTS_PATH
|
||
global UI_PATH, STYLE_FILE, ICONS_PATH, ASSETS_PATH, DNA_FILE_PATH, DNA_IMG_PATH
|
||
global TOOL_YEAR, TOOL_MOD_FILENAME, TOOL_LANG, TOOL_WSCL_NAME, TOOL_HELP_URL
|
||
global TOOL_MAIN_SCRIPT, TOOL_COMMAND_ICON, TOOL_ICON
|
||
|
||
# 尝试导入配置
|
||
try:
|
||
import config
|
||
importlib.reload(config)
|
||
|
||
TOOL_NAME = config.TOOL_NAME
|
||
TOOL_VERSION = config.TOOL_VERSION
|
||
TOOL_AUTHOR = config.TOOL_AUTHOR
|
||
TOOL_YEAR = config.TOOL_YEAR
|
||
TOOL_MOD_FILENAME = config.TOOL_MOD_FILENAME
|
||
TOOL_LANG = config.TOOL_LANG
|
||
TOOL_WSCL_NAME = config.TOOL_WSCL_NAME
|
||
TOOL_HELP_URL = config.TOOL_HELP_URL
|
||
TOOL_PATH = config.TOOL_PATH
|
||
SCRIPTS_PATH = config.SCRIPTS_PATH
|
||
TOOL_MAIN_SCRIPT = config.TOOL_MAIN_SCRIPT
|
||
UI_PATH = config.UI_PATH
|
||
STYLE_FILE = config.STYLE_FILE
|
||
ICONS_PATH = config.ICONS_PATH
|
||
TOOL_ICON = config.TOOL_ICON
|
||
ASSETS_PATH = config.ASSETS_PATH
|
||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||
DNA_IMG_PATH = config.DNA_IMG_PATH
|
||
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
||
|
||
print(f"配置导入成功,当前版本: {TOOL_NAME} {TOOL_VERSION}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"配置导入失败: {str(e)}")
|
||
return False
|
||
|
||
# 尝试导入Config模块
|
||
try:
|
||
from scripts.utils import Config
|
||
except ImportError:
|
||
# 创建默认Config对象
|
||
class DefaultConfig:
|
||
DNA_CONFIG = {
|
||
'DNA_PATH': os.path.join(TOOL_PATH, 'assets', 'dna'),
|
||
'DNA_FILE_PATH': os.path.join(TOOL_PATH, 'assets', 'dna', 'default.dna'),
|
||
'DNA_VERSION': 'DNAv4',
|
||
'LOD_LEVELS': [0, 1, 2, 3, 4],
|
||
'DEFAULT_MESH_INDICES': [0]
|
||
}
|
||
Config = DefaultConfig()
|
||
|
||
|
||
#===================================== MODULE RELOADER =====================================
|
||
class ModuleReloader(object):
|
||
"""Class for reloading modules in the Plugin"""
|
||
|
||
@staticmethod
|
||
def get_package_modules(package_name):
|
||
"""
|
||
获取包中的所有模块
|
||
|
||
Args:
|
||
package_name (str): 包名
|
||
|
||
Returns:
|
||
list: 模块名列表
|
||
"""
|
||
try:
|
||
# 特殊处理 scripts.Main,它不是一个包
|
||
if package_name == "scripts.Main":
|
||
return []
|
||
|
||
# 尝试导入包
|
||
package = __import__(package_name, fromlist=["*"])
|
||
|
||
# 获取包的路径
|
||
package_path = getattr(package, "__path__", None)
|
||
|
||
# 如果不是包,返回空列表
|
||
if package_path is None:
|
||
return []
|
||
|
||
# 获取包中的所有模块
|
||
modules = []
|
||
for _, name, is_pkg in pkgutil.iter_modules(package_path):
|
||
module_name = f"{package_name}.{name}"
|
||
modules.append(module_name)
|
||
|
||
# 如果是子包,递归获取子包中的模块
|
||
if is_pkg:
|
||
submodules = ModuleReloader.get_package_modules(module_name)
|
||
modules.extend(submodules)
|
||
|
||
return modules
|
||
except Exception as e:
|
||
print(f"获取包 {package_name} 中的模块时出错: {str(e)}")
|
||
return []
|
||
|
||
@staticmethod
|
||
def reload_module(module_name):
|
||
"""
|
||
重新加载指定模块
|
||
|
||
Args:
|
||
module_name (str): 模块名
|
||
|
||
Returns:
|
||
bool: 成功返回True,失败返回False
|
||
"""
|
||
try:
|
||
# 检查是否是scripts.Main的子模块,如果是则跳过
|
||
if module_name.startswith("scripts.Main.") and module_name != "scripts.Main":
|
||
print(f"跳过 {module_name},因为scripts.Main不是一个包")
|
||
return False
|
||
|
||
# 尝试导入模块
|
||
try:
|
||
# 首先尝试直接导入
|
||
module = importlib.import_module(module_name)
|
||
except ImportError:
|
||
# 如果直接导入失败,尝试添加工具路径到sys.path
|
||
sys_path_modified = False
|
||
if TOOL_PATH not in sys.path:
|
||
sys.path.insert(0, TOOL_PATH)
|
||
sys_path_modified = True
|
||
|
||
module = __import__(module_name, fromlist=["*"])
|
||
|
||
if sys_path_modified:
|
||
sys.path.remove(TOOL_PATH)
|
||
|
||
# 重新加载模块
|
||
importlib.reload(module)
|
||
|
||
print(f"成功重新加载模块: {module_name}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"重新加载模块 {module_name} 时出错: {str(e)}")
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
@classmethod
|
||
def reload_all_modules(cls):
|
||
"""
|
||
重新加载所有插件模块
|
||
|
||
Returns:
|
||
dict: 重新加载每个模块的结果
|
||
"""
|
||
# 首先声明全局变量
|
||
global TOOL_NAME, TOOL_VERSION, TOOL_AUTHOR, TOOL_PATH, SCRIPTS_PATH
|
||
global UI_PATH, STYLE_FILE, ICONS_PATH, ASSETS_PATH, DNA_FILE_PATH
|
||
|
||
# 初始化结果字典
|
||
results = {}
|
||
|
||
# 清理缓存文件
|
||
clean_pycache(TOOL_PATH)
|
||
|
||
# 重载配置 - 使用import_main_config函数
|
||
try:
|
||
if import_main_config():
|
||
results['config'] = True
|
||
else:
|
||
results['config'] = False
|
||
except Exception as e:
|
||
print(f"重新加载配置时出现未预期的错误: {str(e)}")
|
||
traceback.print_exc()
|
||
results['config'] = False
|
||
|
||
# 定义要重新加载的模块
|
||
modules_to_reload = [
|
||
"scripts.utils",
|
||
"scripts.ui",
|
||
"scripts.Main"
|
||
]
|
||
|
||
# 获取所有子模块
|
||
all_modules = []
|
||
for module in modules_to_reload:
|
||
all_modules.append(module)
|
||
# 跳过scripts.Main的子模块,因为它不是一个包
|
||
if module != "scripts.Main":
|
||
try:
|
||
submodules = cls.get_package_modules(module)
|
||
if submodules:
|
||
all_modules.extend(submodules)
|
||
except Exception as e:
|
||
print(f"获取模块 {module} 的子模块时出错: {str(e)}")
|
||
|
||
# 去除重复项并排序
|
||
all_modules = sorted(list(set(all_modules)))
|
||
|
||
# 过滤掉scripts.Main的子模块
|
||
all_modules = [m for m in all_modules if not (m.startswith("scripts.Main.") and m != "scripts.Main")]
|
||
|
||
# 按照依赖关系对模块进行排序
|
||
# 确保配置模块先重新加载
|
||
priority_modules = []
|
||
normal_modules = []
|
||
|
||
for module in all_modules:
|
||
if "config" in module.lower() or module.endswith(".config"):
|
||
priority_modules.append(module)
|
||
else:
|
||
normal_modules.append(module)
|
||
|
||
# 先重新加载优先级模块,然后是普通模块
|
||
for module in priority_modules + normal_modules:
|
||
results[module] = cls.reload_module(module)
|
||
|
||
return results
|
||
|
||
|
||
def reload_all():
|
||
"""Reload all Plugin modules and display results"""
|
||
print("\n" + "-"*50)
|
||
print("Reloading Plugin modules...")
|
||
print("-"*50)
|
||
|
||
# 获取插件根目录 - 使用config中定义的TOOL_PATH
|
||
try:
|
||
import config
|
||
TOOL_PATH = config.TOOL_PATH
|
||
except ImportError:
|
||
# 如果无法导入config,则使用相对路径
|
||
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
print(f"Plugin root directory: {TOOL_PATH}")
|
||
|
||
# 清理 __pycache__ 目录
|
||
print("Cleaning __pycache__ directories...")
|
||
pycache_count = clean_pycache(TOOL_PATH)
|
||
print(f"Removed {pycache_count} __pycache__ directories and .pyc files")
|
||
|
||
# Reload modules
|
||
results = ModuleReloader.reload_all_modules()
|
||
|
||
success_count = sum(1 for success in results.values() if success)
|
||
total_count = len(results)
|
||
|
||
print("\nReload Summary:")
|
||
print(f"Successfully reloaded {success_count} of {total_count} modules")
|
||
|
||
if success_count < total_count:
|
||
print("\nFailed modules:")
|
||
for module, success in results.items():
|
||
if not success:
|
||
print(f" - {module}")
|
||
|
||
print("-"*50)
|
||
return results
|
||
|
||
|
||
#===================================== MODULE RELOADER UI =====================================
|
||
class ModuleReloaderUI(QtWidgets.QDialog):
|
||
"""模块重载工具UI类"""
|
||
def __init__(self, parent=None):
|
||
"""初始化UI"""
|
||
parent = parent or getMayaMainWindow()
|
||
super(ModuleReloaderUI, self).__init__(parent)
|
||
|
||
self.setWindowTitle("Delos - 模块重载工具")
|
||
self.setMinimumWidth(600)
|
||
self.setMinimumHeight(500)
|
||
self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
|
||
|
||
# 创建UI
|
||
self.create_ui()
|
||
|
||
def create_ui(self):
|
||
"""创建UI元素"""
|
||
# 主布局
|
||
main_layout = QtWidgets.QVBoxLayout(self)
|
||
main_layout.setContentsMargins(10, 10, 10, 10)
|
||
main_layout.setSpacing(10)
|
||
|
||
# 标题标签
|
||
title_label = QtWidgets.QLabel("Delos 模块重载工具")
|
||
title_label.setStyleSheet("font-size: 16px; font-weight: bold;")
|
||
main_layout.addWidget(title_label)
|
||
|
||
# 说明标签
|
||
desc_label = QtWidgets.QLabel("选择要重载的模块类别,然后点击'重载选定模块'按钮。")
|
||
main_layout.addWidget(desc_label)
|
||
|
||
# 创建模块选择区域
|
||
modules_group = QtWidgets.QGroupBox("模块选择")
|
||
modules_layout = QtWidgets.QVBoxLayout(modules_group)
|
||
|
||
# 全选复选框
|
||
self.all_modules_cb = QtWidgets.QCheckBox("重载所有模块")
|
||
self.all_modules_cb.setChecked(True)
|
||
modules_layout.addWidget(self.all_modules_cb)
|
||
|
||
# 模块类别
|
||
self.module_categories = {
|
||
"核心模块": ["scripts.Main", "scripts.utils", "scripts.ui"],
|
||
"UI模块": ["scripts.ui.main_window", "scripts.ui.toolbar", "scripts.ui.model_editor_panel",
|
||
"scripts.ui.joint_calibration_panel", "scripts.ui.blendshape_edit_panel",
|
||
"scripts.ui.dna_browser_panel", "scripts.ui.animation_system_panel"],
|
||
"工具模块": ["scripts.utils.utils_rigging", "scripts.utils.utils_geometry",
|
||
"scripts.utils.utils_definition", "scripts.utils.utils_behaviour",
|
||
"scripts.utils.utils_toolbar", "scripts.utils.dna_manager"]
|
||
}
|
||
|
||
# 创建模块类别复选框
|
||
self.module_cbs = {}
|
||
for category, modules in self.module_categories.items():
|
||
category_cb = QtWidgets.QCheckBox(category)
|
||
modules_layout.addWidget(category_cb)
|
||
|
||
# 添加子模块列表
|
||
modules_list = QtWidgets.QListWidget()
|
||
modules_list.setMaximumHeight(100)
|
||
for module in modules:
|
||
item = QtWidgets.QListWidgetItem(module)
|
||
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
|
||
item.setCheckState(QtCore.Qt.Checked)
|
||
modules_list.addItem(item)
|
||
|
||
modules_layout.addWidget(modules_list)
|
||
self.module_cbs[category] = (category_cb, modules)
|
||
|
||
# 连接类别复选框和模块列表
|
||
category_cb.stateChanged.connect(lambda state, lst=modules_list: self.toggle_category(state, lst))
|
||
|
||
# 连接全选复选框
|
||
self.all_modules_cb.stateChanged.connect(self.toggle_all_modules)
|
||
|
||
main_layout.addWidget(modules_group)
|
||
|
||
# 结果文本区域
|
||
self.results_text = QtWidgets.QTextEdit()
|
||
self.results_text.setReadOnly(True)
|
||
main_layout.addWidget(self.results_text)
|
||
|
||
# 按钮区域
|
||
buttons_layout = QtWidgets.QHBoxLayout()
|
||
|
||
# 重载按钮
|
||
self.reload_button = QtWidgets.QPushButton("重载选定模块")
|
||
self.reload_button.setMinimumHeight(30)
|
||
buttons_layout.addWidget(self.reload_button)
|
||
|
||
# 清理缓存按钮
|
||
self.clean_button = QtWidgets.QPushButton("仅清理缓存")
|
||
self.clean_button.setMinimumHeight(30)
|
||
buttons_layout.addWidget(self.clean_button)
|
||
|
||
# 关闭按钮
|
||
self.close_button = QtWidgets.QPushButton("关闭")
|
||
self.close_button.setMinimumHeight(30)
|
||
buttons_layout.addWidget(self.close_button)
|
||
|
||
main_layout.addLayout(buttons_layout)
|
||
|
||
# 连接按钮信号
|
||
self.reload_button.clicked.connect(self.reload_and_update_ui)
|
||
self.clean_button.clicked.connect(self.clean_cache_only)
|
||
self.close_button.clicked.connect(self.close)
|
||
|
||
def toggle_all_modules(self, state):
|
||
"""切换是否选择所有模块"""
|
||
for category, (cb, _) in self.module_cbs.items():
|
||
cb.setEnabled(not state)
|
||
|
||
def toggle_category(self, state, list_widget):
|
||
"""切换类别中的所有模块"""
|
||
for i in range(list_widget.count()):
|
||
item = list_widget.item(i)
|
||
item.setCheckState(QtCore.Qt.Checked if state else QtCore.Qt.Unchecked)
|
||
|
||
def get_selected_modules(self):
|
||
"""获取选定的模块"""
|
||
if self.all_modules_cb.isChecked():
|
||
return None # 表示所有模块
|
||
|
||
selected_categories = []
|
||
for category, (cb, modules) in self.module_cbs.items():
|
||
if cb.isChecked():
|
||
selected_categories.extend(modules)
|
||
|
||
return selected_categories
|
||
|
||
def reload_and_update_ui(self):
|
||
"""重载模块并更新UI"""
|
||
self.results_text.clear()
|
||
self.results_text.append("正在重载模块...\n")
|
||
|
||
# 获取插件根目录
|
||
try:
|
||
import config
|
||
TOOL_PATH = config.TOOL_PATH
|
||
except ImportError:
|
||
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
self.results_text.append(f"插件根目录: {TOOL_PATH}")
|
||
|
||
# 清理 __pycache__ 目录
|
||
self.results_text.append("正在清理 __pycache__ 目录...")
|
||
pycache_count = clean_pycache(TOOL_PATH)
|
||
self.results_text.append(f"已删除 {pycache_count} 个 __pycache__ 目录和 .pyc 文件\n")
|
||
|
||
# 确定要重载的模块
|
||
results = {}
|
||
selected_modules = self.get_selected_modules()
|
||
|
||
if selected_modules is None:
|
||
# 重载所有模块
|
||
results = ModuleReloader.reload_all_modules()
|
||
else:
|
||
if not selected_modules:
|
||
self.results_text.append("未选择任何模块,操作已取消。")
|
||
return
|
||
|
||
# 获取所有模块
|
||
all_modules = []
|
||
for package in selected_modules:
|
||
# 跳过scripts.Main的子模块
|
||
if package == "scripts.Main":
|
||
all_modules.append(package)
|
||
elif package.startswith("scripts."):
|
||
try:
|
||
submodules = ModuleReloader.get_package_modules(package)
|
||
all_modules.extend(submodules)
|
||
all_modules.append(package) # 确保包本身也被重载
|
||
except Exception as e:
|
||
self.results_text.append(f"获取模块 {package} 的子模块时出错: {str(e)}")
|
||
all_modules.append(package) # 至少尝试重载包本身
|
||
else:
|
||
all_modules.append(package)
|
||
|
||
# 去除重复项并排序
|
||
all_modules = sorted(list(set(all_modules)))
|
||
|
||
# 过滤掉scripts.Main的子模块
|
||
all_modules = [m for m in all_modules if not (m.startswith("scripts.Main.") and m != "scripts.Main")]
|
||
|
||
# 重载选定的模块
|
||
results = {}
|
||
for module in all_modules:
|
||
results[module] = ModuleReloader.reload_module(module)
|
||
|
||
# 更新UI显示结果
|
||
success_count = sum(1 for success in results.values() if success)
|
||
total_count = len(results)
|
||
|
||
self.results_text.append(f"成功重载 {success_count}/{total_count} 个模块\n")
|
||
|
||
# 显示成功重载的模块
|
||
self.results_text.append("成功重载的模块:")
|
||
for module, success in results.items():
|
||
if success:
|
||
self.results_text.append(f" - {module}")
|
||
|
||
# 显示失败的模块(如果有)
|
||
if success_count < total_count:
|
||
self.results_text.append("\n重载失败的模块:")
|
||
for module, success in results.items():
|
||
if not success:
|
||
self.results_text.append(f" - {module}")
|
||
|
||
# 提示用户重载完成
|
||
self.results_text.append("\n重载操作已完成!")
|
||
|
||
def clean_cache_only(self):
|
||
"""仅清理缓存"""
|
||
self.results_text.clear()
|
||
self.results_text.append("仅清理缓存...\n")
|
||
|
||
# 获取插件根目录
|
||
try:
|
||
import config
|
||
TOOL_PATH = config.TOOL_PATH
|
||
except ImportError:
|
||
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
self.results_text.append(f"插件根目录: {TOOL_PATH}")
|
||
|
||
# 清理 __pycache__ 目录
|
||
pycache_count = clean_pycache(TOOL_PATH)
|
||
self.results_text.append(f"已删除 {pycache_count} 个 __pycache__ 目录和 .pyc 文件")
|
||
self.results_text.append("\n缓存清理操作已完成!")
|
||
|
||
|
||
def show_reload_ui():
|
||
"""显示模块重载UI"""
|
||
try:
|
||
# 关闭已有的窗口 - 使用多种方法确保关闭
|
||
window_title = "Delos - 模块重载工具"
|
||
window_closed = False
|
||
|
||
# 方法1: 使用窗口标题查找
|
||
for widget in QtWidgets.QApplication.topLevelWidgets():
|
||
if widget.isVisible() and hasattr(widget, 'windowTitle') and widget.windowTitle() == window_title:
|
||
print(f"关闭已有的模块重载工具窗口: {widget}")
|
||
widget.close()
|
||
widget.deleteLater()
|
||
window_closed = True
|
||
|
||
# 方法2: 使用类型名称字符串查找
|
||
if not window_closed:
|
||
for widget in QtWidgets.QApplication.topLevelWidgets():
|
||
if widget.isVisible() and widget.__class__.__name__ == "ModuleReloaderUI":
|
||
print(f"关闭已有的模块重载工具窗口: {widget}")
|
||
widget.close()
|
||
widget.deleteLater()
|
||
window_closed = True
|
||
|
||
# 方法3: 使用Maya命令关闭窗口
|
||
try:
|
||
import maya.cmds as cmds
|
||
if cmds.window("moduleReloaderWindow", exists=True):
|
||
cmds.deleteUI("moduleReloaderWindow", window=True)
|
||
print("使用Maya命令关闭模块重载工具窗口")
|
||
window_closed = True
|
||
except Exception as e:
|
||
print(f"使用Maya命令关闭窗口失败: {str(e)}")
|
||
|
||
# 创建新窗口
|
||
dialog = ModuleReloaderUI()
|
||
dialog.setObjectName("moduleReloaderWindow") # 设置窗口名称便于后续关闭
|
||
dialog.show()
|
||
return dialog
|
||
except Exception as e:
|
||
traceback.print_exc()
|
||
print(f"显示UI失败: {str(e)}。回退到命令行重载。")
|
||
return reload_all()
|
||
|
||
# Main function to be called from Maya
|
||
def main():
|
||
"""从Maya调用的主函数"""
|
||
try:
|
||
# 检查Qt模块是否可用
|
||
if HAS_QT:
|
||
# 显示重载UI
|
||
show_reload_ui()
|
||
else:
|
||
# 如果Qt不可用,回退到命令行重载
|
||
reload_all()
|
||
|
||
print("模块重载操作已完成!")
|
||
return True
|
||
except Exception as e:
|
||
print(f"模块重载过程中出错: {str(e)}")
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
|
||
# Allow running this script directly
|
||
if __name__ == "__main__":
|
||
main()
|