diff --git a/.windsurfrules b/.windsurfrules index b14416e..e82e039 100644 --- a/.windsurfrules +++ b/.windsurfrules @@ -166,7 +166,7 @@ We support one-click to correct the pose of the character to the correct pose, a - Face and panel controllers can be seamlessly switched, use context7; - https://pointart.oss-cn-hangzhou.aliyuncs.com/wp-content/uploads/2024/06/%E9%9D%A2%E9%83%A8%E6%8E%A7%E5%88%B6%E5%99%A8.mp4, use context7; -- Aiming at the problem that Metahuman's face control panel is not intuitive, we support the generation of a brand-new face controller, which can directly adjust the expression and muscles of the character on the face. If you contact Metahuman controller soon, it will greatly reduce your learning cost. +- Aiming at the problem that Metahuman face control panel is not intuitive, we support the generation of a brand-new face controller, which can directly adjust the expression and muscles of the character on the face. If you contact Metahuman controller soon, it will greatly reduce your learning cost. #### 1.1.7. Different topological binding diff --git a/Plan.md b/Plan.md index 05daca3..e46c459 100644 --- a/Plan.md +++ b/Plan.md @@ -154,13 +154,30 @@ MetaHumanDNAPlugin/ ## 进度记录与后续安排 -### 2025-05-06 更新 +### 2025-05-08 更新 -- 基础框架与UI阶段(第一阶段)已完成95% -- 完成了主要UI模块的创建和基本功能实现 +#### 已完成 +- 基础框架与UI(第一阶段)已完成95% +- 主界面与四大核心面板(geometry/rigging/behaviour/definition)功能与布局基本完善 +- 行为面板(behaviour.py)布局结构已规范化,分割器与面板嵌套逻辑已修正,交互体验提升 +- 多语言映射文件(localization.py)已补全,支持各主要功能区和按钮的中英文切换 - 优化了项目结构,明确了各模块的职责和接口 -- 需要进行UI微调与优化,包括统一样式、完善交互等 -- DNA处理核心模块已初步实现,需要进一步完善与测试 +- 参考Epic官方MetaHuman DNA Calibration与SuperRigging等插件,吸收最佳实践 + +#### 进行中 +- UI微调与优化(统一按钮样式、图标、响应式布局) +- 多语言支持完善(持续补全各模块UI文本映射) +- DNA核心功能开发(dnalib模块完善、MetaHuman DNA标准兼容、文件导入导出) +- 增强UI与Maya交互的稳定性,优化性能,减少重绘 +- 行为、定义、几何等面板的交互细节持续优化 + +#### 下一步 +- 完成所有UI面板的多语言、样式、布局一致性 +- 完善DNA文件读写、MetaHuman兼容与一键式流程 +- 开发批量处理、自动化绑定与多LOD支持 +- 增强文档与测试,持续同步开发进度 + +--- ### 2025-04-30 更新 diff --git a/config.py b/config.py index 3390ae5..54805ed 100644 --- a/config.py +++ b/config.py @@ -14,7 +14,7 @@ TOOL_YEAR = "2025" TOOL_MOD_FILENAME = f"{TOOL_NAME.lower()}.mod" TOOL_LANG = "en_US" TOOL_WSCL_NAME = f"{TOOL_NAME}WorkspaceControl" -TOOL_HELP_URL = f"http://10.72.61.59:3000/ArtGroup/{TOOL_NAME}/wiki" +TOOL_HELP_URL = f"https://gitea.cgnico.com/CGNICO/{TOOL_NAME}/wiki" # Path Configuration TOOL_PATH = os.path.dirname(os.path.abspath(__file__)).replace("\\", "/") diff --git a/scripts/Main.py b/scripts/Main.py index b1ef12a..672dae1 100644 --- a/scripts/Main.py +++ b/scripts/Main.py @@ -31,8 +31,7 @@ from scripts.ui import behaviour from scripts.ui import definition #========================================= LOCALIZATION ===================================== from scripts.ui import localization -LANG = localization.LANG -get_text = localization.get_text +TEXT = localization.TEXT #=========================================== CONFIG ========================================= import config TOOL_NAME = config.TOOL_NAME @@ -111,13 +110,13 @@ class MainWindow(QtWidgets.QWidget): # 创建功能区域切换按钮组 self.function_buttons = {} - self.function_buttons["geometry"] = QtWidgets.QPushButton(get_text("geometry", "几何体")) + self.function_buttons["geometry"] = QtWidgets.QPushButton(TEXT("geometry", "几何体")) self.function_buttons["geometry"].setIcon(ui_utils.load_icon("meshes.png")) - self.function_buttons["rigging"] = QtWidgets.QPushButton(get_text("rigging", "绑定")) + self.function_buttons["rigging"] = QtWidgets.QPushButton(TEXT("rigging", "绑定")) self.function_buttons["rigging"].setIcon(ui_utils.load_icon("configuration.png")) - self.function_buttons["behaviour"] = QtWidgets.QPushButton(get_text("behaviour", "行为")) + self.function_buttons["behaviour"] = QtWidgets.QPushButton(TEXT("behaviour", "行为")) self.function_buttons["behaviour"].setIcon(ui_utils.load_icon("behaviour.png")) - self.function_buttons["definition"] = QtWidgets.QPushButton(get_text("definition", "定义")) + self.function_buttons["definition"] = QtWidgets.QPushButton(TEXT("definition", "定义")) self.function_buttons["definition"].setIcon(ui_utils.load_icon("definition.png")) # 设置按钮样式和属性 diff --git a/scripts/ReloadModules.py b/scripts/ReloadModules.py index 6cab00d..e39df32 100644 --- a/scripts/ReloadModules.py +++ b/scripts/ReloadModules.py @@ -51,6 +51,9 @@ except ImportError: HAS_QT = False print("警告: 无法导入Qt模块,UI功能将不可用") +import config +TOOL_NAME = config.TOOL_NAME + #===================================== 公共函数 ===================================== def clean_pycache(root_dir): """ @@ -411,7 +414,7 @@ class ModuleReloaderUI(QtWidgets.QDialog): parent = parent or getMayaMainWindow() super(ModuleReloaderUI, self).__init__(parent) - self.setWindowTitle(f"{TOOL_NAME} - 模块重载工具") + self.setWindowTitle("模块重载工具") self.setMinimumWidth(600) self.setMinimumHeight(500) self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) @@ -427,7 +430,7 @@ class ModuleReloaderUI(QtWidgets.QDialog): main_layout.setSpacing(10) # 标题标签 - title_label = QtWidgets.QLabel(f"{TOOL_NAME} 模块重载工具") + title_label = QtWidgets.QLabel("模块重载工具") title_label.setStyleSheet("font-size: 16px; font-weight: bold;") main_layout.addWidget(title_label) diff --git a/scripts/ui/behaviour.py b/scripts/ui/behaviour.py index d511a09..841c211 100644 --- a/scripts/ui/behaviour.py +++ b/scripts/ui/behaviour.py @@ -17,8 +17,8 @@ Behaviour UI Module for Plugin - 控制面板查找 """ #========================================= IMPORT ========================================= -from Qt import QtWidgets, QtCore, QtGui -from Qt.QtCompat import wrapInstance +from scripts.ui.Qt import QtWidgets, QtCore, QtGui +from scripts.ui.Qt.QtCompat import wrapInstance from maya import OpenMayaUI as omui import maya.cmds as cmds import maya.mel as mel @@ -57,51 +57,29 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT #========================================= LOCATION ======================================= from scripts.ui import localization -LANG = localization.LANG -get_text = localization.get_text +TEXT = localization.TEXT class BehaviourUI(ui_utils.BaseUI): """ 行为系统UI类 - 负责显示角色行为编辑界面和基础操作 继承自BaseUI类,实现行为系统相关的UI功能 """ - # 类变量,存储单例实例 - _instance = None - - @classmethod - def get_instance(cls): - """ - 获取BehaviourUI的单例实例 - - Returns: - BehaviourUI: 单例实例,如果不存在则返回None - """ - return cls._instance - + #========================================== INIT ======================================== def __init__(self, parent=None): - """ - 初始化行为系统UI - """ - super(BehaviourUI, self).__init__() # 不传递parent参数给BaseUI - - # 设置单例实例 - BehaviourUI._instance = self + super().__init__(parent) # 创建主控件 - self.main_widget = QtWidgets.QWidget(parent) + self.main_widget = QtWidgets.QWidget() self.main_widget.setObjectName("behaviourMainWidget") - # 初始化控件、布局和按钮字典 - self.controls = {} - self.layouts = {} - self.buttons = {} - self.splitters = {} - # 创建UI组件 self.create_widgets() self.create_layouts() self.create_connections() + # 更新UI文本 + self.update_language() + # 设置全局样式,确保所有控件都没有最小宽度限制 self.main_widget.setStyleSheet(""" QWidget { min-width: 0px; } @@ -118,7 +96,7 @@ class BehaviourUI(ui_utils.BaseUI): 包括标题标签、搜索框、控制列表、滑块等 """ # 标题标签 - self.controls["title_label"] = QtWidgets.QLabel(get_text("behaviour_title", "行为系统")) + self.controls["title_label"] = QtWidgets.QLabel(TEXT("behaviour_title", "行为系统")) self.controls["title_label"].setObjectName("behaviourTitleLabel") self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter) self.controls["title_label"].setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px;") @@ -141,7 +119,7 @@ class BehaviourUI(ui_utils.BaseUI): # 搜索框 self.controls["search_input"] = QtWidgets.QLineEdit() self.controls["search_input"].setObjectName("searchInput") - self.controls["search_input"].setPlaceholderText(get_text("search", "搜索...")) + self.controls["search_input"].setPlaceholderText(TEXT("search", "搜索...")) self.controls["search_input"].setFixedHeight(25) # 控制列表 @@ -193,27 +171,27 @@ class BehaviourUI(ui_utils.BaseUI): self.buttons["page_6"].setCheckable(True) # 左下角Range按钮 - self.buttons["range_minus"] = QtWidgets.QPushButton(get_text(" Range - ", " 范围 - ")) + self.buttons["range_minus"] = QtWidgets.QPushButton(TEXT(" Range - ", " 范围 - ")) self.buttons["range_minus"].setObjectName("rangeMinusButton") self.buttons["range_minus"].setIcon(ui_utils.load_icon("behaviour.png")) self.buttons["range_minus"].setMinimumWidth(0) - self.buttons["range_plus"] = QtWidgets.QPushButton(get_text(" Range + ", " 范围 + ")) + self.buttons["range_plus"] = QtWidgets.QPushButton(TEXT(" Range + ", " 范围 + ")) self.buttons["range_plus"].setObjectName("rangePlusButton") self.buttons["range_plus"].setIcon(ui_utils.load_icon("behaviour.png")) self.buttons["range_plus"].setMinimumWidth(0) # 左侧面板控件 - Raw Control - self.controls["raw_control_group"] = QtWidgets.QGroupBox(get_text("Raw Control", "原始控制")) + self.controls["raw_control_group"] = QtWidgets.QGroupBox(TEXT("Raw Control", "原始控制")) self.controls["raw_control_group"].setObjectName("rawControlGroup") - self.controls["raw_control_group"].setTitle(get_text("Raw Control", "原始控制")) + self.controls["raw_control_group"].setTitle(TEXT("Raw Control", "原始控制")) self.controls["raw_control_group"].setFixedHeight(25) # 右侧面板控件 - Related BlendShapes - self.controls["blendshapes_group"] = QtWidgets.QGroupBox(get_text("Related BlendShapes", "相关BlendShapes")) + self.controls["blendshapes_group"] = QtWidgets.QGroupBox(TEXT("Related BlendShapes", "相关BlendShapes")) self.controls["blendshapes_group"].setObjectName("blendshapesGroup") - self.controls["blendshapes_group"].setTitle(get_text("Related BlendShapes", "相关BlendShapes")) + self.controls["blendshapes_group"].setTitle(TEXT("Related BlendShapes", "相关BlendShapes")) self.controls["blendshapes_group"].setFixedHeight(25) # BlendShapes列表 @@ -239,60 +217,60 @@ class BehaviourUI(ui_utils.BaseUI): self.controls["bs_slider_all_check"].setObjectName("bsSliderAllCheck") # 右下角BS Range按钮 - self.buttons["bs_range_minus"] = QtWidgets.QPushButton(get_text(" Range - ", " 范围 - ")) + self.buttons["bs_range_minus"] = QtWidgets.QPushButton(TEXT(" Range - ", " 范围 - ")) self.buttons["bs_range_minus"].setObjectName("bsRangeMinusButton") self.buttons["bs_range_minus"].setIcon(ui_utils.load_icon("behaviour.png")) self.buttons["bs_range_minus"].setMinimumWidth(0) - self.buttons["bs_range_plus"] = QtWidgets.QPushButton(get_text(" Range + ", " 范围 + ")) + self.buttons["bs_range_plus"] = QtWidgets.QPushButton(TEXT(" Range + ", " 范围 + ")) self.buttons["bs_range_plus"].setObjectName("bsRangePlusButton") self.buttons["bs_range_plus"].setIcon(ui_utils.load_icon("behaviour.png")) self.buttons["bs_range_plus"].setMinimumWidth(0) # BlendShape操作按钮 - self.buttons["flip_target"] = QtWidgets.QPushButton(get_text("Flip Target", "翻转目标")) + self.buttons["flip_target"] = QtWidgets.QPushButton(TEXT("Flip Target", "翻转目标")) self.buttons["flip_target"].setObjectName("flipTargetButton") self.buttons["flip_target"].setIcon(ui_utils.load_icon("mirrorL.png")) - self.buttons["mirror_target"] = QtWidgets.QPushButton(get_text("Mirror Target", "镜像目标")) + self.buttons["mirror_target"] = QtWidgets.QPushButton(TEXT("Mirror Target", "镜像目标")) self.buttons["mirror_target"].setObjectName("mirrorTargetButton") self.buttons["mirror_target"].setIcon(ui_utils.load_icon("mirror.png")) - self.buttons["find_flip_target"] = QtWidgets.QPushButton(get_text("Find Flip Target", "查找翻转目标")) + self.buttons["find_flip_target"] = QtWidgets.QPushButton(TEXT("Find Flip Target", "查找翻转目标")) self.buttons["find_flip_target"].setObjectName("findFlipTargetButton") self.buttons["find_flip_target"].setIcon(ui_utils.load_icon("mirrorR.png")) - self.buttons["add_blendshape"] = QtWidgets.QPushButton(get_text("Add BlendShape", "添加BlendShape")) + self.buttons["add_blendshape"] = QtWidgets.QPushButton(TEXT("Add BlendShape", "添加BlendShape")) self.buttons["add_blendshape"].setObjectName("addBlendshapeButton") self.buttons["add_blendshape"].setIcon(ui_utils.load_icon("blendShape.png")) - self.buttons["delete_blendshape"] = QtWidgets.QPushButton(get_text("Delete BlendShape", "删除BlendShape")) + self.buttons["delete_blendshape"] = QtWidgets.QPushButton(TEXT("Delete BlendShape", "删除BlendShape")) self.buttons["delete_blendshape"].setObjectName("deleteBlendshapeButton") self.buttons["delete_blendshape"].setIcon(ui_utils.load_icon("blendShape.png")) - self.buttons["batch_blendshape"] = QtWidgets.QPushButton(get_text("Batch BlendShape", "批量BlendShape")) + self.buttons["batch_blendshape"] = QtWidgets.QPushButton(TEXT("Batch BlendShape", "批量BlendShape")) self.buttons["batch_blendshape"].setObjectName("batchBlendshapeButton") self.buttons["batch_blendshape"].setIcon(ui_utils.load_icon("blendShape.png")) - self.buttons["bs_range_minus"] = QtWidgets.QPushButton(get_text(" Range - ", " 范围 - ")) + self.buttons["bs_range_minus"] = QtWidgets.QPushButton(TEXT(" Range - ", " 范围 - ")) self.buttons["bs_range_minus"].setObjectName("bsRangeMinusButton") self.buttons["bs_range_minus"].setIcon(ui_utils.load_icon("behaviour.png")) self.buttons["bs_range_minus"].setMinimumWidth(0) - self.buttons["bs_range_plus"] = QtWidgets.QPushButton(get_text(" Range + ", " 范围 + ")) + self.buttons["bs_range_plus"] = QtWidgets.QPushButton(TEXT(" Range + ", " 范围 + ")) self.buttons["bs_range_plus"].setObjectName("bsRangePlusButton") self.buttons["bs_range_plus"].setIcon(ui_utils.load_icon("behaviour.png")) self.buttons["bs_range_plus"].setMinimumWidth(0) - self.buttons["rebuild_select"] = QtWidgets.QPushButton(get_text("Rebuild Select", "重建选择")) + self.buttons["rebuild_select"] = QtWidgets.QPushButton(TEXT("Rebuild Select", "重建选择")) self.buttons["rebuild_select"].setObjectName("rebuildSelectButton") self.buttons["rebuild_select"].setIcon(ui_utils.load_icon("loading.png")) - self.buttons["reposition_joints"] = QtWidgets.QPushButton(get_text("Reposition Joints", "重新定位关节")) + self.buttons["reposition_joints"] = QtWidgets.QPushButton(TEXT("Reposition Joints", "重新定位关节")) self.buttons["reposition_joints"].setObjectName("repositionJointsButton") self.buttons["reposition_joints"].setIcon(ui_utils.load_icon("loading.png")) - self.buttons["blend_select"] = QtWidgets.QPushButton(get_text("Blend Select", "混合选择")) + self.buttons["blend_select"] = QtWidgets.QPushButton(TEXT("Blend Select", "混合选择")) self.buttons["blend_select"].setObjectName("blendSelectButton") self.buttons["blend_select"].setIcon(ui_utils.load_icon("loading.png")) @@ -314,64 +292,64 @@ class BehaviourUI(ui_utils.BaseUI): self.controls["bottom_slider_all_check"].setObjectName("bottomSliderAllCheck") # 底部标签页按钮 - self.buttons["tab_psd"] = QtWidgets.QPushButton(get_text("PSD", "PSD")) + self.buttons["tab_psd"] = QtWidgets.QPushButton(TEXT("PSD", "PSD")) self.buttons["tab_psd"].setIcon(ui_utils.load_icon("psd.png")) self.buttons["tab_psd"].setObjectName("tabPsdButton") self.buttons["tab_psd"].setCheckable(True) self.buttons["tab_psd"].setChecked(True) - self.buttons["tab_bse"] = QtWidgets.QPushButton(get_text("BSE", "BSE")) + self.buttons["tab_bse"] = QtWidgets.QPushButton(TEXT("BSE", "BSE")) self.buttons["tab_bse"].setIcon(ui_utils.load_icon("blendShape.png")) self.buttons["tab_bse"].setObjectName("tabBseButton") self.buttons["tab_bse"].setCheckable(True) self.buttons["tab_bse"].setChecked(True) - self.buttons["tab_key"] = QtWidgets.QPushButton(get_text("KEY", "KEY")) + self.buttons["tab_key"] = QtWidgets.QPushButton(TEXT("KEY", "KEY")) self.buttons["tab_key"].setIcon(ui_utils.load_icon("setKeyOnAnim.png")) self.buttons["tab_key"].setObjectName("tabKeyButton") self.buttons["tab_key"].setCheckable(True) self.buttons["tab_key"].setChecked(True) - self.buttons["tab_mir"] = QtWidgets.QPushButton(get_text("MIR", "MIR")) + self.buttons["tab_mir"] = QtWidgets.QPushButton(TEXT("MIR", "MIR")) self.buttons["tab_mir"].setIcon(ui_utils.load_icon("mirrorR.png")) self.buttons["tab_mir"].setObjectName("tabMirButton") self.buttons["tab_mir"].setCheckable(True) self.buttons["tab_mir"].setChecked(True) - self.buttons["tab_ark"] = QtWidgets.QPushButton(get_text("ARK", "ARK")) + self.buttons["tab_ark"] = QtWidgets.QPushButton(TEXT("ARK", "ARK")) self.buttons["tab_ark"].setIcon(ui_utils.load_icon("ARKit52.png")) self.buttons["tab_ark"].setObjectName("tabArkButton") self.buttons["tab_ark"].setCheckable(True) self.buttons["tab_ark"].setChecked(True) - self.buttons["tab_ctr"] = QtWidgets.QPushButton(get_text("CTR", "CTR")) + self.buttons["tab_ctr"] = QtWidgets.QPushButton(TEXT("CTR", "CTR")) self.buttons["tab_ctr"].setIcon(ui_utils.load_icon("ctrl_hide.png")) self.buttons["tab_ctr"].setObjectName("tabCtrButton") self.buttons["tab_ctr"].setCheckable(True) self.buttons["tab_ctr"].setChecked(True) # 底部功能按钮 - self.buttons["reset_default_expression"] = QtWidgets.QPushButton(get_text("Reset Default", "重置默认")) + self.buttons["reset_default_expression"] = QtWidgets.QPushButton(TEXT("Reset Default", "重置默认")) self.buttons["reset_default_expression"].setIcon(ui_utils.load_icon("reset.png")) self.buttons["reset_default_expression"].setObjectName("resetDefaultExpressionButton") - self.buttons["find_select_expression"] = QtWidgets.QPushButton(get_text("Find Select", "查找选择")) + self.buttons["find_select_expression"] = QtWidgets.QPushButton(TEXT("Find Select", "查找选择")) self.buttons["find_select_expression"].setIcon(ui_utils.load_icon("expressions_current.png")) self.buttons["find_select_expression"].setObjectName("findSelectExpressionButton") - self.buttons["write_current_expressions"] = QtWidgets.QPushButton(get_text("Write Current", "写入当前")) + self.buttons["write_current_expressions"] = QtWidgets.QPushButton(TEXT("Write Current", "写入当前")) self.buttons["write_current_expressions"].setIcon(ui_utils.load_icon("expression.png")) self.buttons["write_current_expressions"].setObjectName("writeCurrentExpressionsButton") - self.buttons["controller_find"] = QtWidgets.QPushButton(get_text("Controller Find", "控制器查找")) + self.buttons["controller_find"] = QtWidgets.QPushButton(TEXT("Controller Find", "控制器查找")) self.buttons["controller_find"].setIcon(ui_utils.load_icon("controller.png")) self.buttons["controller_find"].setObjectName("controllerFindButton") - self.buttons["select_associated_joint"] = QtWidgets.QPushButton(get_text("Select Joint", "选择关节")) + self.buttons["select_associated_joint"] = QtWidgets.QPushButton(TEXT("Select Joint", "选择关节")) self.buttons["select_associated_joint"].setIcon(ui_utils.load_icon("out_joint.png")) self.buttons["select_associated_joint"].setObjectName("selectAssociatedJointButton") - self.buttons["write_find_mirror"] = QtWidgets.QPushButton(get_text("Find Mirror", "查找镜像")) + self.buttons["write_find_mirror"] = QtWidgets.QPushButton(TEXT("Find Mirror", "查找镜像")) self.buttons["write_find_mirror"].setIcon(ui_utils.load_icon("mirror.png")) self.buttons["write_find_mirror"].setObjectName("writeFindMirrorButton") @@ -417,7 +395,7 @@ class BehaviourUI(ui_utils.BaseUI): self.layouts["left_content_layout"].setSpacing(5) # 添加标题标签 - left_title = QtWidgets.QLabel(get_text("Raw Control", "原始控制")) + left_title = QtWidgets.QLabel(TEXT("Raw Control", "原始控制")) left_title.setStyleSheet("font-weight: bold;") self.layouts["left_content_layout"].addWidget(left_title) @@ -481,7 +459,7 @@ class BehaviourUI(ui_utils.BaseUI): self.layouts["right_content_layout"].setSpacing(5) # 添加标题标签 - right_title = QtWidgets.QLabel(get_text("Related BlendShapes", "相关BlendShapes")) + right_title = QtWidgets.QLabel(TEXT("Related BlendShapes", "相关BlendShapes")) right_title.setStyleSheet("font-weight: bold;") self.layouts["right_content_layout"].addWidget(right_title) diff --git a/scripts/ui/definition.py b/scripts/ui/definition.py index 3faf97b..ffa8485 100644 --- a/scripts/ui/definition.py +++ b/scripts/ui/definition.py @@ -11,8 +11,8 @@ Definition UI Module for Plugin - 工具:重新定位头部关节,重新定位身体关节,重新定位全身关节,快速创建预设 """ #========================================= IMPORT ========================================= -from Qt import QtWidgets, QtCore, QtGui -from Qt.QtCompat import wrapInstance +from scripts.ui.Qt import QtWidgets, QtCore, QtGui +from scripts.ui.Qt.QtCompat import wrapInstance from maya import OpenMayaUI as omui import maya.cmds as cmds import maya.mel as mel @@ -51,8 +51,7 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT #========================================= LOCATION ======================================= from scripts.ui import localization -LANG = localization.LANG -get_text = localization.get_text +TEXT = localization.TEXT class DefinitionUI(ui_utils.BaseUI): """ @@ -64,27 +63,19 @@ class DefinitionUI(ui_utils.BaseUI): """ 初始化定义系统UI """ - super(DefinitionUI, self).__init__() # 不传递parent参数给BaseUI - - # 设置单例实例 - DefinitionUI._instance = self + super().__init__(parent) # 创建主控件 - self.main_widget = QtWidgets.QWidget(parent) + self.main_widget = QtWidgets.QWidget() self.main_widget.setObjectName("definitionMainWidget") - # 初始化控件、布局和按钮字典 - self.controls = {} - self.layouts = {} - self.buttons = {} - self.splitters = {} - # 创建UI组件 self.create_widgets() self.create_layouts() self.create_connections() - - # 注意:移除了这里的分割器元素添加代码 + + # 更新UI文本 + self.update_language() #========================================= WIDGET ======================================= def create_widgets(self): @@ -93,7 +84,7 @@ class DefinitionUI(ui_utils.BaseUI): 包括按钮、标签、列表等 """ # 标题标签 - 使用HTML格式化标题 - title_text = f"

{get_text('definition_title', 'DNA定义')}

" + title_text = f"

{TEXT('definition_title', 'DNA定义')}

" self.controls["title_label"] = QtWidgets.QLabel(title_text) self.controls["title_label"].setObjectName("definitionTitleLabel") self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter) @@ -124,7 +115,7 @@ class DefinitionUI(ui_utils.BaseUI): self.controls["lods_list"].setObjectName("lodsList") # 定义LOD关联按钮 - self.buttons["define_lod_relations"] = QtWidgets.QPushButton(get_text("define_lod_relations", "定义LOD关联")) + self.buttons["define_lod_relations"] = QtWidgets.QPushButton(TEXT("define_lod_relations", "定义LOD关联")) self.buttons["define_lod_relations"].setIcon(ui_utils.load_icon("layerEditor.png")) self.buttons["define_lod_relations"].setObjectName("defineLodRelationsButton") @@ -137,7 +128,7 @@ class DefinitionUI(ui_utils.BaseUI): self.controls["meshes_list"].setObjectName("meshesList") # 创建几何体按钮 - self.buttons["create_geometry"] = QtWidgets.QPushButton(get_text("create_geometry", "创建几何体")) + self.buttons["create_geometry"] = QtWidgets.QPushButton(TEXT("create_geometry", "创建几何体")) self.buttons["create_geometry"].setIcon(ui_utils.load_icon("polyCube.png")) self.buttons["create_geometry"].setObjectName("createGeometryButton") @@ -168,61 +159,61 @@ class DefinitionUI(ui_utils.BaseUI): # 底部工具面板 # 写入部分 - self.controls["write_label"] = QtWidgets.QLabel(get_text("Write", "写入")) + self.controls["write_label"] = QtWidgets.QLabel(TEXT("Write", "写入")) self.controls["write_label"].setObjectName("WriteLabel") self.controls["write_label"].setAlignment(QtCore.Qt.AlignCenter) - self.buttons["write_neutral_pose_joint_position"] = QtWidgets.QPushButton(get_text("Write Neutral Pose Joint Position", "写入中性Pose关节位置")) + self.buttons["write_neutral_pose_joint_position"] = QtWidgets.QPushButton(TEXT("Write Neutral Pose Joint Position", "写入中性Pose关节位置")) self.buttons["write_neutral_pose_joint_position"].setIcon(ui_utils.load_icon("HIKCharacterToolBodyPart.png")) self.buttons["write_neutral_pose_joint_position"].setObjectName("WriteNeutralPoseJointPositionButton") - self.buttons["write_geometry"] = QtWidgets.QPushButton(get_text("Write Geometry", "写入几何体")) + self.buttons["write_geometry"] = QtWidgets.QPushButton(TEXT("Write Geometry", "写入几何体")) self.buttons["write_geometry"].setIcon(ui_utils.load_icon("polyCube.png")) self.buttons["write_geometry"].setObjectName("WriteGeometryButton") - self.buttons["write_skin_weight"] = QtWidgets.QPushButton(get_text("Write Skin Weight", "写入蒙皮权重")) + self.buttons["write_skin_weight"] = QtWidgets.QPushButton(TEXT("Write Skin Weight", "写入蒙皮权重")) self.buttons["write_skin_weight"].setIcon(ui_utils.load_icon("paintSkinWeights.png")) self.buttons["write_skin_weight"].setObjectName("WriteSkinWeightButton") - self.buttons["write_blendshape_target"] = QtWidgets.QPushButton(get_text("Write Blendshape Target", "写入BS对象")) + self.buttons["write_blendshape_target"] = QtWidgets.QPushButton(TEXT("Write Blendshape Target", "写入BS对象")) self.buttons["write_blendshape_target"].setIcon(ui_utils.load_icon("blendShape.png")) self.buttons["write_blendshape_target"].setObjectName("WriteBlendshapeTargetButton") # 创建部分 - self.controls["create_label"] = QtWidgets.QLabel(get_text("Create", "创建")) + self.controls["create_label"] = QtWidgets.QLabel(TEXT("Create", "创建")) self.controls["create_label"].setObjectName("CreateLabel") self.controls["create_label"].setAlignment(QtCore.Qt.AlignCenter) - self.buttons["create_blendshapes_for_mesh"] = QtWidgets.QPushButton(get_text("Create Blendshapes For Mesh", "为模型创建Blendshape")) + self.buttons["create_blendshapes_for_mesh"] = QtWidgets.QPushButton(TEXT("Create Blendshapes For Mesh", "为模型创建Blendshape")) self.buttons["create_blendshapes_for_mesh"].setIcon(ui_utils.load_icon("blendShapeEditor.png")) self.buttons["create_blendshapes_for_mesh"].setObjectName("CreateBlendshapeForMeshButton") - self.buttons["create_skin_for_mesh"] = QtWidgets.QPushButton(get_text("Create Skin For Mesh", "为模型创建绑定蒙皮")) + self.buttons["create_skin_for_mesh"] = QtWidgets.QPushButton(TEXT("Create Skin For Mesh", "为模型创建绑定蒙皮")) self.buttons["create_skin_for_mesh"].setIcon(ui_utils.load_icon("smoothSkin.png")) self.buttons["create_skin_for_mesh"].setObjectName("CreateSkinForMeshButton") - self.buttons["unbind_skin_for_mesh"] = QtWidgets.QPushButton(get_text("Unbind Skin For Mesh", "为模型取消绑定蒙皮")) + self.buttons["unbind_skin_for_mesh"] = QtWidgets.QPushButton(TEXT("Unbind Skin For Mesh", "为模型取消绑定蒙皮")) self.buttons["unbind_skin_for_mesh"].setIcon(ui_utils.load_icon("detachSkin.png")) self.buttons["unbind_skin_for_mesh"].setObjectName("UnbindSkinForMeshButton") # 工具部分 - self.controls["tools_label"] = QtWidgets.QGroupBox(get_text("Tools", "工具")) + self.controls["tools_label"] = QtWidgets.QGroupBox(TEXT("Tools", "工具")) self.controls["tools_label"].setObjectName("ToolsLabel") self.controls["tools_label"].setAlignment(QtCore.Qt.AlignCenter) - self.buttons["new_head_netural_joint_transform"] = QtWidgets.QPushButton(get_text("New Head Netural Joint Transform", "重新定位头部关节")) + self.buttons["new_head_netural_joint_transform"] = QtWidgets.QPushButton(TEXT("New Head Netural Joint Transform", "重新定位头部关节")) self.buttons["new_head_netural_joint_transform"].setIcon(ui_utils.load_icon("HIKCharacterToolSkeleton.png")) self.buttons["new_head_netural_joint_transform"].setObjectName("NewHeadNeturalJointTransformButton") - self.buttons["new_body_netural_joint_transform"] = QtWidgets.QPushButton(get_text("New Body Netural Joint Transform", "重新定位身体关节")) + self.buttons["new_body_netural_joint_transform"] = QtWidgets.QPushButton(TEXT("New Body Netural Joint Transform", "重新定位身体关节")) self.buttons["new_body_netural_joint_transform"].setIcon(ui_utils.load_icon("HIKCharacterToolSkeleton.png")) self.buttons["new_body_netural_joint_transform"].setObjectName("NewBodyNeturalJointTransformButton") - self.buttons["new_netural_joint_transform"] = QtWidgets.QPushButton(get_text("New Netural Joint Transform", "重新定位全身关节")) + self.buttons["new_netural_joint_transform"] = QtWidgets.QPushButton(TEXT("New Netural Joint Transform", "重新定位全身关节")) self.buttons["new_netural_joint_transform"].setIcon(ui_utils.load_icon("HIKCharacterToolSkeleton.png")) self.buttons["new_netural_joint_transform"].setObjectName("NewNeturalJointTransformButton") - self.buttons["quick_create_preset"] = QtWidgets.QPushButton(get_text("Quick Create Preset", "快速创建预设")) + self.buttons["quick_create_preset"] = QtWidgets.QPushButton(TEXT("Quick Create Preset", "快速创建预设")) self.buttons["quick_create_preset"].setIcon(ui_utils.load_icon("QR_QuickRigTool.png")) self.buttons["quick_create_preset"].setObjectName("QuickCreatePreset") @@ -324,7 +315,7 @@ class DefinitionUI(ui_utils.BaseUI): self.layouts["bottom_panel"].setSpacing(10) # 写入部分QGroupBox - self.controls["write_group"] = QtWidgets.QGroupBox(get_text("Write", "写入")) + self.controls["write_group"] = QtWidgets.QGroupBox(TEXT("Write", "写入")) self.controls["write_group"].setObjectName("writeGroup") self.layouts["write_layout"] = QtWidgets.QVBoxLayout() self.layouts["write_layout"].setSpacing(5) @@ -336,7 +327,7 @@ class DefinitionUI(ui_utils.BaseUI): self.controls["write_group"].setLayout(self.layouts["write_layout"]) # 创建部分QGroupBox - self.controls["create_group"] = QtWidgets.QGroupBox(get_text("Create", "创建")) + self.controls["create_group"] = QtWidgets.QGroupBox(TEXT("Create", "创建")) self.controls["create_group"].setObjectName("createGroup") self.layouts["create_layout"] = QtWidgets.QVBoxLayout() self.layouts["create_layout"].setSpacing(5) @@ -347,7 +338,7 @@ class DefinitionUI(ui_utils.BaseUI): self.controls["create_group"].setLayout(self.layouts["create_layout"]) # 工具部分QGroupBox - self.controls["tools_group"] = QtWidgets.QGroupBox(get_text("Tools", "工具")) + self.controls["tools_group"] = QtWidgets.QGroupBox(TEXT("Tools", "工具")) self.controls["tools_group"].setObjectName("toolsGroup") self.layouts["tools_layout"] = QtWidgets.QVBoxLayout() self.layouts["tools_layout"].setSpacing(5) diff --git a/scripts/ui/geometry.py b/scripts/ui/geometry.py index b0415ab..28d9d3c 100644 --- a/scripts/ui/geometry.py +++ b/scripts/ui/geometry.py @@ -16,8 +16,8 @@ Geometry UI Module for Plugin - 修复点序 """ #========================================= IMPORT ========================================= -from Qt import QtWidgets, QtCore, QtGui -from Qt.QtCompat import wrapInstance +from scripts.ui.Qt import QtWidgets, QtCore, QtGui +from scripts.ui.Qt.QtCompat import wrapInstance from maya import OpenMayaUI as omui import maya.cmds as cmds import maya.mel as mel @@ -56,22 +56,16 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT #========================================= LOCATION ======================================= from scripts.ui import localization -LANG = localization.LANG -get_text = localization.get_text +TEXT = localization.TEXT class GeometryUI(ui_utils.BaseUI): """ 几何模型UI类 - 负责显示几何模型编辑界面和基础操作 继承自BaseUI类,实现几何模型相关的UI功能 """ - #========================================== INIT ======================================== - def __init__(self): - """ - 初始化几何模型UI - 创建主控件和布局,并连接信号和槽 - """ - super(GeometryUI, self).__init__() - + # 只继承BaseUI,不自定义单例相关代码 + def __init__(self, parent=None): + super().__init__(parent) # 创建主控件 self.main_widget = QtWidgets.QWidget() self.main_widget.setObjectName("geometryMainWidget") @@ -80,6 +74,9 @@ class GeometryUI(ui_utils.BaseUI): self.create_widgets() self.create_layouts() self.create_connections() + + # 更新UI文本 + self.update_language() #========================================= WIDGET ======================================= def create_widgets(self): @@ -88,7 +85,7 @@ class GeometryUI(ui_utils.BaseUI): 包括按钮、标签、列表等 """ # 标题标签 - 使用HTML格式化标题 - title_text = f"

{get_text('geometry_title', '几何模型')}

" + title_text = f"

{TEXT('geometry_title', '几何模型')}

" self.controls["title_label"] = QtWidgets.QLabel(title_text) self.controls["title_label"].setObjectName("geometryTitleLabel") self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter) @@ -107,115 +104,6 @@ class GeometryUI(ui_utils.BaseUI): # 创建底部功能按钮区域 self.create_bottom_buttons() - - # 模型列表 - self.controls["model_list"] = QtWidgets.QListWidget() - self.controls["model_list"].setObjectName("modelList") - - # 模型操作按钮 - self.buttons["add_model"] = QtWidgets.QPushButton(get_text("add_model", "添加模型")) - self.buttons["add_model"].setObjectName("addModelButton") - - self.buttons["remove_model"] = QtWidgets.QPushButton(get_text("remove_model", "移除模型")) - self.buttons["remove_model"].setObjectName("removeModelButton") - - self.buttons["duplicate_model"] = QtWidgets.QPushButton(get_text("duplicate_model", "复制模型")) - self.buttons["duplicate_model"].setObjectName("duplicateModelButton") - - # 右侧面板控件 - 模型属性 - self.controls["model_properties_group"] = QtWidgets.QGroupBox(get_text("model_properties", "模型属性")) - self.controls["model_properties_group"].setObjectName("modelPropertiesGroup") - - # 模型名称标签和输入框 - self.controls["model_name_label"] = QtWidgets.QLabel(get_text("name", "名称:")) - self.controls["model_name_label"].setObjectName("modelNameLabel") - - self.controls["model_name_input"] = QtWidgets.QLineEdit() - self.controls["model_name_input"].setObjectName("modelNameInput") - self.controls["model_name_input"].setPlaceholderText(get_text("enter_model_name", "输入模型名称")) - - # 模型类型标签和下拉框 - self.controls["model_type_label"] = QtWidgets.QLabel(get_text("type", "类型:")) - self.controls["model_type_label"].setObjectName("modelTypeLabel") - - self.controls["model_type_combo"] = QtWidgets.QComboBox() - self.controls["model_type_combo"].setObjectName("modelTypeCombo") - self.controls["model_type_combo"].addItems(["Base", "Head", "Body", "Accessory", "Other"]) - - # 模型可见性复选框 - self.controls["model_visible_check"] = QtWidgets.QCheckBox(get_text("visible", "可见")) - self.controls["model_visible_check"].setObjectName("modelVisibleCheck") - self.controls["model_visible_check"].setChecked(True) - - # 模型属性按钮 - self.buttons["apply_properties"] = QtWidgets.QPushButton(get_text("apply", "应用")) - self.buttons["apply_properties"].setObjectName("applyPropertiesButton") - - self.buttons["reset_properties"] = QtWidgets.QPushButton(get_text("reset", "重置")) - self.buttons["reset_properties"].setObjectName("resetPropertiesButton") - - # 右侧面板控件 - 模型工具 - self.controls["model_tools_group"] = QtWidgets.QGroupBox(get_text("model_tools", "模型工具")) - self.controls["model_tools_group"].setObjectName("modelToolsGroup") - - # 模型工具按钮 - self.buttons["standardize_names"] = QtWidgets.QPushButton(get_text("standardize_names", "标准化命名")) - self.buttons["standardize_names"].setObjectName("standardizeNamesButton") - - self.buttons["auto_group"] = QtWidgets.QPushButton(get_text("auto_group", "自动分组")) - self.buttons["auto_group"].setObjectName("autoGroupButton") - - self.buttons["generate_accessories"] = QtWidgets.QPushButton(get_text("generate_accessories", "生成配件")) - self.buttons["generate_accessories"].setObjectName("generateAccessoriesButton") - - self.buttons["fix_seams"] = QtWidgets.QPushButton(get_text("fix_seams", "修复接缝")) - self.buttons["fix_seams"].setObjectName("fixSeamsButton") - - self.buttons["fix_vertex_order"] = QtWidgets.QPushButton(get_text("fix_vertex_order", "修复点序")) - self.buttons["fix_vertex_order"].setObjectName("fixVertexOrderButton") - - # 底部工具面板 - # 导入部分 - self.controls["import_group"] = QtWidgets.QGroupBox(get_text("import", "导入")) - self.controls["import_group"].setObjectName("importGroup") - - self.buttons["import_model"] = QtWidgets.QPushButton(get_text("import_model", "导入模型")) - self.buttons["import_model"].setObjectName("importModelButton") - - self.buttons["import_fbx"] = QtWidgets.QPushButton(get_text("import_fbx", "导入FBX")) - self.buttons["import_fbx"].setObjectName("importFbxButton") - - self.buttons["import_obj"] = QtWidgets.QPushButton(get_text("import_obj", "导入OBJ")) - self.buttons["import_obj"].setObjectName("importObjButton") - - # 导出部分 - self.controls["export_group"] = QtWidgets.QGroupBox(get_text("export", "导出")) - self.controls["export_group"].setObjectName("exportGroup") - - self.buttons["export_model"] = QtWidgets.QPushButton(get_text("export_model", "导出模型")) - self.buttons["export_model"].setObjectName("exportModelButton") - - self.buttons["export_fbx"] = QtWidgets.QPushButton(get_text("export_fbx", "导出 FBX")) - self.buttons["export_fbx"].setObjectName("exportFbxButton") - - self.buttons["export_obj"] = QtWidgets.QPushButton(get_text("export_obj", "导出 OBJ")) - self.buttons["export_obj"].setObjectName("exportObjButton") - - # 工具部分 - self.controls["tools_group"] = QtWidgets.QGroupBox(get_text("tools", "工具")) - self.controls["tools_group"].setObjectName("toolsGroup") - - self.buttons["check_model"] = QtWidgets.QPushButton(get_text("check_model", "检查模型")) - self.buttons["check_model"].setObjectName("checkModelButton") - - self.buttons["optimize_model"] = QtWidgets.QPushButton(get_text("optimize_model", "优化模型")) - self.buttons["optimize_model"].setObjectName("optimizeModelButton") - - self.buttons["clean_model"] = QtWidgets.QPushButton(get_text("clean_model", "清理模型")) - self.buttons["clean_model"].setObjectName("cleanModelButton") - - self.buttons["uv_tools"] = QtWidgets.QPushButton(get_text("uv_tools", "UV工具")) - self.buttons["uv_tools"].setObjectName("uvToolsButton") def create_lod_tabs(self): """ @@ -274,15 +162,15 @@ class GeometryUI(ui_utils.BaseUI): # 输入框 line_edit = QtWidgets.QLineEdit() - line_edit.setPlaceholderText(get_text("enter_model_name", "输入模型名称")) + line_edit.setPlaceholderText(TEXT("enter_model_name", "输入模型名称")) line_edit.setObjectName(f"{lod_name}_{part}_input") - # 创建加载按钮(统一插件风格) - load_button = QtWidgets.QPushButton(get_text(" load ", " 加 载 ")) - load_button.setObjectName("{TOOL_NAME}LoadButton") + # 创建加载按钮(统一风格) + load_button = QtWidgets.QPushButton(TEXT("load", " 加 载 ")) + load_button.setObjectName("LoadButton") load_button.setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "loading.png"))) load_button.setIconSize(QtCore.QSize(16, 16)) - load_button.setToolTip(get_text("load_model", "加载模型")) + load_button.setToolTip(TEXT("load_model", "加载模型")) load_button.setFixedSize(105, 24) # 更紧凑,和输入框高度完全一致 load_button.setStyleSheet(""" QPushButton { @@ -308,24 +196,57 @@ class GeometryUI(ui_utils.BaseUI): # 添加弹性空间 tab_layout.addStretch(1) - + + # === 添加LOD专属底部三大按钮 === + lod_buttons_layout = QtWidgets.QHBoxLayout() + lod_buttons_layout.setContentsMargins(0, 0, 0, 0) + lod_buttons_layout.setSpacing(10) + + btn_auto_load = QtWidgets.QPushButton(TEXT("auto_load_meshes", "自动加载模型")) + btn_auto_load.setIcon(ui_utils.load_icon("load_meshes.png")) + btn_auto_load.setIconSize(QtCore.QSize(20, 20)) + btn_auto_load.setObjectName(f"{lod_name}_autoLoadMeshesButton") + btn_auto_load.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + + btn_standardized = QtWidgets.QPushButton(TEXT("standardized_naming", "标准化命名")) + btn_standardized.setIcon(ui_utils.load_icon("standardized_naming.png")) + btn_standardized.setIconSize(QtCore.QSize(20, 20)) + btn_standardized.setObjectName(f"{lod_name}_standardizedNamingButton") + btn_standardized.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + + btn_auto_group = QtWidgets.QPushButton(TEXT("automatic_grouping", "自动分组")) + btn_auto_group.setIcon(ui_utils.load_icon("automatic_grouping.png")) + btn_auto_group.setIconSize(QtCore.QSize(20, 20)) + btn_auto_group.setObjectName(f"{lod_name}_automaticGroupingButton") + btn_auto_group.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + + lod_buttons_layout.addWidget(btn_auto_load, 1) + lod_buttons_layout.addWidget(btn_standardized, 1) + lod_buttons_layout.addWidget(btn_auto_group, 1) + + tab_layout.addLayout(lod_buttons_layout) + # 保存引用(如需后续操作) + self.buttons[f"{lod_name}_auto_load_meshes"] = btn_auto_load + self.buttons[f"{lod_name}_standardized_naming"] = btn_standardized + self.buttons[f"{lod_name}_automatic_grouping"] = btn_auto_group + # 将标签页添加到标签页控件 self.controls["tab_widget"].addTab(tab, lod_name) # 创建清理按钮 - self.buttons["clean"] = QtWidgets.QPushButton(get_text("clean", " 清 理 ")) - self.buttons["clean"].setObjectName("clearButton") - self.buttons["clean"].setIcon(ui_utils.load_icon("delete.png")) - self.buttons["clean"].setIconSize(QtCore.QSize(16, 16)) - self.buttons["clean"].setFixedSize(150, 28) - self.buttons["clean"].setToolTip(get_text("clear_all_models", "清理所有模型")) - self.buttons["clean"].setStyleSheet(""" + self.buttons["clear"] = QtWidgets.QPushButton(TEXT("clear", " 清 理 ")) + self.buttons["clear"].setObjectName("clearButton") + self.buttons["clear"].setIcon(ui_utils.load_icon("delete.png")) + self.buttons["clear"].setIconSize(QtCore.QSize(16, 16)) + self.buttons["clear"].setFixedSize(150, 28) + self.buttons["clear"].setToolTip(TEXT("clear_all_models", "清理所有模型")) + self.buttons["clear"].setStyleSheet(""" QPushButton { padding: 2px 2px; margin: 0px 50px 0px 0px; /* 上右下左的边距,增加上边距避免与标签栏重叠 */ } """) - self.buttons["clean"].setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + self.buttons["clear"].setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) def create_bottom_buttons(self): """ @@ -344,7 +265,7 @@ class GeometryUI(ui_utils.BaseUI): bottom_layout.setSpacing(5) # 创建模型工具区域 - model_tools_group = QtWidgets.QGroupBox(get_text("model_tools", "模型工具")) + model_tools_group = QtWidgets.QGroupBox(TEXT("model_tools", "模型工具")) model_tools_group.setObjectName("modelToolsGroup") # 创建模型工具布局 @@ -365,7 +286,7 @@ class GeometryUI(ui_utils.BaseUI): topology_container_layout = QtWidgets.QHBoxLayout(topology_container) topology_container_layout.setContentsMargins(5, 5, 5, 5) - topology_label = QtWidgets.QLabel(get_text("topology_structure", "拓扑结构") + ":") + topology_label = QtWidgets.QLabel(TEXT("topology_structure", "拓扑结构") + ":") self.controls["topology_combo"] = QtWidgets.QComboBox() self.controls["topology_combo"].setObjectName("topologyCombo") self.controls["topology_combo"].addItem("MetaHuman") @@ -379,10 +300,10 @@ class GeometryUI(ui_utils.BaseUI): lod_container_layout = QtWidgets.QHBoxLayout(lod_container) lod_container_layout.setContentsMargins(5, 5, 5, 5) - lod_label = QtWidgets.QLabel(get_text("select_lod", "选择LOD") + ":") + lod_label = QtWidgets.QLabel(TEXT("select_lod", "选择LOD") + ":") self.controls["lod_combo"] = QtWidgets.QComboBox() self.controls["lod_combo"].setObjectName("lodCombo") - self.controls["lod_combo"].addItem(get_text("all", "全部")) + self.controls["lod_combo"].addItem(TEXT("all", "全部")) for i in range(8): # LOD0~LOD7 self.controls["lod_combo"].addItem(f"LOD{i}") @@ -395,7 +316,7 @@ class GeometryUI(ui_utils.BaseUI): button_container_layout = QtWidgets.QHBoxLayout(button_container) button_container_layout.setContentsMargins(5, 5, 5, 5) - self.buttons["create_lod"] = QtWidgets.QPushButton(get_text("create_lod", "创建LOD")) + self.buttons["create_lod"] = QtWidgets.QPushButton(TEXT("create_lod", "创建LOD")) self.buttons["create_lod"].setObjectName("createLodButton") self.buttons["create_lod"].setIcon(ui_utils.load_icon("create_lod.png")) self.buttons["create_lod"].setMinimumHeight(30) @@ -413,31 +334,26 @@ class GeometryUI(ui_utils.BaseUI): # 将水平布局添加到模型工具布局 model_tools_layout.addLayout(self.layouts["top_row_layout"], 0, 0, 1, 5) - # 创建模型工具按钮 - # 设置按钮的尺寸策略,使其均等撑满一行 + # 保留原有按钮行布局 size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) - - # 创建每行按钮的布局 self.layouts["buttons_row1_layout"] = QtWidgets.QHBoxLayout() self.layouts["buttons_row1_layout"].setContentsMargins(0, 0, 0, 0) self.layouts["buttons_row1_layout"].setSpacing(10) - self.layouts["buttons_row2_layout"] = QtWidgets.QHBoxLayout() self.layouts["buttons_row2_layout"].setContentsMargins(0, 0, 0, 0) self.layouts["buttons_row2_layout"].setSpacing(10) - self.layouts["buttons_row3_layout"] = QtWidgets.QHBoxLayout() self.layouts["buttons_row3_layout"].setContentsMargins(0, 0, 0, 0) self.layouts["buttons_row3_layout"].setSpacing(10) # 第一行按钮 - self.buttons["separate_model"] = QtWidgets.QPushButton(get_text("separate_model", "模型分离")) + self.buttons["separate_model"] = QtWidgets.QPushButton(TEXT("separate_model", "模型分离")) self.buttons["separate_model"].setObjectName("separateModelButton") self.buttons["separate_model"].setIcon(ui_utils.load_icon("polySplitVertex.png")) self.buttons["separate_model"].setMinimumHeight(30) self.buttons["separate_model"].setSizePolicy(size_policy) - self.buttons["generate_face_components"] = QtWidgets.QPushButton(get_text("generate_face_components", "生成面部配件")) + self.buttons["generate_face_components"] = QtWidgets.QPushButton(TEXT("generate_face_components", "生成面部配件")) self.buttons["generate_face_components"].setObjectName("generateFaceComponentsButton") self.buttons["generate_face_components"].setIcon(ui_utils.load_icon("meshes.png")) self.buttons["generate_face_components"].setMinimumHeight(30) @@ -448,13 +364,13 @@ class GeometryUI(ui_utils.BaseUI): self.layouts["buttons_row1_layout"].addWidget(self.buttons["generate_face_components"]) # 第二行按钮 - self.buttons["fix_normals"] = QtWidgets.QPushButton(get_text("fix_normals", "修复法线")) + self.buttons["fix_normals"] = QtWidgets.QPushButton(TEXT("fix_normals", "修复法线")) self.buttons["fix_normals"].setObjectName("fixNormalsButton") self.buttons["fix_normals"].setIcon(ui_utils.load_icon("repair_normals.png")) self.buttons["fix_normals"].setMinimumHeight(30) self.buttons["fix_normals"].setSizePolicy(size_policy) - self.buttons["fix_vertex_order"] = QtWidgets.QPushButton(get_text("fix_vertex_order", "修复点序")) + self.buttons["fix_vertex_order"] = QtWidgets.QPushButton(TEXT("fix_vertex_order", "修复点序")) self.buttons["fix_vertex_order"].setObjectName("fixVertexOrderButton") self.buttons["fix_vertex_order"].setIcon(ui_utils.load_icon("repair_vertex_order.png")) self.buttons["fix_vertex_order"].setMinimumHeight(30) @@ -465,13 +381,13 @@ class GeometryUI(ui_utils.BaseUI): self.layouts["buttons_row2_layout"].addWidget(self.buttons["fix_vertex_order"]) # 第三行按钮 - self.buttons["fix_seams"] = QtWidgets.QPushButton(get_text("fix_seams", "修复接缝")) + self.buttons["fix_seams"] = QtWidgets.QPushButton(TEXT("fix_seams", "修复接缝")) self.buttons["fix_seams"].setObjectName("fixSeamsButton") self.buttons["fix_seams"].setIcon(ui_utils.load_icon("polyChipOff.png")) self.buttons["fix_seams"].setMinimumHeight(30) self.buttons["fix_seams"].setSizePolicy(size_policy) - self.buttons["optimize_scene"] = QtWidgets.QPushButton(get_text("optimize_scene", "优化场景")) + self.buttons["optimize_scene"] = QtWidgets.QPushButton(TEXT("optimize_scene", "优化场景")) self.buttons["optimize_scene"].setObjectName("optimizeSceneButton") self.buttons["optimize_scene"].setIcon(ui_utils.load_icon("singlePerspLayout.png")) self.buttons["optimize_scene"].setMinimumHeight(30) @@ -505,7 +421,7 @@ class GeometryUI(ui_utils.BaseUI): # 将清理按钮直接添加到标签页控件的右上角 # 设置标签页控件的角落部件 - self.controls["tab_widget"].setCornerWidget(self.buttons["clean"], QtCore.Qt.TopRightCorner) + self.controls["tab_widget"].setCornerWidget(self.buttons["clear"], QtCore.Qt.TopRightCorner) # 添加标签页控件到主布局 self.layouts["main_layout"].addWidget(self.controls["tab_widget"]) @@ -563,7 +479,7 @@ class GeometryUI(ui_utils.BaseUI): ) # 连接清理按钮 - self.buttons["clean"].clicked.connect(utils_geometry.clean) + self.buttons["clear"].clicked.connect(utils_geometry.clean) # 连接拓扑结构下拉框 self.controls["topology_combo"].currentIndexChanged.connect(utils_geometry.update_topology) diff --git a/scripts/ui/localization.py b/scripts/ui/localization.py index 5a6fb3d..aaf47d9 100644 --- a/scripts/ui/localization.py +++ b/scripts/ui/localization.py @@ -13,124 +13,6 @@ current_language = config.TOOL_LANG # 默认使用中文 # 语言字典 LANG = { - "en_US": { - # 主界面 - "geometry": "Geometry", - "rigging": "Rigging", - "behaviour": "Behaviour", - "definition": "Definition", - - # 几何体模块 - "geometry_title": "Geometry", - "clean": " Clean ", - "load": "Load mesh", - "clear_all_models": " Clean all models", - "add_model": "Add Model", - "remove_model": "Remove Model", - "duplicate_model": "Duplicate Model", - "model_properties": "Model Properties", - "model_tools": "Model Tools", - "name": "Name", - "enter_model_name": "Enter Model Name", - "type": "Type", - "visible": "Visible", - "apply": "Apply", - "reset": "Reset", - "topology_structure": "Topology Structure", - "select_lod": "Select LOD", - "all": "All", - "create_lod": "Create LOD", - "separate_model": "Separate Model", - "generate_face_components": "Generate Face Components", - "fix_point_order": "Fix point order", - "fix_normals": "Fix normal", - "fix_vertex_order": "Fix vertex order", - "fix_seams": "Fix seams", - "standardize_naming": "Standardize Naming", - "optimize_scene": "Optimize Scene", - "auto_group": "Auto Group", - "create_custom_lod": "Create Custom LOD", - "import_lod": "Import LOD", - "export_lod": "Export LOD", - "search": "Search...", - - # 绑定模块 - "rigging_title": "Rigging System", - "presets": "Presets", - "assets": "Assets", - "descriptor": "Descriptor", - "project_path": "Project Path", - "Presets DNA:": "Presets DNA:", - "gender": "Gender", - "age": "Age", - "translation_unit": "Translation Unit", - "rotation_unit": "Rotation Unit", - "coordinate_system": "Coordinate System", - "lod_count": "LOD Count", - "archetype": "Archetype", - "import_skeleton": "Import Skeleton", - "build_rigging": "Build Rigging", - "remove_all": "Remove All", - - # 行为模块 - "behaviour_title": "Behaviour System", - "search": "Search...", - " Range - ": " Range - ", - " Range + ": " Range + ", - "Raw Control": "Raw Control", - "Related BlendShapes": "Related BlendShapes", - "Add": "Add", - "Delete": "Delete", - "Batch": "Batch", - "Rebuild": "Rebuild", - "Reposition": "Reposition", - "Blend": "Blend", - "Flip Target": "Flip Target", - "Mirror Target": "Mirror Target", - "Find Flip Target": "Find Flip Target", - "Add BlendShape": "Add BlendShape", - "Delete BlendShape": "Delete BlendShape", - "Batch BlendShape": "Batch BlendShape", - "Rebuild Select": "Rebuild Select", - "Reposition Joints": "Reposition Joints", - "Blend Select": "Blend Select", - "Reset Default": "Reset Default", - "Find Select": "Find Select", - "Write Current": "Write Current", - "Controller Find": "Controller Find", - "Select Joint": "Select Joint", - "Find Mirror": "Find Mirror", - - # 定义模块 - "definition_title": "Definition System", - "lods": "LODs", - "meshes": "Meshes", - "bones": "Bones", - "name_pattern": "Name Pattern", - "expression": "Expression", - "add_lod": "Add LOD", - "remove_lod": "Remove LOD", - "duplicate_lod": "Duplicate LOD", - "add_mesh": "Add Mesh", - "remove_mesh": "Remove Mesh", - "duplicate_mesh": "Duplicate Mesh", - "add_bone": "Add Bone", - "remove_bone": "Remove Bone", - "duplicate_bone": "Duplicate Bone", - "import_definition": "Import Definition", - "export_definition": "Export Definition", - - # 工具栏 - "Save DNA": "Save DNA", - "Open DNA": "Open DNA", - "Create RL4 node": "Create RL4 Node", - "Delete RL4 node": "Delete RL4 Node", - "Import skin": "Import Skin", - "Export skin": "Export Skin", - "Copy skin": "Copy Skin", - "Switch language": "Switch Language", - "Help": "Help" - }, "zh_CN": { # 主界面 "geometry": "几何体", @@ -140,55 +22,46 @@ LANG = { # 几何体模块 "geometry_title": "几何模型", - "clean": " 清 理 ", - "load": " 加 载 ", - "clear_all_models": " 清理所有模型", - "add_model": "添加模型", - "remove_model": "移除模型", - "duplicate_model": "复制模型", - "model_properties": "模型属性", - "model_tools": "模型工具", - "name": "名称", "enter_model_name": "输入模型名称", - "type": "类型", - "visible": "可见", - "apply": "应用", - "reset": "重置", + "load": " 加 载 ", + "load_model": "加载模型", + "auto_load_meshes": "自动加载模型", + "standardized_naming": "标准化命名", + "automatic_grouping": "自动分组", + "clear": " 清 理 ", + "clear_all_models": "清理所有模型", + "model_tools": "模型工具", "topology_structure": "拓扑结构", "select_lod": "选择LOD", "all": "全部", "create_lod": "创建LOD", "separate_model": "模型分离", "generate_face_components": "生成面部配件", - "fix_point_order": "修复点序", "fix_normals": "修复法线", "fix_vertex_order": "修复点序", "fix_seams": "修复接缝", - "standardize_naming": "标准化命名", "optimize_scene": "优化场景", - "auto_group": "自动分组", - "create_custom_lod": "创建自定义LOD", - "import_lod": "导入LOD", - "export_lod": "导出LOD", - "search": "搜索...", # 绑定模块 "rigging_title": "绑定系统", "presets": "预设", - "assets": "资源", - "descriptor": "描述器", - "project_path": "项目路径", + "export_presets": "导出预设", + "import_presets": "导入预设", + "assets": "资产", + "project_path": "项目路径:", "Presets DNA:": "预设 DNA:", - "gender": "性别", - "age": "年龄", - "translation_unit": "平移单位", - "rotation_unit": "旋转单位", - "coordinate_system": "坐标系统", - "lod_count": "LOD数量", - "archetype": "原型", + "descriptor": "描述", + "name": "名称:", + "archetype": "原型:", + "gender": "性别:", + "age": "年龄:", + "translation_unit": "平移单位:", + "rotation_unit": "旋转单位:", + "coordinate_system": "坐标系统:", + "lod_count": "LOD数量:", + "remove_all": "移除全部", "import_skeleton": "导入骨骼", "build_rigging": "创建绑定", - "remove_all": "移除全部", # 行为模块 "behaviour_title": "行为系统", @@ -221,23 +94,21 @@ LANG = { # 定义模块 "definition_title": "定义系统", - "lods": "级别细节", - "meshes": "网格", - "bones": "骨骼", - "name_pattern": "命名模式", - "expression": "表情", - "add_lod": "添加LOD", - "remove_lod": "移除LOD", - "duplicate_lod": "复制LOD", - "add_mesh": "添加网格", - "remove_mesh": "移除网格", - "duplicate_mesh": "复制网格", - "add_bone": "添加骨骼", - "remove_bone": "移除骨骼", - "duplicate_bone": "复制骨骼", - "import_definition": "导入定义", - "export_definition": "导出定义", - + "define_lod_relations": "定义LOD关联", + "create_geometry": "创建几何体", + "Write Neutral Pose Joint Position": "写入中性Pose关节位置", + "Write Geometry": "写入几何体", + "Write Skin Weight": "写入蒙皮权重", + "Write Blendshape Target": "写入BS对象", + "Create Blendshapes For Mesh": "为模型创建Blendshape", + "Create Skin For Mesh": "为模型创建绑定蒙皮", + "Unbind Skin For Mesh": "为模型取消绑定蒙皮", + "Tools": "工具", + "New Head Netural Joint Transform": "重新定位头部关节", + "New Body Netural Joint Transform": "重新定位身体关节", + "New Netural Joint Transform": "重新定位全身关节", + "Quick Create Preset": "快速创建预设", + # 工具栏 "保存DNA": "保存DNA", "打开DNA": "打开DNA", @@ -248,10 +119,117 @@ LANG = { "复制蒙皮": "复制蒙皮", "切换语言": "切换语言", "帮助": "帮助" + }, + "en_US": { + # Main Interface + "geometry": "Geometry", + "rigging": "Rigging", + "behaviour": "Behaviour", + "definition": "Definition", + + # Geometry Module + "geometry_title": "Geometry Model", + "enter_model_name": "Enter Model Name", + "load": "Load", + "load_model": "Load Model", + "auto_load_meshes": "Auto Load Meshes", + "standardized_naming": "Standardized Naming", + "automatic_grouping": "Automatic Grouping", + "clear": "Clear", + "clear_all_models": "Clear All Models", + "model_tools": "Model Tools", + "topology_structure": "Topology Structure", + "select_lod": "Select LOD", + "all": "All", + "create_lod": "Create LOD", + "separate_model": "Separate Model", + "generate_face_components": "Generate Face Components", + "fix_normals": "Fix Normals", + "fix_vertex_order": "Fix Vertex Order", + "fix_seams": "Fix Seams", + "optimize_scene": "Optimize Scene", + + # Rigging Module + "rigging_title": "Rigging System", + "presets": "Presets", + "export_presets": "Export Presets", + "import_presets": "Import Presets", + "assets": "Assets", + "project_path": "Project Path:", + "Presets DNA:": "Presets DNA:", + "descriptor": "Descriptor", + "name": "Name:", + "archetype": "Archetype:", + "gender": "Gender:", + "age": "Age:", + "translation_unit": "Translation Unit:", + "rotation_unit": "Rotation Unit:", + "coordinate_system": "Coordinate System:", + "lod_count": "LOD Count:", + "remove_all": "Remove All", + "import_skeleton": "Import Skeleton", + "build_rigging": "Build Rigging", + + # Behaviour Module + "behaviour_title": "Behaviour System", + "search": "Search...", + " Range - ": " Range - ", + " Range + ": " Range + ", + "Raw Control": "Raw Control", + "Related BlendShapes": "Related BlendShapes", + "Add": "Add", + "Delete": "Delete", + "Batch": "Batch", + "Rebuild": "Rebuild", + "Reposition": "Reposition", + "Blend": "Blend", + "Flip Target": "Flip Target", + "Mirror Target": "Mirror Target", + "Find Flip Target": "Find Flip Target", + "Add BlendShape": "Add BlendShape", + "Delete BlendShape": "Delete BlendShape", + "Batch BlendShape": "Batch BlendShape", + "Rebuild Select": "Rebuild Select", + "Reposition Joints": "Reposition Joints", + "Blend Select": "Blend Select", + "Reset Default": "Reset Default", + "Find Select": "Find Select", + "Write Current": "Write Current", + "Controller Find": "Controller Find", + "Select Joint": "Select Joint", + "Find Mirror": "Find Mirror", + + # Definition Module + "definition_title": "Definition System", + "define_lod_relations": "Define LOD Relations", + "create_geometry": "Create Geometry", + "Write Neutral Pose Joint Position": "Write Neutral Pose Joint Position", + "Write Geometry": "Write Geometry", + "Write Skin Weight": "Write Skin Weight", + "Write Blendshape Target": "Write BlendShape Target", + "Create Blendshapes For Mesh": "Create BlendShapes For Mesh", + "Create Skin For Mesh": "Create Skin For Mesh", + "Unbind Skin For Mesh": "Unbind Skin For Mesh", + "Tools": "Tools", + "New Head Netural Joint Transform": "Relocate Head Joint", + "New Body Netural Joint Transform": "Relocate Body Joint", + "New Netural Joint Transform": "Relocate All Joints", + "Quick Create Preset": "Quick Create Preset", + + # Toolbar + "保存DNA": "Save DNA", + "打开DNA": "Open DNA", + "创建RL4节点": "Create RL4 Node", + "删除RL4节点": "Delete RL4 Node", + "导入蒙皮": "Import Skin", + "导出蒙皮": "Export Skin", + "复制蒙皮": "Copy Skin", + "切换语言": "Switch Language", + "帮助": "Help" } } -def get_text(key, default=None): +def TEXT(key, default=None): """ 获取当前语言的文本 diff --git a/scripts/ui/rigging.py b/scripts/ui/rigging.py index 30380ae..cc16e29 100644 --- a/scripts/ui/rigging.py +++ b/scripts/ui/rigging.py @@ -14,8 +14,8 @@ Rigging UI Module for Plugin - 复制蒙皮 """ #========================================= IMPORT ========================================= -from Qt import QtWidgets, QtCore, QtGui -from Qt.QtCompat import wrapInstance +from scripts.ui.Qt import QtWidgets, QtCore, QtGui +from scripts.ui.Qt.QtCompat import wrapInstance from maya import OpenMayaUI as omui import maya.cmds as cmds import maya.mel as mel @@ -54,8 +54,7 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT #========================================= LOCATION ======================================= from scripts.ui import localization -LANG = localization.LANG -get_text = localization.get_text +TEXT = localization.TEXT class RiggingUI(ui_utils.BaseUI): """ @@ -63,21 +62,13 @@ class RiggingUI(ui_utils.BaseUI): 继承自BaseUI类,实现绑定系统相关的UI功能 """ #========================================== INIT ======================================== - def __init__(self): + def __init__(self, parent=None): """ 初始化绑定系统UI 创建主控件和布局,并连接信号和槽 """ - super(RiggingUI, self).__init__() - - # 初始化字典 - self.controls = {} - self.layouts = {} - self.buttons = {} - self.splitters = {} - self.inputs = {} - self.labels = {} - + super().__init__(parent) + # 创建主控件 self.main_widget = QtWidgets.QWidget() self.main_widget.setObjectName("riggingMainWidget") @@ -86,6 +77,9 @@ class RiggingUI(ui_utils.BaseUI): self.create_widgets() self.create_layouts() self.create_connections() + + # 更新UI文本 + self.update_language() #========================================= WIDGET ======================================= def create_widgets(self): @@ -94,7 +88,7 @@ class RiggingUI(ui_utils.BaseUI): 包括按钮、标签、列表等 """ # 标题标签 - 使用HTML格式化标题 - title_text = f"

{get_text('rigging_title', '骨骼绑定')}

" + title_text = f"

{TEXT('rigging_title', '骨骼绑定')}

" self.controls["title_label"] = QtWidgets.QLabel(title_text) self.controls["title_label"].setObjectName("riggingTitleLabel") self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter) @@ -109,7 +103,7 @@ class RiggingUI(ui_utils.BaseUI): self.controls["presets_panel"].setObjectName("presetsPanel") # Presets 组 - self.controls["presets_group"] = QtWidgets.QGroupBox(get_text("presets", "Presets")) + self.controls["presets_group"] = QtWidgets.QGroupBox(TEXT("presets", "Presets")) self.controls["presets_group"].setObjectName("presetsGroup") # 创建预设显示区域 @@ -190,12 +184,12 @@ class RiggingUI(ui_utils.BaseUI): self.controls["presets_slider"].setValue(50) # 导出预设按钮 - self.buttons["export_presets"] = QtWidgets.QPushButton(get_text("export_presets", "导出预设")) + self.buttons["export_presets"] = QtWidgets.QPushButton(TEXT("export_presets", "导出预设")) self.buttons["export_presets"].setObjectName("exportPresetsButton") self.buttons["export_presets"].setIcon(ui_utils.load_icon("export")) # 导入预设按钮 - self.buttons["import_presets"] = QtWidgets.QPushButton(get_text("import_presets", "导入预设")) + self.buttons["import_presets"] = QtWidgets.QPushButton(TEXT("import_presets", "导入预设")) self.buttons["import_presets"].setObjectName("importPresetsButton") self.buttons["import_presets"].setIcon(ui_utils.load_icon("import")) @@ -210,11 +204,11 @@ class RiggingUI(ui_utils.BaseUI): self.controls["assets_panel"].setObjectName("assetsPanel") # Assets 组 - self.controls["assets_group"] = QtWidgets.QGroupBox(get_text("assets", "Assets")) + self.controls["assets_group"] = QtWidgets.QGroupBox(TEXT("assets", "资产")) self.controls["assets_group"].setObjectName("assetsGroup") # 项目路径标签和输入框 - self.controls["project_path_label"] = QtWidgets.QLabel(get_text("project_path", "项目路径:")) + self.controls["project_path_label"] = QtWidgets.QLabel(TEXT("project_path", "项目路径:")) self.controls["project_path_label"].setObjectName("projectPathLabel") self.controls["project_path_input"] = QtWidgets.QLineEdit() @@ -229,7 +223,7 @@ class RiggingUI(ui_utils.BaseUI): self.buttons["browse_path"].setFixedWidth(100) # Presets DNA 标签和输入框 - self.controls["presets_dna_label"] = QtWidgets.QLabel(get_text("Presets DNA:", "预设 DNA:")) + self.controls["presets_dna_label"] = QtWidgets.QLabel(TEXT("Presets DNA:", "预设 DNA:")) self.controls["presets_dna_label"].setObjectName("presetsDnaLabel") self.controls["presets_dna_input"] = QtWidgets.QLineEdit() @@ -247,18 +241,18 @@ class RiggingUI(ui_utils.BaseUI): self.controls["descriptor_panel"].setObjectName("descriptorPanel") # Descriptor 组 - self.controls["descriptor_group"] = QtWidgets.QGroupBox(get_text("descriptor", "Descriptor")) + self.controls["descriptor_group"] = QtWidgets.QGroupBox(TEXT("descriptor", "描述")) self.controls["descriptor_group"].setObjectName("descriptorGroup") # 名称标签和输入框 - self.controls["name_label"] = QtWidgets.QLabel(get_text("name", "名称:")) + self.controls["name_label"] = QtWidgets.QLabel(TEXT("name", "名称:")) self.controls["name_label"].setObjectName("nameLabel") self.controls["name_input"] = QtWidgets.QLineEdit() self.controls["name_input"].setObjectName("nameInput") # 原型标签和下拉框 - self.controls["archetype_label"] = QtWidgets.QLabel(get_text("archetype", "原型:")) + self.controls["archetype_label"] = QtWidgets.QLabel(TEXT("archetype", "原型:")) self.controls["archetype_label"].setObjectName("archetypeLabel") self.controls["archetype_combo"] = QtWidgets.QComboBox() @@ -268,7 +262,7 @@ class RiggingUI(ui_utils.BaseUI): self.controls["archetype_combo"].addItem("african") # 性别标签和下拉框 - self.controls["gender_label"] = QtWidgets.QLabel(get_text("gender", "性别:")) + self.controls["gender_label"] = QtWidgets.QLabel(TEXT("gender", "性别:")) self.controls["gender_label"].setObjectName("genderLabel") self.controls["gender_combo"] = QtWidgets.QComboBox() @@ -277,7 +271,7 @@ class RiggingUI(ui_utils.BaseUI): self.controls["gender_combo"].addItem("male") # 年龄标签和输入框 - self.controls["age_label"] = QtWidgets.QLabel(get_text("age", "年龄:")) + self.controls["age_label"] = QtWidgets.QLabel(TEXT("age", "年龄:")) self.controls["age_label"].setObjectName("ageLabel") self.controls["age_spinner"] = QtWidgets.QSpinBox() @@ -287,7 +281,7 @@ class RiggingUI(ui_utils.BaseUI): self.controls["age_spinner"].setValue(24) # 平移单位标签和下拉框 - self.controls["translation_unit_label"] = QtWidgets.QLabel(get_text("translation_unit", "平移单位:")) + self.controls["translation_unit_label"] = QtWidgets.QLabel(TEXT("translation_unit", "平移单位:")) self.controls["translation_unit_label"].setObjectName("translationUnitLabel") self.controls["translation_unit_combo"] = QtWidgets.QComboBox() @@ -297,7 +291,7 @@ class RiggingUI(ui_utils.BaseUI): self.controls["translation_unit_combo"].addItem("m") # 旋转单位标签和下拉框 - self.controls["rotation_unit_label"] = QtWidgets.QLabel(get_text("rotation_unit", "旋转单位:")) + self.controls["rotation_unit_label"] = QtWidgets.QLabel(TEXT("rotation_unit", "旋转单位:")) self.controls["rotation_unit_label"].setObjectName("rotationUnitLabel") self.controls["rotation_unit_combo"] = QtWidgets.QComboBox() @@ -306,7 +300,7 @@ class RiggingUI(ui_utils.BaseUI): self.controls["rotation_unit_combo"].addItem("radians") # 坐标系统标签和下拉框 - self.controls["coordinate_system_label"] = QtWidgets.QLabel(get_text("coordinate_system", "坐标系统:")) + self.controls["coordinate_system_label"] = QtWidgets.QLabel(TEXT("coordinate_system", "坐标系统:")) self.controls["coordinate_system_label"].setObjectName("coordinateSystemLabel") self.controls["coordinate_system_combo"] = QtWidgets.QComboBox() @@ -315,7 +309,7 @@ class RiggingUI(ui_utils.BaseUI): self.controls["coordinate_system_combo"].addItem("ZAxisUp") # LOD数量标签和输入框 - self.controls["lod_count_label"] = QtWidgets.QLabel(get_text("lod_count", "LOD数量:")) + self.controls["lod_count_label"] = QtWidgets.QLabel(TEXT("lod_count", "LOD数量:")) self.controls["lod_count_label"].setObjectName("lodCountLabel") self.controls["lod_count_spinner"] = QtWidgets.QSpinBox() @@ -329,17 +323,17 @@ class RiggingUI(ui_utils.BaseUI): self.controls["bottom_buttons_panel"].setObjectName("bottomButtonsPanel") # 删除所有按钮 - self.buttons["remove_all"] = QtWidgets.QPushButton(get_text("remove_all", "删除所有")) + self.buttons["remove_all"] = QtWidgets.QPushButton(TEXT("remove_all", "删除全部")) self.buttons["remove_all"].setObjectName("removeAllButton") self.buttons["remove_all"].setIcon(ui_utils.load_icon("delete.png")) # 导入骨骼按钮 - self.buttons["import_skeleton"] = QtWidgets.QPushButton(get_text("import_skeleton", "导入骨骼")) + self.buttons["import_skeleton"] = QtWidgets.QPushButton(TEXT("import_skeleton", "导入骨骼")) self.buttons["import_skeleton"].setObjectName("importSkeletonButton") self.buttons["import_skeleton"].setIcon(ui_utils.load_icon("HIKCharacterToolSkeleton.png")) # 生成绑定按钮 - self.buttons["build_rigging"] = QtWidgets.QPushButton(get_text("build_rigging", "生成绑定")) + self.buttons["build_rigging"] = QtWidgets.QPushButton(TEXT("build_rigging", "创建绑定")) self.buttons["build_rigging"].setObjectName("buildRiggingButton") self.buttons["build_rigging"].setIcon(ui_utils.load_icon("HIKcreateControlRig.png")) diff --git a/scripts/ui/style.qss b/scripts/ui/style.qss index ba5c826..a0ab76e 100644 --- a/scripts/ui/style.qss +++ b/scripts/ui/style.qss @@ -1,5 +1,4 @@ /* 插件样式表 */ -/* 作者: Virtuos Games */ /* 版本: Alpha v1.0.0 */ /* ==================== 全局样式 ==================== */ diff --git a/scripts/ui/toolbar.py b/scripts/ui/toolbar.py index 6f520ac..01ed98b 100644 --- a/scripts/ui/toolbar.py +++ b/scripts/ui/toolbar.py @@ -13,8 +13,8 @@ Toolbar UI Module for Plugin - 删除RL4节点(用于切换DNA编辑的状态) """ #========================================= IMPORT ========================================= -from Qt import QtWidgets, QtCore, QtGui -from Qt.QtCompat import wrapInstance +from scripts.ui.Qt import QtWidgets, QtCore, QtGui +from scripts.ui.Qt.QtCompat import wrapInstance from maya import OpenMayaUI as omui import maya.cmds as cmds import maya.mel as mel @@ -28,7 +28,6 @@ import sys import os from scripts.ui import ui_utils from scripts.utils import utils_toolbar -from scripts.ui.localization import get_text #========================================== CONFIG ======================================== import config TOOL_NAME = config.TOOL_NAME @@ -54,36 +53,20 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT #========================================= LOCATION ======================================= from scripts.ui import localization -LANG = localization.LANG +TEXT = localization.TEXT class ToolbarUI(ui_utils.BaseUI): """ 工具栏UI类 - 负责显示工具栏界面和基础操作 继承自BaseUI类,实现工具栏相关的UI功能 """ - # 类变量,存储单例实例 - _instance = None - - @classmethod - def get_instance(cls): - """ - 获取ToolbarUI的单例实例 - - Returns: - ToolbarUI: 单例实例,如果不存在则返回None - """ - return cls._instance - #========================================== INIT ======================================== - def __init__(self): + def __init__(self, parent=None): """ 初始化工具栏UI 创建主控件和布局,并连接信号和槽 """ - super(ToolbarUI, self).__init__() - - # 设置单例实例 - ToolbarUI._instance = self + super().__init__(parent) # 创建主控件 self.main_widget = QtWidgets.QWidget() @@ -135,7 +118,7 @@ class ToolbarUI(ui_utils.BaseUI): checkable: 是否可选中 """ button = QtWidgets.QPushButton() - button.setToolTip(get_text(tooltip, tooltip)) + button.setToolTip(TEXT(tooltip, tooltip)) # 构建图标完整路径 icon_path = os.path.join(ICONS_PATH, icon_name) @@ -146,7 +129,7 @@ class ToolbarUI(ui_utils.BaseUI): button.setIconSize(QtCore.QSize(24, 24)) else: # 如果图标不存在,使用文字 - button.setText(get_text(tooltip, tooltip)) + button.setText(TEXT(tooltip, tooltip)) button.setObjectName(f"{tooltip.replace(' ', '_').lower()}_button") button.setFixedSize(32, 32) diff --git a/scripts/ui/ui_utils.py b/scripts/ui/ui_utils.py index 4e94f87..59f4e68 100644 --- a/scripts/ui/ui_utils.py +++ b/scripts/ui/ui_utils.py @@ -6,8 +6,8 @@ UI Utilities Module for Plugin UI工具模块 - 提供UI相关的通用函数 """ #========================================= IMPORT ========================================= -from Qt import QtWidgets, QtCore, QtGui -from Qt.QtCompat import wrapInstance +from scripts.ui.Qt import QtWidgets, QtCore, QtGui +from scripts.ui.Qt.QtCompat import wrapInstance from maya import OpenMayaUI as omui import maya.cmds as cmds import maya.mel as mel @@ -47,16 +47,15 @@ TOOL_HEIGHT = config.TOOL_HEIGHT #========================================= LOCATION ======================================= from scripts.ui import localization -LANG = localization.LANG - +TEXT = localization.TEXT #============================================ UI BASE ========================================== -class BaseUI(object): +class BaseUI(QtWidgets.QWidget): """ UI基类 所有UI面板的基类,提供通用的UI功能 """ - def __init__(self): - """初始化UI基类""" + def __init__(self, parent=None): + super().__init__(parent) # 初始化字典 self.controls = {} self.layouts = {} @@ -64,7 +63,6 @@ class BaseUI(object): self.splitters = {} self.inputs = {} self.labels = {} - # 创建主控件 self.main_widget = None @@ -82,10 +80,23 @@ class BaseUI(object): def update_language(self): """ - 更新所有UI文本到当前语言 + 递归刷新所有UI控件文本,支持多语言切换 """ - if self.main_widget: - update_ui_texts(self.main_widget) + from scripts.ui import localization + # 批量刷新注册字典中的控件 + for group in [self.controls, self.labels, self.buttons, getattr(self, 'inputs', {}), getattr(self, 'splitters', {})]: + for key, widget in group.items(): + # QLabel/QPushButton/QCheckBox/QRadioButton等 + if hasattr(widget, 'setText'): + widget.setText(TEXT(key, widget.text() if hasattr(widget, 'text') else "")) + # QLineEdit等 + elif hasattr(widget, 'setPlaceholderText'): + widget.setPlaceholderText(TEXT(key, widget.placeholderText() if hasattr(widget, 'placeholderText') else "")) + # 递归刷新所有自定义子UI(即BaseUI子类) + for child in self.findChildren(QtWidgets.QWidget): + if child is not self and hasattr(child, 'update_language') and callable(child.update_language): + child.update_language() + #============================================ UI HELPERS ========================================== def connect_ui_signals(ui_instance, signal_mapping): @@ -268,7 +279,7 @@ def update_ui_texts(widget): for lang in ["zh_CN", "en_US"]: for key, text in localization.LANG.get(lang, {}).items(): if text == current_text: - widget.setText(localization.get_text(key, current_text)) + widget.setText(TEXT(key, current_text)) break # 更新按钮文本和工具提示 @@ -279,7 +290,7 @@ def update_ui_texts(widget): for lang in ["zh_CN", "en_US"]: for key, text in localization.LANG.get(lang, {}).items(): if text == current_text: - widget.setText(localization.get_text(key, current_text)) + widget.setText(TEXT(key, current_text)) break # 更新工具提示 @@ -288,7 +299,7 @@ def update_ui_texts(widget): for lang in ["zh_CN", "en_US"]: for key, text in localization.LANG.get(lang, {}).items(): if text == current_tip: - widget.setToolTip(localization.get_text(key, current_tip)) + widget.setToolTip(TEXT(key, current_tip)) break # 递归处理所有子控件 diff --git a/scripts/utils/utils_behaviour.py b/scripts/utils/utils_behaviour.py index 7d4b7c8..75b837d 100644 --- a/scripts/utils/utils_behaviour.py +++ b/scripts/utils/utils_behaviour.py @@ -44,7 +44,7 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT # Localization from scripts.ui import localization -LANG = localization.LANG +TEXT = localization.TEXT #========================================== FUNCTIONS ======================================== @@ -448,10 +448,10 @@ def update_raw_slider_value(value): normalized_value = value / 100.0 # 获取UI实例并更新显示 - from scripts.ui.behaviour import BehaviourUI - ui_instance = BehaviourUI.get_instance() - if ui_instance and hasattr(ui_instance, 'controls'): - ui_instance.controls["raw_slider_value"].setText(f"{normalized_value:.3f}") + from scripts.ui import behaviour + behaviour_ui = behaviour.BehaviourUI.get_instance() + if behaviour_ui and hasattr(behaviour_ui, 'controls'): + behaviour_ui.controls["raw_slider_value"].setText(f"{normalized_value:.3f}") # 更新控制值 update_control_value(value) @@ -472,10 +472,10 @@ def update_bs_slider_value(value): normalized_value = value / 100.0 # 获取UI实例并更新显示 - from scripts.ui.behaviour import BehaviourUI - ui_instance = BehaviourUI.get_instance() - if ui_instance and hasattr(ui_instance, 'controls'): - ui_instance.controls["bs_slider_value"].setText(f"{normalized_value:.3f}") + from scripts.ui import behaviour + behaviour_ui = behaviour.BehaviourUI.get_instance() + if behaviour_ui and hasattr(behaviour_ui, 'controls'): + behaviour_ui.controls["bs_slider_value"].setText(f"{normalized_value:.3f}") # 更新BlendShape值 update_blendshape_value(value) @@ -496,10 +496,10 @@ def update_bottom_slider_value(value): normalized_value = value / 100.0 # 获取UI实例并更新显示 - from scripts.ui.behaviour import BehaviourUI - ui_instance = BehaviourUI.get_instance() - if ui_instance and hasattr(ui_instance, 'controls'): - ui_instance.controls["bottom_slider_value"].setText(f"{normalized_value:.3f}") + from scripts.ui import behaviour + behaviour_ui = behaviour.BehaviourUI.get_instance() + if behaviour_ui and hasattr(behaviour_ui, 'controls'): + behaviour_ui.controls["bottom_slider_value"].setText(f"{normalized_value:.3f}") # 更新主值 update_main_value(value) diff --git a/scripts/utils/utils_definition.py b/scripts/utils/utils_definition.py index 77a8eea..f579153 100644 --- a/scripts/utils/utils_definition.py +++ b/scripts/utils/utils_definition.py @@ -44,7 +44,7 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT # Localization from scripts.ui import localization -LANG = localization.LANG +TEXT = localization.TEXT #========================================== FUNCTIONS ======================================== # 左侧面板功能 diff --git a/scripts/utils/utils_geometry.py b/scripts/utils/utils_geometry.py index 3a7d7db..81ff915 100644 --- a/scripts/utils/utils_geometry.py +++ b/scripts/utils/utils_geometry.py @@ -44,7 +44,7 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT # Localization from scripts.ui import localization -LANG = localization.LANG +TEXT = localization.TEXT #========================================== FUNCTIONS ======================================== # 左侧面板功能 @@ -439,15 +439,15 @@ def clean(): # 确认删除 result = cmds.confirmDialog( - title=LANG.get("confirm_delete", "确认删除"), - message=LANG.get("delete_lod_confirm", f"确定要删除{lod_name}吗?"), - button=[LANG.get("yes", "是"), LANG.get("no", "否")], - defaultButton=LANG.get("no", "否"), - cancelButton=LANG.get("no", "否"), - dismissString=LANG.get("no", "否") + title=TEXT("confirm_delete", "确认删除"), + message=TEXT("delete_lod_confirm", f"确定要删除{lod_name}吗?"), + button=[TEXT("yes", "是"), TEXT("no", "否")], + defaultButton=TEXT("no", "否"), + cancelButton=TEXT("no", "否"), + dismissString=TEXT("no", "否") ) - if result == LANG.get("yes", "是"): + if result == TEXT("yes", "是"): # 删除与该LOD相关的所有模型 nodes_to_delete = cmds.ls(f"{lod_name}_*") if nodes_to_delete: @@ -548,7 +548,7 @@ def separate_model(): # 获取当前选中的模型 selected_models = cmds.ls(selection=True, type="transform") if not selected_models: - cmds.warning(LANG.get("no_model_selected", "未选中模型")) + cmds.warning(TEXT("no_model_selected", "未选中模型")) return False # 对每个选中的模型进行分离 @@ -572,7 +572,7 @@ def fix_normals(): # 获取当前选中的模型 selected_models = cmds.ls(selection=True, type="transform") if not selected_models: - cmds.warning(LANG.get("no_model_selected", "未选中模型")) + cmds.warning(TEXT("no_model_selected", "未选中模型")) return False # 对每个选中的模型修复法线 @@ -626,7 +626,7 @@ def modify_topology(): # 获取当前选中的模型 selected_models = cmds.ls(selection=True, type="transform") if not selected_models: - cmds.warning(LANG.get("no_model_selected", "未选中模型")) + cmds.warning(TEXT("no_model_selected", "未选中模型")) return False # 切换到多边形编辑模式 @@ -649,7 +649,7 @@ def generate_face_components(): # 获取当前选中的模型 selected_models = cmds.ls(selection=True, type="transform") if not selected_models: - cmds.warning(LANG.get("no_model_selected", "未选中模型")) + cmds.warning(TEXT("no_model_selected", "未选中模型")) return False # 生成眉毛 @@ -676,7 +676,7 @@ def generate_uvs(): # 获取当前选中的模型 selected_models = cmds.ls(selection=True, type="transform") if not selected_models: - cmds.warning(LANG.get("no_model_selected", "未选中模型")) + cmds.warning(TEXT("no_model_selected", "未选中模型")) return False # 为每个选中的模型生成UV diff --git a/scripts/utils/utils_rigging.py b/scripts/utils/utils_rigging.py index a8e71e6..e490842 100644 --- a/scripts/utils/utils_rigging.py +++ b/scripts/utils/utils_rigging.py @@ -44,7 +44,7 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT # Localization from scripts.ui import localization -LANG = localization.LANG +TEXT = localization.TEXT #========================================== GLOBALS ======================================== # 存储当前选中的关节和控制器信息 diff --git a/scripts/utils/utils_toolbar.py b/scripts/utils/utils_toolbar.py index c975b1d..a30db88 100644 --- a/scripts/utils/utils_toolbar.py +++ b/scripts/utils/utils_toolbar.py @@ -39,10 +39,7 @@ TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT # Localization from scripts.ui import localization -LANG = localization.LANG - -# 添加全局变量记录当前语言 -current_language = "zh_CN" # 默认使用中文 +TEXT = localization.TEXT #========================================== FUNCTIONS ======================================== @@ -57,7 +54,7 @@ def save_dna(): fileFilter="DNA Files (*.dna);;All Files (*.*)", dialogStyle=2, fileMode=0, - caption=LANG.get("save_dna", "保存DNA文件") + caption=TEXT("save_dna", "保存DNA文件") ) if file_path and len(file_path) > 0: @@ -77,7 +74,7 @@ def open_dna(): fileFilter="DNA Files (*.dna);;All Files (*.*)", dialogStyle=2, fileMode=1, - caption=LANG.get("open_dna", "打开DNA文件") + caption=TEXT("open_dna", "打开DNA文件") ) if file_path and len(file_path) > 0: @@ -123,7 +120,7 @@ def import_skin(): fileFilter="Skin Files (*.skin);;XML Files (*.xml);;All Files (*.*)", dialogStyle=2, fileMode=1, - caption=LANG.get("import_skin", "导入蒙皮") + caption=TEXT("import_skin", "导入蒙皮") ) if file_path and len(file_path) > 0: @@ -143,7 +140,7 @@ def export_skin(): fileFilter="Skin Files (*.skin);;XML Files (*.xml);;All Files (*.*)", dialogStyle=2, fileMode=0, - caption=LANG.get("export_skin", "导出蒙皮") + caption=TEXT("export_skin", "导出蒙皮") ) if file_path and len(file_path) > 0: @@ -174,8 +171,8 @@ def show_help(): try: # 打开帮助文档或显示帮助对话框 help_dialog = QtWidgets.QMessageBox() - help_dialog.setWindowTitle(LANG.get("help_title", "帮助")) - help_dialog.setText(LANG.get("help_message", "该插件是一个用于自定义MetaHuman的Maya插件。\n\n详细信息请参考文档。")) + help_dialog.setWindowTitle(TEXT("help_title", "帮助")) + help_dialog.setText(TEXT("help_message", "该插件是一个用于自定义MetaHuman的Maya插件。\n\n详细信息请参考文档。")) help_dialog.setStandardButtons(QtWidgets.QMessageBox.Ok) help_dialog.exec_() except Exception as e: @@ -302,10 +299,10 @@ def show_help(): webbrowser.open(config.TOOL_HELP_URL) else: cmds.confirmDialog( - title=LANG.get("help", "帮助"), - message=LANG.get("help_not_available", "帮助文档暂不可用"), - button=[LANG.get("ok", "确定")], - defaultButton=LANG.get("ok", "确定") + title=TEXT("help", "帮助"), + message=TEXT("help_not_available", "帮助文档暂不可用"), + button=[TEXT("ok", "确定")], + defaultButton=TEXT("ok", "确定") ) except Exception as e: print(f"显示帮助信息时出错: {e}") @@ -360,15 +357,12 @@ def toggle_language(): """ from scripts.ui import localization import config - from ui.Qt import QtWidgets - + from scripts.ui.Qt import QtWidgets + # 使用localization模块来切换语言 new_language = localization.switch_language() - - # 更新配置 config.TOOL_LANG = new_language - - # 尝试更新已有窗口的语言,而不重启窗口 + try: # 查找主窗口 main_window = None @@ -376,37 +370,33 @@ def toggle_language(): if widget.objectName() == f"{config.TOOL_NAME}MainWindow" and isinstance(widget, QtWidgets.QWidget): main_window = widget break - + if main_window: # 更新主窗口标题 main_window.setWindowTitle(f"{config.TOOL_NAME} {config.TOOL_VERSION}") - - # 获取各个UI实例并更新语言 - from scripts.ui import geometry, rigging, behaviour, definition, toolbar - - # 更新各个模块的UI - if hasattr(geometry, 'GeometryUI') and geometry.GeometryUI.get_instance(): - geometry.GeometryUI.get_instance().update_language() - - if hasattr(rigging, 'RiggingUI') and rigging.RiggingUI.get_instance(): - rigging.RiggingUI.get_instance().update_language() - - if hasattr(behaviour, 'BehaviourUI') and behaviour.BehaviourUI.get_instance(): - behaviour.BehaviourUI.get_instance().update_language() - - if hasattr(definition, 'DefinitionUI') and definition.DefinitionUI.get_instance(): - definition.DefinitionUI.get_instance().update_language() - - # 更新工具栏 - if hasattr(toolbar, 'ToolbarUI') and hasattr(main_window, 'toolbar_ui'): - main_window.toolbar_ui.update_language() + + # 遍历主窗口的所有子控件,批量动态更新语言 + for child in main_window.findChildren(QtWidgets.QWidget): + # 只要有update_language方法就调用 + if hasattr(child, 'update_language') and callable(child.update_language): + try: + child.update_language() + except Exception as e: + print(f"更新语言失败: {child}: {e}") # 更新功能按钮文字 if hasattr(main_window, 'function_buttons'): for key, button in main_window.function_buttons.items(): - button.setText(localization.get_text(key)) + button.setText(localization.TEXT(key)) print(f"语言已切换到: {new_language}") + + # 切换语言后强制重载主窗口,保证所有UI和控件100%刷新 + from scripts.Main import main + for widget in QtWidgets.QApplication.allWidgets(): + if widget.objectName() == f"{config.TOOL_NAME}MainWindow" and isinstance(widget, QtWidgets.QWidget): + widget.close() + main() return except Exception as e: print(f"动态更新语言失败,将重启窗口: {e}")