This commit is contained in:
2025-05-06 08:33:33 +08:00
parent 8d6fa92690
commit 32c4ee33d6
3 changed files with 1260 additions and 1681 deletions

View File

@@ -60,251 +60,76 @@ class RiggingUI(ui_utils.BaseUI):
继承自BaseUI类实现绑定系统相关的UI功能
"""
#======================================= FUNCTIONS ======================================
def on_show_event(self, event):
def connect_ui_signals(self):
"""
显示事件处理
当面板显示时重置分割器大小
连接UI信号和槽
设置UI控件的事件处理函数
"""
self.reset_splitter_sizes()
super(RiggingUI, self).showEvent(event)
# 创建信号映射字典
signal_mapping = {
'buttons': {
'add_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.add_joint},
'remove_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.remove_joint},
'duplicate_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.duplicate_joint},
'add_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.add_controller},
'remove_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.remove_controller},
'duplicate_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.duplicate_controller},
'import_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.import_dna},
'export_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.export_dna},
'calibrate_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.calibrate_dna},
},
'splitters': {
'main_splitter': {'signal': 'splitterMoved', 'handler': lambda pos, index: ui_utils.on_splitter_moved(self, pos, index)},
}
}
# 使用ui_utils中的通用函数连接信号
ui_utils.connect_ui_signals(self, signal_mapping)
# 连接关节属性编辑控件
if hasattr(self, 'joint_name_edit'):
self.joint_name_edit.editingFinished.connect(lambda: utils_rigging.handle_joint_name_changed(self.joint_name_edit))
# 关节位置编辑
if hasattr(self, 'joint_pos_x_spin'):
self.joint_pos_x_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_position_changed(0, [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin]))
if hasattr(self, 'joint_pos_y_spin'):
self.joint_pos_y_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_position_changed(1, [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin]))
if hasattr(self, 'joint_pos_z_spin'):
self.joint_pos_z_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_position_changed(2, [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin]))
# 关节旋转编辑
if hasattr(self, 'joint_rot_x_spin'):
self.joint_rot_x_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_rotation_changed(0, [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin]))
if hasattr(self, 'joint_rot_y_spin'):
self.joint_rot_y_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_rotation_changed(1, [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin]))
if hasattr(self, 'joint_rot_z_spin'):
self.joint_rot_z_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_rotation_changed(2, [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin]))
# 关节缩放编辑
if hasattr(self, 'joint_scale_x_spin'):
self.joint_scale_x_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_scale_changed(0, [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin]))
if hasattr(self, 'joint_scale_y_spin'):
self.joint_scale_y_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_scale_changed(1, [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin]))
if hasattr(self, 'joint_scale_z_spin'):
self.joint_scale_z_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_scale_changed(2, [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin]))
# 关节属性应用和重置按钮
if "apply_joint_props_btn" in self.buttons:
pos_widgets = [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin] if all(hasattr(self, attr) for attr in ['joint_pos_x_spin', 'joint_pos_y_spin', 'joint_pos_z_spin']) else None
rot_widgets = [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin] if all(hasattr(self, attr) for attr in ['joint_rot_x_spin', 'joint_rot_y_spin', 'joint_rot_z_spin']) else None
scale_widgets = [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin] if all(hasattr(self, attr) for attr in ['joint_scale_x_spin', 'joint_scale_y_spin', 'joint_scale_z_spin']) else None
self.buttons["apply_joint_props_btn"].clicked.connect(lambda: utils_rigging.apply_joint_properties_from_ui(pos_widgets, rot_widgets, scale_widgets))
if "reset_joint_props_btn" in self.buttons:
pos_widgets = [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin] if all(hasattr(self, attr) for attr in ['joint_pos_x_spin', 'joint_pos_y_spin', 'joint_pos_z_spin']) else None
rot_widgets = [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin] if all(hasattr(self, attr) for attr in ['joint_rot_x_spin', 'joint_rot_y_spin', 'joint_rot_z_spin']) else None
scale_widgets = [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin] if all(hasattr(self, attr) for attr in ['joint_scale_x_spin', 'joint_scale_y_spin', 'joint_scale_z_spin']) else None
self.buttons["reset_joint_props_btn"].clicked.connect(lambda: utils_rigging.reset_joint_properties_ui(pos_widgets, rot_widgets, scale_widgets))
# 使用Maya的脚本任务来监听选择变化
ui_utils.connect_maya_selection_changed(self, utils_rigging.on_selection_changed)
def reset_splitter_sizes(self):
"""
重置分割器大小,确保左右栏宽度均等
"""
if self.splitters["main_splitter"]:
width = self.splitters["main_splitter"].width()
self.splitters["main_splitter"].setSizes([width // 2, width // 2])
def on_splitter_moved(self, pos, index):
"""
分割器移动事件处理
记录当前分割器位置
"""
utils_rigging.update_splitter_position(self.splitters["main_splitter"])
# 左侧面板 - 骨骼列表操作
def add_joint(self):
"""
添加关节
"""
utils_rigging.add_joint(self.controls["skeleton_list"])
def remove_joint(self):
"""
移除关节
"""
utils_rigging.remove_joint(self.controls["skeleton_list"])
def duplicate_joint(self):
"""
复制关节
"""
utils_rigging.duplicate_joint(self.controls["skeleton_list"])
def on_joint_selection_changed(self):
"""
关节选择变化事件
更新关节属性面板
"""
utils_rigging.update_joint_properties(
self.controls["skeleton_list"],
self.controls["joint_name_input"],
self.controls["joint_x_input"],
self.controls["joint_y_input"],
self.controls["joint_z_input"],
self.controls["joint_rx_input"],
self.controls["joint_ry_input"],
self.controls["joint_rz_input"],
self.controls["joint_sx_input"],
self.controls["joint_sy_input"],
self.controls["joint_sz_input"]
)
# 左侧面板 - 控制器列表操作
def add_controller(self):
"""
添加控制器
"""
utils_rigging.add_controller(self.controls["controller_list"])
def remove_controller(self):
"""
移除控制器
"""
utils_rigging.remove_controller(self.controls["controller_list"])
def duplicate_controller(self):
"""
复制控制器
"""
utils_rigging.duplicate_controller(self.controls["controller_list"])
def on_controller_selection_changed(self):
"""
控制器选择变化事件
更新控制器属性
"""
utils_rigging.update_controller_properties(self.controls["controller_list"])
# 右侧面板 - 关节属性
def on_joint_name_changed(self):
"""
关节名称变化事件
"""
utils_rigging.update_joint_name(
self.controls["skeleton_list"],
self.controls["joint_name_input"]
)
def on_joint_position_changed(self, axis):
"""
关节位置变化事件
"""
utils_rigging.update_joint_position(
self.controls["skeleton_list"],
axis,
self.controls[f"joint_{axis}_input"]
)
def on_joint_rotation_changed(self, axis):
"""
关节旋转变化事件
"""
utils_rigging.update_joint_rotation(
self.controls["skeleton_list"],
axis,
self.controls[f"joint_r{axis}_input"]
)
def on_joint_scale_changed(self, axis):
"""
关节缩放变化事件
"""
utils_rigging.update_joint_scale(
self.controls["skeleton_list"],
axis,
self.controls[f"joint_s{axis}_input"]
)
def apply_joint_properties(self):
"""
应用关节属性
"""
utils_rigging.apply_joint_properties(
self.controls["skeleton_list"],
self.controls["joint_name_input"],
self.controls["joint_x_input"],
self.controls["joint_y_input"],
self.controls["joint_z_input"],
self.controls["joint_rx_input"],
self.controls["joint_ry_input"],
self.controls["joint_rz_input"],
self.controls["joint_sx_input"],
self.controls["joint_sy_input"],
self.controls["joint_sz_input"]
)
def reset_joint_properties(self):
"""
重置关节属性
"""
utils_rigging.reset_joint_properties(
self.controls["skeleton_list"],
self.controls["joint_name_input"],
self.controls["joint_x_input"],
self.controls["joint_y_input"],
self.controls["joint_z_input"],
self.controls["joint_rx_input"],
self.controls["joint_ry_input"],
self.controls["joint_rz_input"],
self.controls["joint_sx_input"],
self.controls["joint_sy_input"],
self.controls["joint_sz_input"]
)
# 右侧面板 - 绑定工具
def create_binding(self):
"""
创建绑定
"""
utils_rigging.create_binding()
def copy_skin(self):
"""
复制蒙皮
"""
utils_rigging.copy_skin()
def mirror_skin(self):
"""
镜像蒙皮
"""
utils_rigging.mirror_skin()
def paint_weights(self):
"""
绘制权重
"""
utils_rigging.paint_weights()
# 底部工具面板 - DNA操作
def import_dna(self):
"""
导入DNA
"""
utils_rigging.import_dna()
def export_dna(self):
"""
导出DNA
"""
utils_rigging.export_dna()
def calibrate_dna(self):
"""
校准DNA
"""
utils_rigging.calibrate_dna()
# 底部工具面板 - 骨骼工具
def import_skeleton(self):
"""
导入骨骼
"""
utils_rigging.import_skeleton()
def export_skeleton(self):
"""
导出骨骼
"""
utils_rigging.export_skeleton()
def calibrate_skeleton(self):
"""
校准骨骼
"""
utils_rigging.calibrate_skeleton()
# 底部工具面板 - 绑定工具
def generate_controllers(self):
"""
生成控制器
"""
utils_rigging.generate_controllers()
def generate_body(self):
"""
生成身体
"""
utils_rigging.generate_body()
def clean_rigging(self):
"""
清理绑定
"""
utils_rigging.clean_rigging()
#========================================== INIT ========================================
def __init__(self):
"""
@@ -313,6 +138,14 @@ class RiggingUI(ui_utils.BaseUI):
"""
super(RiggingUI, self).__init__()
# 初始化字典
self.controls = {}
self.layouts = {}
self.buttons = {}
self.splitters = {}
self.inputs = {}
self.labels = {}
# 创建主控件
self.main_widget = QtWidgets.QWidget()
self.main_widget.setObjectName("riggingMainWidget")
@@ -320,7 +153,7 @@ class RiggingUI(ui_utils.BaseUI):
# 初始化UI
self.create_widgets()
self.create_layouts()
self.create_connections()
self.connect_ui_signals()
#========================================= WIDGET =======================================
def create_widgets(self):
@@ -335,36 +168,244 @@ class RiggingUI(ui_utils.BaseUI):
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
self.controls["title_label"].setMaximumHeight(30) # 限制标题高度
# 左侧面板
self.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("riggingLeftPanel")
# 创建主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Vertical)
self.splitters["main_splitter"].setObjectName("riggingMainSplitter")
# 右侧面板
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("riggingRightPanel")
# 1. Presets 面板
self.controls["presets_panel"] = QtWidgets.QWidget()
self.controls["presets_panel"].setObjectName("presetsPanel")
# 左侧面板控件 - 骨骼列表
self.controls["skeleton_group"] = QtWidgets.QGroupBox("Skeleton [000]")
self.controls["skeleton_group"].setObjectName("skeletonGroup")
# Presets 组
self.controls["presets_group"] = QtWidgets.QGroupBox(LANG.get("presets", "Presets"))
self.controls["presets_group"].setObjectName("presetsGroup")
# 骨骼列表
self.controls["skeleton_list"] = QtWidgets.QListWidget()
self.controls["skeleton_list"].setObjectName("skeletonList")
# 创建预设显示区域
self.controls["presets_scroll_area"] = QtWidgets.QScrollArea()
self.controls["presets_scroll_area"].setWidgetResizable(True)
self.controls["presets_scroll_area"].setObjectName("presetsScrollArea")
# 添加测试项目
for i in range(5):
item = QtWidgets.QListWidgetItem(f"Joint_{i}")
self.controls["skeleton_list"].addItem(item)
# 预设内容区域
self.controls["presets_content"] = QtWidgets.QWidget()
self.controls["presets_content"].setObjectName("presetsContent")
# 骨骼操作按钮
self.buttons["add_joint"] = QtWidgets.QPushButton(LANG.get("add_joint", "添加关节"))
self.buttons["add_joint"].setObjectName("addJointButton")
# 预设流布局
self.controls["presets_flow_layout"] = QtWidgets.QGridLayout(self.controls["presets_content"])
self.controls["presets_flow_layout"].setObjectName("presetsFlowLayout")
self.controls["presets_flow_layout"].setContentsMargins(5, 5, 5, 5)
self.controls["presets_flow_layout"].setSpacing(10)
self.buttons["remove_joint"] = QtWidgets.QPushButton(LANG.get("remove_joint", "移除关节"))
self.buttons["remove_joint"].setObjectName("removeJointButton")
# 添加测试预设项
for i in range(6): # 添加6个预设项如图中所示
col = i % 6
row = i // 6
preset_widget = QtWidgets.QWidget()
preset_widget.setObjectName(f"preset_{i}")
preset_widget.setMinimumSize(120, 150) # 设置预设项大小
preset_widget.setMaximumSize(120, 150)
# 预设布局
preset_layout = QtWidgets.QVBoxLayout(preset_widget)
preset_layout.setContentsMargins(0, 0, 0, 0)
preset_layout.setSpacing(2)
# 预设图片
preset_image = QtWidgets.QLabel()
preset_image.setObjectName(f"preset_image_{i}")
preset_image.setMinimumSize(120, 120)
preset_image.setMaximumSize(120, 120)
preset_image.setScaledContents(True)
preset_image.setStyleSheet("background-color: #333333; border: 1px solid #555555;")
# 加载测试图片
pixmap = QtGui.QPixmap(os.path.join(ASSETS_PATH, "metahuman_placeholder.png"))
if not pixmap.isNull():
preset_image.setPixmap(pixmap)
# 预设标签
preset_label = QtWidgets.QLabel("METAHUMAN")
preset_label.setObjectName(f"preset_label_{i}")
preset_label.setAlignment(QtCore.Qt.AlignCenter)
preset_label.setStyleSheet("color: white; background-color: rgba(0, 0, 0, 128);")
# 添加到布局
preset_layout.addWidget(preset_image)
preset_layout.addWidget(preset_label)
# 添加到流布局
self.controls["presets_flow_layout"].addWidget(preset_widget, row, col)
self.buttons["duplicate_joint"] = QtWidgets.QPushButton(LANG.get("duplicate_joint", "复制关节"))
self.buttons["duplicate_joint"].setObjectName("duplicateJointButton")
# 设置滚动区域内容
self.controls["presets_scroll_area"].setWidget(self.controls["presets_content"])
# 预设底部滑块和按钮
self.controls["presets_slider_layout"] = QtWidgets.QHBoxLayout()
self.controls["presets_slider_layout"].setContentsMargins(5, 5, 5, 5)
self.controls["presets_slider_layout"].setSpacing(5)
# 数量显示
self.controls["presets_count_label"] = QtWidgets.QLabel("99")
self.controls["presets_count_label"].setObjectName("presetsCountLabel")
self.controls["presets_count_label"].setAlignment(QtCore.Qt.AlignCenter)
self.controls["presets_count_label"].setStyleSheet("font-weight: bold;")
# 滑块
self.controls["presets_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.controls["presets_slider"].setObjectName("presetsSlider")
self.controls["presets_slider"].setMinimum(0)
self.controls["presets_slider"].setMaximum(100)
self.controls["presets_slider"].setValue(50)
# 导出预设按钮
self.buttons["export_presets"] = QtWidgets.QPushButton(LANG.get("export_presets", "导出预设"))
self.buttons["export_presets"].setObjectName("exportPresetsButton")
self.buttons["export_presets"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "export.png")))
# 导入预设按钮
self.buttons["import_presets"] = QtWidgets.QPushButton(LANG.get("import_presets", "导入预设"))
self.buttons["import_presets"].setObjectName("importPresetsButton")
self.buttons["import_presets"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "import.png")))
# 添加到滑块布局
self.controls["presets_slider_layout"].addWidget(self.controls["presets_count_label"])
self.controls["presets_slider_layout"].addWidget(self.controls["presets_slider"])
self.controls["presets_slider_layout"].addWidget(self.buttons["export_presets"])
self.controls["presets_slider_layout"].addWidget(self.buttons["import_presets"])
# 2. Assets 面板
self.controls["assets_panel"] = QtWidgets.QWidget()
self.controls["assets_panel"].setObjectName("assetsPanel")
# Assets 组
self.controls["assets_group"] = QtWidgets.QGroupBox(LANG.get("assets", "Assets"))
self.controls["assets_group"].setObjectName("assetsGroup")
# 项目路径标签和输入框
self.controls["project_path_label"] = QtWidgets.QLabel(LANG.get("project_path", "项目路径:"))
self.controls["project_path_label"].setObjectName("projectPathLabel")
self.controls["project_path_input"] = QtWidgets.QLineEdit()
self.controls["project_path_input"].setObjectName("projectPathInput")
self.controls["project_path_input"].setText("D:/Personal/Document/maya/SuperRiggingEditor/files/data/MetaHuman")
# 浏览按钮
self.buttons["browse_path"] = QtWidgets.QPushButton("...")
self.buttons["browse_path"].setObjectName("browsePathButton")
self.buttons["browse_path"].setFixedWidth(30)
# Presets DNA 标签和输入框
self.controls["presets_dna_label"] = QtWidgets.QLabel(LANG.get("presets_dna", "Presets DNA:"))
self.controls["presets_dna_label"].setObjectName("presetsDnaLabel")
self.controls["presets_dna_input"] = QtWidgets.QLineEdit()
self.controls["presets_dna_input"].setObjectName("presetsDnaInput")
# 浏览按钮
self.buttons["browse_dna"] = QtWidgets.QPushButton("...")
self.buttons["browse_dna"].setObjectName("browseDnaButton")
self.buttons["browse_dna"].setFixedWidth(30)
# 3. Descriptor 面板
self.controls["descriptor_panel"] = QtWidgets.QWidget()
self.controls["descriptor_panel"].setObjectName("descriptorPanel")
# Descriptor 组
self.controls["descriptor_group"] = QtWidgets.QGroupBox(LANG.get("descriptor", "Descriptor"))
self.controls["descriptor_group"].setObjectName("descriptorGroup")
# 名称标签和输入框
self.controls["name_label"] = QtWidgets.QLabel(LANG.get("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(LANG.get("archetype", "原型:"))
self.controls["archetype_label"].setObjectName("archetypeLabel")
self.controls["archetype_combo"] = QtWidgets.QComboBox()
self.controls["archetype_combo"].setObjectName("archetypeCombo")
self.controls["archetype_combo"].addItem("asian")
self.controls["archetype_combo"].addItem("caucasian")
self.controls["archetype_combo"].addItem("african")
# 性别标签和下拉框
self.controls["gender_label"] = QtWidgets.QLabel(LANG.get("gender", "性别:"))
self.controls["gender_label"].setObjectName("genderLabel")
self.controls["gender_combo"] = QtWidgets.QComboBox()
self.controls["gender_combo"].setObjectName("genderCombo")
self.controls["gender_combo"].addItem("female")
self.controls["gender_combo"].addItem("male")
# 年龄标签和输入框
self.controls["age_label"] = QtWidgets.QLabel(LANG.get("age", "年龄:"))
self.controls["age_label"].setObjectName("ageLabel")
self.controls["age_spinner"] = QtWidgets.QSpinBox()
self.controls["age_spinner"].setObjectName("ageSpinner")
self.controls["age_spinner"].setMinimum(1)
self.controls["age_spinner"].setMaximum(100)
self.controls["age_spinner"].setValue(18)
# 平移单位标签和下拉框
self.controls["translation_unit_label"] = QtWidgets.QLabel(LANG.get("translation_unit", "平移单位:"))
self.controls["translation_unit_label"].setObjectName("translationUnitLabel")
self.controls["translation_unit_combo"] = QtWidgets.QComboBox()
self.controls["translation_unit_combo"].setObjectName("translationUnitCombo")
self.controls["translation_unit_combo"].addItem("cm")
self.controls["translation_unit_combo"].addItem("mm")
self.controls["translation_unit_combo"].addItem("m")
# 旋转单位标签和下拉框
self.controls["rotation_unit_label"] = QtWidgets.QLabel(LANG.get("rotation_unit", "旋转单位:"))
self.controls["rotation_unit_label"].setObjectName("rotationUnitLabel")
self.controls["rotation_unit_combo"] = QtWidgets.QComboBox()
self.controls["rotation_unit_combo"].setObjectName("rotationUnitCombo")
self.controls["rotation_unit_combo"].addItem("degrees")
self.controls["rotation_unit_combo"].addItem("radians")
# 坐标系统标签和下拉框
self.controls["coordinate_system_label"] = QtWidgets.QLabel(LANG.get("coordinate_system", "坐标系统:"))
self.controls["coordinate_system_label"].setObjectName("coordinateSystemLabel")
self.controls["coordinate_system_combo"] = QtWidgets.QComboBox()
self.controls["coordinate_system_combo"].setObjectName("coordinateSystemCombo")
self.controls["coordinate_system_combo"].addItem("YAxisUp")
self.controls["coordinate_system_combo"].addItem("ZAxisUp")
# LOD数量标签和输入框
self.controls["lod_count_label"] = QtWidgets.QLabel(LANG.get("lod_count", "LOD数量:"))
self.controls["lod_count_label"].setObjectName("lodCountLabel")
self.controls["lod_count_spinner"] = QtWidgets.QSpinBox()
self.controls["lod_count_spinner"].setObjectName("lodCountSpinner")
self.controls["lod_count_spinner"].setMinimum(0)
self.controls["lod_count_spinner"].setMaximum(8)
self.controls["lod_count_spinner"].setValue(0)
# 底部按钮区域
self.controls["bottom_buttons_panel"] = QtWidgets.QWidget()
self.controls["bottom_buttons_panel"].setObjectName("bottomButtonsPanel")
# 删除所有按钮
self.buttons["remove_all"] = QtWidgets.QPushButton(LANG.get("remove_all", "删除所有"))
self.buttons["remove_all"].setObjectName("removeAllButton")
self.buttons["remove_all"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "delete.png")))
# 导入骨骼按钮
self.buttons["import_skeleton"] = QtWidgets.QPushButton(LANG.get("import_skeleton", "导入骨骼"))
self.buttons["import_skeleton"].setObjectName("importSkeletonButton")
self.buttons["import_skeleton"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "import_skeleton.png")))
# 生成绑定按钮
self.buttons["build_rigging"] = QtWidgets.QPushButton(LANG.get("build_rigging", "生成绑定"))
self.buttons["build_rigging"].setObjectName("buildRiggingButton")
self.buttons["build_rigging"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "build_rigging.png")))
# 左侧面板控件 - 控制器列表
self.controls["controller_group"] = QtWidgets.QGroupBox("Controllers [000]")
@@ -546,291 +587,126 @@ class RiggingUI(ui_utils.BaseUI):
创建绑定系统UI布局
组织控件的排列和层次结构
"""
# 主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(2, 2, 2, 2)
self.layouts["main_layout"].setSpacing(2)
# 创建主布局
main_layout = QtWidgets.QVBoxLayout(self.main_widget)
main_layout.setContentsMargins(5, 5, 5, 5)
main_layout.setSpacing(5)
# 添加标题标签
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 添加标题
main_layout.addWidget(self.controls["title_label"])
# 创建主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("riggingMainSplitter")
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
# 添加主分割器到主布局
main_layout.addWidget(self.splitters["main_splitter"])
# 左侧面板布局
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
self.layouts["left_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["left_layout"].setSpacing(5)
# 1. Presets 面板布局
presets_layout = QtWidgets.QVBoxLayout(self.controls["presets_panel"])
presets_layout.setContentsMargins(0, 0, 0, 0)
presets_layout.setSpacing(5)
# 骨骼组布局
self.layouts["skeleton_group_layout"] = QtWidgets.QVBoxLayout(self.controls["skeleton_group"])
self.layouts["skeleton_group_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["skeleton_group_layout"].setSpacing(5)
# Presets 组布局
presets_group_layout = QtWidgets.QVBoxLayout(self.controls["presets_group"])
presets_group_layout.setContentsMargins(5, 5, 5, 5)
presets_group_layout.setSpacing(5)
# 骨骼列表
self.layouts["skeleton_group_layout"].addWidget(self.controls["skeleton_list"])
# 添加预设滚动区域
presets_group_layout.addWidget(self.controls["presets_scroll_area"])
# 骨骼操作按钮行
self.layouts["skeleton_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["skeleton_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["skeleton_buttons_layout"].setSpacing(2)
# 添加预设底部滑块布局
presets_group_layout.addLayout(self.controls["presets_slider_layout"])
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["add_joint"])
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["remove_joint"])
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["duplicate_joint"])
# 添加Presets组到Presets面板
presets_layout.addWidget(self.controls["presets_group"])
self.layouts["skeleton_group_layout"].addLayout(self.layouts["skeleton_buttons_layout"])
# 2. Assets 面板布局
assets_layout = QtWidgets.QVBoxLayout(self.controls["assets_panel"])
assets_layout.setContentsMargins(0, 0, 0, 0)
assets_layout.setSpacing(5)
# 控制器组布局
self.layouts["controller_group_layout"] = QtWidgets.QVBoxLayout(self.controls["controller_group"])
self.layouts["controller_group_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["controller_group_layout"].setSpacing(5)
# Assets 组布局
assets_group_layout = QtWidgets.QGridLayout(self.controls["assets_group"])
assets_group_layout.setContentsMargins(5, 5, 5, 5)
assets_group_layout.setSpacing(5)
# 控制器列表
self.layouts["controller_group_layout"].addWidget(self.controls["controller_list"])
# 添加项目路径标签和输入框
assets_group_layout.addWidget(self.controls["project_path_label"], 0, 0)
assets_group_layout.addWidget(self.controls["project_path_input"], 0, 1)
assets_group_layout.addWidget(self.buttons["browse_path"], 0, 2)
# 控制器操作按钮行
self.layouts["controller_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["controller_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["controller_buttons_layout"].setSpacing(2)
# 添加Presets DNA标签和输入框
assets_group_layout.addWidget(self.controls["presets_dna_label"], 1, 0)
assets_group_layout.addWidget(self.controls["presets_dna_input"], 1, 1)
assets_group_layout.addWidget(self.buttons["browse_dna"], 1, 2)
self.layouts["controller_buttons_layout"].addWidget(self.buttons["add_controller"])
self.layouts["controller_buttons_layout"].addWidget(self.buttons["remove_controller"])
self.layouts["controller_buttons_layout"].addWidget(self.buttons["duplicate_controller"])
# 添加Assets组到Assets面板
assets_layout.addWidget(self.controls["assets_group"])
self.layouts["controller_group_layout"].addLayout(self.layouts["controller_buttons_layout"])
# 3. Descriptor 面板布局
descriptor_layout = QtWidgets.QVBoxLayout(self.controls["descriptor_panel"])
descriptor_layout.setContentsMargins(0, 0, 0, 0)
descriptor_layout.setSpacing(5)
# 添加组到左侧面板
self.layouts["left_layout"].addWidget(self.controls["skeleton_group"])
self.layouts["left_layout"].addWidget(self.controls["controller_group"])
# Descriptor 组布局
descriptor_group_layout = QtWidgets.QGridLayout(self.controls["descriptor_group"])
descriptor_group_layout.setContentsMargins(5, 5, 5, 5)
descriptor_group_layout.setSpacing(5)
# 右侧面板布局
self.layouts["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
self.layouts["right_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["right_layout"].setSpacing(5)
# 添加名称标签和输入框
descriptor_group_layout.addWidget(self.controls["name_label"], 0, 0)
descriptor_group_layout.addWidget(self.controls["name_input"], 0, 1, 1, 3)
# 关节属性组布局
self.layouts["joint_properties_layout"] = QtWidgets.QVBoxLayout(self.controls["joint_properties_group"])
self.layouts["joint_properties_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["joint_properties_layout"].setSpacing(5)
# 添加原型标签和下拉框
descriptor_group_layout.addWidget(self.controls["archetype_label"], 1, 0)
descriptor_group_layout.addWidget(self.controls["archetype_combo"], 1, 1)
# 关节名称行
self.layouts["joint_name_layout"] = QtWidgets.QHBoxLayout()
self.layouts["joint_name_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["joint_name_layout"].setSpacing(5)
# 添加性别标签和下拉框
descriptor_group_layout.addWidget(self.controls["gender_label"], 1, 2)
descriptor_group_layout.addWidget(self.controls["gender_combo"], 1, 3)
self.layouts["joint_name_layout"].addWidget(self.controls["joint_name_label"])
self.layouts["joint_name_layout"].addWidget(self.controls["joint_name_input"])
# 添加年龄标签和输入框
descriptor_group_layout.addWidget(self.controls["age_label"], 2, 0)
descriptor_group_layout.addWidget(self.controls["age_spinner"], 2, 1)
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_name_layout"])
# 添加平移单位标签和下拉框
descriptor_group_layout.addWidget(self.controls["translation_unit_label"], 3, 0)
descriptor_group_layout.addWidget(self.controls["translation_unit_combo"], 3, 1)
# 关节位置行
self.layouts["joint_position_layout"] = QtWidgets.QVBoxLayout()
self.layouts["joint_position_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["joint_position_layout"].setSpacing(2)
# 添加旋转单位标签和下拉框
descriptor_group_layout.addWidget(self.controls["rotation_unit_label"], 3, 2)
descriptor_group_layout.addWidget(self.controls["rotation_unit_combo"], 3, 3)
self.layouts["joint_position_layout"].addWidget(self.controls["joint_position_label"])
# 添加坐标系统标签和下拉框
descriptor_group_layout.addWidget(self.controls["coordinate_system_label"], 4, 0)
descriptor_group_layout.addWidget(self.controls["coordinate_system_combo"], 4, 1)
# 位置坐标行
self.layouts["position_coords_layout"] = QtWidgets.QGridLayout()
self.layouts["position_coords_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["position_coords_layout"].setSpacing(5)
# 添加LOD数量标签和输入框
descriptor_group_layout.addWidget(self.controls["lod_count_label"], 4, 2)
descriptor_group_layout.addWidget(self.controls["lod_count_spinner"], 4, 3)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_x_label"], 0, 0)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_x_input"], 0, 1)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_y_label"], 1, 0)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_y_input"], 1, 1)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_z_label"], 2, 0)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_z_input"], 2, 1)
# 添加Descriptor组到Descriptor面板
descriptor_layout.addWidget(self.controls["descriptor_group"])
self.layouts["joint_position_layout"].addLayout(self.layouts["position_coords_layout"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_position_layout"])
# 添加各个面板到主分割器
self.splitters["main_splitter"].addWidget(self.controls["presets_panel"])
self.splitters["main_splitter"].addWidget(self.controls["assets_panel"])
self.splitters["main_splitter"].addWidget(self.controls["descriptor_panel"])
# 关节旋转行
self.layouts["joint_rotation_layout"] = QtWidgets.QVBoxLayout()
self.layouts["joint_rotation_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["joint_rotation_layout"].setSpacing(2)
# 底部按钮区域布局
bottom_buttons_layout = QtWidgets.QHBoxLayout(self.controls["bottom_buttons_panel"])
bottom_buttons_layout.setContentsMargins(5, 5, 5, 5)
bottom_buttons_layout.setSpacing(10)
self.layouts["joint_rotation_layout"].addWidget(self.controls["joint_rotation_label"])
# 添加底部按钮
bottom_buttons_layout.addWidget(self.buttons["remove_all"])
bottom_buttons_layout.addStretch(1) # 添加弹性空间
bottom_buttons_layout.addWidget(self.buttons["import_skeleton"])
bottom_buttons_layout.addWidget(self.buttons["build_rigging"])
# 旋转坐标行
self.layouts["rotation_coords_layout"] = QtWidgets.QGridLayout()
self.layouts["rotation_coords_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["rotation_coords_layout"].setSpacing(5)
# 添加底部按钮区域到主布局
main_layout.addWidget(self.controls["bottom_buttons_panel"])
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rx_label"], 0, 0)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rx_input"], 0, 1)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_ry_label"], 1, 0)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_ry_input"], 1, 1)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rz_label"], 2, 0)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rz_input"], 2, 1)
# 设置分割器初始大小
self.splitters["main_splitter"].setSizes([400, 100, 200])
self.layouts["joint_rotation_layout"].addLayout(self.layouts["rotation_coords_layout"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_rotation_layout"])
# 关节缩放行
self.layouts["joint_scale_layout"] = QtWidgets.QVBoxLayout()
self.layouts["joint_scale_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["joint_scale_layout"].setSpacing(2)
self.layouts["joint_scale_layout"].addWidget(self.controls["joint_scale_label"])
# 缩放坐标行
self.layouts["scale_coords_layout"] = QtWidgets.QGridLayout()
self.layouts["scale_coords_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["scale_coords_layout"].setSpacing(5)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sx_label"], 0, 0)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sx_input"], 0, 1)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sy_label"], 1, 0)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sy_input"], 1, 1)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sz_label"], 2, 0)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sz_input"], 2, 1)
self.layouts["joint_scale_layout"].addLayout(self.layouts["scale_coords_layout"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_scale_layout"])
# 属性按钮行
self.layouts["properties_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["properties_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["properties_buttons_layout"].setSpacing(5)
self.layouts["properties_buttons_layout"].addWidget(self.buttons["apply_joint_properties"])
self.layouts["properties_buttons_layout"].addWidget(self.buttons["reset_joint_properties"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["properties_buttons_layout"])
# 绑定工具组布局
self.layouts["binding_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["binding_tools_group"])
self.layouts["binding_tools_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["binding_tools_layout"].setSpacing(5)
# 绑定工具按钮网格
self.layouts["binding_tools_grid"] = QtWidgets.QGridLayout()
self.layouts["binding_tools_grid"].setContentsMargins(0, 0, 0, 0)
self.layouts["binding_tools_grid"].setSpacing(5)
self.layouts["binding_tools_grid"].addWidget(self.buttons["create_binding"], 0, 0)
self.layouts["binding_tools_grid"].addWidget(self.buttons["copy_skin"], 0, 1)
self.layouts["binding_tools_grid"].addWidget(self.buttons["mirror_skin"], 1, 0)
self.layouts["binding_tools_grid"].addWidget(self.buttons["paint_weights"], 1, 1)
self.layouts["binding_tools_layout"].addLayout(self.layouts["binding_tools_grid"])
# 添加组到右侧面板
self.layouts["right_layout"].addWidget(self.controls["joint_properties_group"])
self.layouts["right_layout"].addWidget(self.controls["binding_tools_group"])
# 底部工具面板
self.layouts["bottom_panel"] = QtWidgets.QHBoxLayout()
self.layouts["bottom_panel"].setContentsMargins(2, 2, 2, 2)
self.layouts["bottom_panel"].setSpacing(5)
# DNA组布局
self.layouts["dna_layout"] = QtWidgets.QVBoxLayout(self.controls["dna_group"])
self.layouts["dna_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["dna_layout"].setSpacing(5)
self.layouts["dna_layout"].addWidget(self.buttons["import_dna"])
self.layouts["dna_layout"].addWidget(self.buttons["export_dna"])
self.layouts["dna_layout"].addWidget(self.buttons["calibrate_dna"])
# 骨骼工具组布局
self.layouts["skeleton_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["skeleton_tools_group"])
self.layouts["skeleton_tools_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["skeleton_tools_layout"].setSpacing(5)
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["import_skeleton"])
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["export_skeleton"])
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["calibrate_skeleton"])
# 绑定工具组布局
self.layouts["rigging_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["rigging_tools_group"])
self.layouts["rigging_tools_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["rigging_tools_layout"].setSpacing(5)
self.layouts["rigging_tools_layout"].addWidget(self.buttons["generate_controllers"])
self.layouts["rigging_tools_layout"].addWidget(self.buttons["generate_body"])
self.layouts["rigging_tools_layout"].addWidget(self.buttons["clean_rigging"])
# 添加组到底部面板
self.layouts["bottom_panel"].addWidget(self.controls["dna_group"])
self.layouts["bottom_panel"].addWidget(self.controls["skeleton_tools_group"])
self.layouts["bottom_panel"].addWidget(self.controls["rigging_tools_group"])
# 添加底部面板到主布局
self.layouts["main_layout"].addLayout(self.layouts["bottom_panel"])
# 将左右面板添加到主分割器
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
# 设置分割器初始大小和伸缩因子
self.splitters["main_splitter"].setSizes([500, 500])
# 设置分割器的伸缩因子,确保左右栏能够自动调整宽度
# 设置分割器的伸缩因子
for i in range(self.splitters["main_splitter"].count()):
self.splitters["main_splitter"].setStretchFactor(i, 1)
#======================================= CONNECTION =====================================
def create_connections(self):
"""
创建绑定系统UI信号和槽连接
将按钮点击等事件与相应的处理函数连接
"""
# 左侧面板 - 骨骼列表操作
self.buttons["add_joint"].clicked.connect(self.add_joint)
self.buttons["remove_joint"].clicked.connect(self.remove_joint)
self.buttons["duplicate_joint"].clicked.connect(self.duplicate_joint)
self.controls["skeleton_list"].itemSelectionChanged.connect(self.on_joint_selection_changed)
# 左侧面板 - 控制器列表操作
self.buttons["add_controller"].clicked.connect(self.add_controller)
self.buttons["remove_controller"].clicked.connect(self.remove_controller)
self.buttons["duplicate_controller"].clicked.connect(self.duplicate_controller)
self.controls["controller_list"].itemSelectionChanged.connect(self.on_controller_selection_changed)
# 右侧面板 - 关节属性
self.buttons["apply_joint_properties"].clicked.connect(self.apply_joint_properties)
self.buttons["reset_joint_properties"].clicked.connect(self.reset_joint_properties)
# 坐标输入框修改事件
self.controls["joint_name_input"].textChanged.connect(self.on_joint_name_changed)
self.controls["joint_x_input"].textChanged.connect(lambda: self.on_joint_position_changed("x"))
self.controls["joint_y_input"].textChanged.connect(lambda: self.on_joint_position_changed("y"))
self.controls["joint_z_input"].textChanged.connect(lambda: self.on_joint_position_changed("z"))
self.controls["joint_rx_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("x"))
self.controls["joint_ry_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("y"))
self.controls["joint_rz_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("z"))
self.controls["joint_sx_input"].textChanged.connect(lambda: self.on_joint_scale_changed("x"))
self.controls["joint_sy_input"].textChanged.connect(lambda: self.on_joint_scale_changed("y"))
self.controls["joint_sz_input"].textChanged.connect(lambda: self.on_joint_scale_changed("z"))
# 右侧面板 - 绑定工具
self.buttons["create_binding"].clicked.connect(self.create_binding)
self.buttons["copy_skin"].clicked.connect(self.copy_skin)
self.buttons["mirror_skin"].clicked.connect(self.mirror_skin)
self.buttons["paint_weights"].clicked.connect(self.paint_weights)
# 底部工具面板 - DNA操作
self.buttons["import_dna"].clicked.connect(self.import_dna)
self.buttons["export_dna"].clicked.connect(self.export_dna)
self.buttons["calibrate_dna"].clicked.connect(self.calibrate_dna)
# 底部工具面板 - 骨骼工具
self.buttons["import_skeleton"].clicked.connect(self.import_skeleton)
self.buttons["export_skeleton"].clicked.connect(self.export_skeleton)
self.buttons["calibrate_skeleton"].clicked.connect(self.calibrate_skeleton)
# 底部工具面板 - 绑定工具
self.buttons["generate_controllers"].clicked.connect(self.generate_controllers)
self.buttons["generate_body"].clicked.connect(self.generate_body)
self.buttons["clean_rigging"].clicked.connect(self.clean_rigging)
# 分割器移动事件
self.splitters["main_splitter"].splitterMoved.connect(self.on_splitter_moved)
# 添加显示事件处理
self.showEvent = self.on_show_event
self.splitters["main_splitter"].setStretchFactor(i, 1)

View File

@@ -48,11 +48,17 @@ LANG = localization.LANG
# 定义窗口大小变化事件处理类
# 用于监听窗口大小变化并调整分割器宽度
class SplitterResizeHandler(QtCore.QObject):
def __init__(self, parent_tab, main_splitter, is_horizontal=True):
def __init__(self, parent_tab, main_splitter, is_horizontal=True, panel_count=2, panel_ratio=None):
super(SplitterResizeHandler, self).__init__(parent_tab)
self.parent_tab = parent_tab
self.main_splitter = main_splitter
self.is_horizontal = is_horizontal # 是否为水平分割器
self.panel_count = panel_count # 面板数量默认为2左右面板
# 面板比例默认为None则使用默认比例
# 如果是2面板默认比例为[1, 1](左右均等)
# 如果是3面板默认比例为[4, 1, 2]Presets面板较大Assets面板较小Descriptor面板中等
self.panel_ratio = panel_ratio if panel_ratio else ([1, 1] if panel_count == 2 else [4, 1, 2])
# 安装事件过滤器到父标签页
self.parent_tab.installEventFilter(self)
@@ -67,37 +73,227 @@ class SplitterResizeHandler(QtCore.QObject):
def adjustSplitterSizes(self):
# 确保分割器存在且父标签页可见
if self.main_splitter and self.parent_tab.isVisible():
# 计算比例总和
ratio_sum = sum(self.panel_ratio)
if self.is_horizontal:
# 获取父标签页当前宽度
width = self.parent_tab.width()
# 设置分割器左右宽度均等
self.main_splitter.setSizes([width // 2, width // 2])
print(f"分割器 - 窗口大小变化,调整水平分割器宽度为: {width // 2}, {width // 2}")
# 根据面板数量设置分割器大小
if self.panel_count == 2:
# 设置分割器左右宽度按比例分配
sizes = [int(width * ratio / ratio_sum) for ratio in self.panel_ratio]
self.main_splitter.setSizes(sizes)
print(f"分割器 - 窗口大小变化,调整水平分割器宽度为: {sizes}")
elif self.panel_count == 3:
# 设置三面板分割器宽度按比例分配
sizes = [int(width * ratio / ratio_sum) for ratio in self.panel_ratio]
self.main_splitter.setSizes(sizes)
print(f"分割器 - 窗口大小变化,调整三面板水平分割器宽度为: {sizes}")
else:
# 获取父标签页当前高度
height = self.parent_tab.height()
# 设置分割器上下比例为3:1
self.main_splitter.setSizes([height * 3 // 4, height // 4])
print(f"分割器 - 窗口大小变化,调整垂直分割器高度为: {height * 3 // 4}, {height // 4}")
# 根据面板数量设置分割器大小
if self.panel_count == 2:
# 设置分割器上下高度按比例分配
sizes = [int(height * ratio / ratio_sum) for ratio in self.panel_ratio]
self.main_splitter.setSizes(sizes)
print(f"分割器 - 窗口大小变化,调整垂直分割器高度为: {sizes}")
elif self.panel_count == 3:
# 设置三面板分割器高度按比例分配
sizes = [int(height * ratio / ratio_sum) for ratio in self.panel_ratio]
self.main_splitter.setSizes(sizes)
print(f"分割器 - 窗口大小变化,调整三面板垂直分割器高度为: {sizes}")
# 使用类来管理UI控件避免全局变量
class BaseUI:
class BaseUI(object):
"""
基础UI类 - 管理所有UI控件
使用字典存储控件、按钮、布局和分割器引用,避免全局变量
UI基类
所有UI面板的基类提供通用的UI功能
"""
def __init__(self):
# UI控件字典
"""
初始化UI基类
"""
# 初始化字典
self.controls = {}
# 按钮字典
self.buttons = {}
# 布局字典
self.layouts = {}
# 分割器字典
self.buttons = {}
self.splitters = {}
# 分割器大小处理器字典
self.resize_handlers = {}
self.inputs = {}
self.labels = {}
# 创建主控件
self.main_widget = None
def on_show_event(self, event):
"""
显示事件处理
当面板显示时重置分割器大小
Args:
event: 显示事件对象
"""
# 重置分割器大小
self.reset_splitter_sizes()
# 调用父类的showEvent方法
super(BaseUI, self).showEvent(event)
def reset_splitter_sizes(self):
"""
重置分割器大小,设置三个面板的初始大小
Presets面板较大显示预设图片Assets面板较小Descriptor面板中等
"""
if hasattr(self, 'splitters') and 'main_splitter' in self.splitters and self.splitters["main_splitter"]:
# 尝试从设置中读取分割器大小
preset_size = cmds.optionVar(query="MetaFusionRiggingPresetsPanelSize") if cmds.optionVar(exists="MetaFusionRiggingPresetsPanelSize") else 400
assets_size = cmds.optionVar(query="MetaFusionRiggingAssetsPanelSize") if cmds.optionVar(exists="MetaFusionRiggingAssetsPanelSize") else 100
descriptor_size = cmds.optionVar(query="MetaFusionRiggingDescriptorPanelSize") if cmds.optionVar(exists="MetaFusionRiggingDescriptorPanelSize") else 200
# 设置分割器大小
self.splitters["main_splitter"].setSizes([preset_size, assets_size, descriptor_size])
def create_widgets(self):
"""
创建UI控件
创建所有UI控件并存储到字典中
"""
# 子类实现
pass
def create_layouts(self):
"""
创建UI布局
创建所有UI布局并存储到字典中
"""
# 子类实现
pass
def connect_ui_signals(self):
"""
连接UI信号和槽
设置UI控件的事件处理函数
"""
# 子类实现
pass
def showEvent(self, event):
"""
显示事件
当面板显示时调用on_show_event方法
Args:
event: 显示事件对象
"""
# 调用自定义的显示事件处理方法
self.on_show_event(event)
# 分割器相关的工具函数
def update_splitter_position(splitter, sizes=None):
"""
更新分割器位置
Args:
splitter: 分割器对象
sizes: 分割器大小列表如果为None则使用当前分割器大小
"""
if not splitter:
return
# 记录当前分割器位置
if sizes is None:
sizes = splitter.sizes()
# 将分割器位置保存到设置中
# 如果是三面板分割器,则保存三个大小值
if len(sizes) == 3:
# 保存三面板分割器位置Presets、Assets、Descriptor
cmds.optionVar(intValue=["MetaFusionRiggingPresetsPanelSize", sizes[0]])
cmds.optionVar(intValue=["MetaFusionRiggingAssetsPanelSize", sizes[1]])
cmds.optionVar(intValue=["MetaFusionRiggingDescriptorPanelSize", sizes[2]])
else:
# 保存左右分割器位置
cmds.optionVar(intValue=["MetaFusionRiggingLeftPanelSize", sizes[0]])
cmds.optionVar(intValue=["MetaFusionRiggingRightPanelSize", sizes[1]])
print(f"Splitter sizes updated: {sizes}")
# 通用UI事件处理函数
def on_splitter_moved(ui_instance, pos, index):
"""
分割器移动事件处理
记录当前分割器位置
Args:
ui_instance: UI实例包含splitters字典
pos: 分割器位置
index: 分割器索引
"""
if hasattr(ui_instance, 'splitters') and 'main_splitter' in ui_instance.splitters:
update_splitter_position(ui_instance.splitters["main_splitter"])
def connect_ui_signals(ui_instance, signal_mapping):
"""
连接UI信号和槽
设置UI控件的事件处理函数
Args:
ui_instance: UI实例包含控件和布局
signal_mapping: 信号映射字典,格式为:
{
'widget_type': { # 'buttons', 'inputs', 'splitters'
'widget_name': { # 控件名称
'signal': 'signal_name', # 信号名称,如'clicked', 'valueChanged'
'handler': handler_function, # 处理函数
'args': [arg1, arg2, ...] # 可选,处理函数的参数
}
}
}
"""
# 遍历信号映射字典
for widget_type, widgets in signal_mapping.items():
# 获取控件字典
widget_dict = getattr(ui_instance, widget_type, {})
# 遍历控件
for widget_name, signal_info in widgets.items():
# 检查控件是否存在
if widget_name in widget_dict:
widget = widget_dict[widget_name]
signal_name = signal_info.get('signal')
handler = signal_info.get('handler')
args = signal_info.get('args', [])
# 获取信号对象
signal = getattr(widget, signal_name, None)
# 连接信号和槽
if signal and handler:
if args:
signal.connect(lambda *extra, h=handler, a=args: h(*a))
else:
signal.connect(handler)
def connect_maya_selection_changed(ui_instance, handler, parent_widget=None):
"""
连接Maya选择变化事件
Args:
ui_instance: UI实例
handler: 选择变化事件处理函数
parent_widget: 父控件用于设置scriptJob的parent参数
"""
# 如果没有指定父控件则使用UI实例的main_widget
if parent_widget is None and hasattr(ui_instance, 'main_widget'):
parent_widget = ui_instance.main_widget
# 创建scriptJob
if parent_widget:
job_id = cmds.scriptJob(event=["SelectionChanged", handler], parent=parent_widget.objectName())
return job_id
return None
# 获取Maya主窗口
def get_maya_main_window():
"""
获取Maya主窗口

File diff suppressed because it is too large Load Diff