Update
This commit is contained in:
@@ -53,6 +53,8 @@ ASSETS_PATH = config.ASSETS_PATH
|
||||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||||
DNA_IMG_PATH = config.DNA_IMG_PATH
|
||||
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
||||
TOOL_WIDTH = config.TOOL_WIDTH
|
||||
TOOL_HEIGHT = config.TOOL_HEIGHT
|
||||
#========================================= LOCATION =======================================
|
||||
from scripts.ui import localization
|
||||
LANG = localization.LANG
|
||||
@@ -62,47 +64,83 @@ class BehaviourUI(ui_utils.BaseUI):
|
||||
行为系统UI类 - 负责显示角色行为编辑界面和基础操作
|
||||
继承自BaseUI类,实现行为系统相关的UI功能
|
||||
"""
|
||||
#========================================== INIT ========================================
|
||||
def __init__(self):
|
||||
# 类变量,存储单例实例
|
||||
_instance = None
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls):
|
||||
"""
|
||||
获取BehaviourUI的单例实例
|
||||
|
||||
Returns:
|
||||
BehaviourUI: 单例实例,如果不存在则返回None
|
||||
"""
|
||||
return cls._instance
|
||||
|
||||
def __init__(self, parent=None):
|
||||
"""
|
||||
初始化行为系统UI
|
||||
创建主控件和布局,并连接信号和槽
|
||||
"""
|
||||
super(BehaviourUI, self).__init__()
|
||||
|
||||
# 创建主控件
|
||||
self.main_widget = QtWidgets.QWidget()
|
||||
super(BehaviourUI, self).__init__() # 不传递parent参数给BaseUI
|
||||
self.main_widget = QtWidgets.QWidget(parent) # 在创建main_widget时传递parent
|
||||
self.main_widget.setObjectName("behaviourMainWidget")
|
||||
|
||||
# 初始化UI
|
||||
# 设置单例实例
|
||||
BehaviourUI._instance = self
|
||||
|
||||
# 初始化控件、布局和按钮字典
|
||||
self.controls = {}
|
||||
self.layouts = {}
|
||||
self.buttons = {}
|
||||
self.splitters = {}
|
||||
|
||||
# 创建UI组件
|
||||
self.create_widgets()
|
||||
self.create_layouts()
|
||||
self.create_connections()
|
||||
|
||||
#========================================= WIDGET =======================================
|
||||
|
||||
# 在创建完所有布局后,设置分割器的初始大小和属性
|
||||
# 使用ui_utils中的函数来设置分割器大小
|
||||
ui_utils.setup_splitter(self, "main_splitter", [1, 1])
|
||||
|
||||
# 设置分割器所有子元素的最小尺寸为0,确保可以自由调整
|
||||
ui_utils.set_splitter_children_minimum_size(self, recursive=True)
|
||||
|
||||
# 设置所有控件的最小尺寸为0,确保分割器可以自由移动
|
||||
ui_utils.set_all_controls_minimum_size(self)
|
||||
|
||||
# 使用ui_utils中的函数强制设置均等大小
|
||||
ui_utils.force_equal_splitter_sizes(self)
|
||||
|
||||
def create_widgets(self):
|
||||
"""
|
||||
创建行为系统UI控件
|
||||
包括按钮、标签、列表等
|
||||
包括标题标签、搜索框、控制列表、滑块等
|
||||
"""
|
||||
# 标题标签 - 使用HTML格式化标题
|
||||
title_text = f"<h4 style='margin:0;padding:5px;'>{LANG.get('behaviour_title', '行为')}</h4>"
|
||||
self.controls["title_label"] = QtWidgets.QLabel(title_text)
|
||||
# 标题标签
|
||||
self.controls["title_label"] = QtWidgets.QLabel(LANG.get("behaviour_title", "行为系统"))
|
||||
self.controls["title_label"].setObjectName("behaviourTitleLabel")
|
||||
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.controls["title_label"].setMaximumHeight(30) # 限制标题高度
|
||||
self.controls["title_label"].setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px;")
|
||||
|
||||
# 左侧面板
|
||||
# 主分割器
|
||||
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
|
||||
self.splitters["main_splitter"].setObjectName("behaviourMainSplitter")
|
||||
self.splitters["main_splitter"].setHandleWidth(6) # 设置分割器手柄宽度
|
||||
self.splitters["main_splitter"].setChildrenCollapsible(False) # 禁止子部件折叠
|
||||
self.splitters["main_splitter"].setOpaqueResize(True) # 实时显示调整效果,更丝滑
|
||||
|
||||
# 左侧面板 - Raw Control
|
||||
self.controls["left_panel"] = QtWidgets.QWidget()
|
||||
self.controls["left_panel"].setObjectName("behaviourLeftPanel")
|
||||
self.controls["left_panel"].setMinimumWidth(0)
|
||||
self.controls["left_panel"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 右侧面板
|
||||
# 右侧面板 - BlendShapes
|
||||
self.controls["right_panel"] = QtWidgets.QWidget()
|
||||
self.controls["right_panel"].setObjectName("behaviourRightPanel")
|
||||
|
||||
# 左侧面板控件 - Raw Control
|
||||
self.controls["raw_control_group"] = QtWidgets.QGroupBox("Raw Control [000]")
|
||||
self.controls["raw_control_group"].setObjectName("rawControlGroup")
|
||||
self.controls["right_panel"].setMinimumWidth(0)
|
||||
self.controls["right_panel"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 搜索框
|
||||
self.controls["search_input"] = QtWidgets.QLineEdit()
|
||||
@@ -112,15 +150,45 @@ class BehaviourUI(ui_utils.BaseUI):
|
||||
# 控制列表
|
||||
self.controls["control_list"] = QtWidgets.QListWidget()
|
||||
self.controls["control_list"].setObjectName("controlList")
|
||||
self.controls["control_list"].setMinimumWidth(0) # 设置最小宽度为零
|
||||
|
||||
# 底部滑块和按钮
|
||||
self.controls["bottom_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.controls["bottom_slider"].setObjectName("bottomSlider")
|
||||
self.controls["bottom_slider"].setMinimum(0)
|
||||
self.controls["bottom_slider"].setMaximum(100)
|
||||
self.controls["bottom_slider"].setValue(10)
|
||||
# 底部滑块
|
||||
self.controls["raw_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.controls["raw_slider"].setObjectName("rawSlider")
|
||||
self.controls["raw_slider"].setMinimum(0)
|
||||
self.controls["raw_slider"].setMaximum(100)
|
||||
self.controls["raw_slider"].setValue(0)
|
||||
self.controls["raw_slider"].setFixedHeight(20)
|
||||
|
||||
# 创建滑块布局,包含数值显示和滑块
|
||||
self.layouts["raw_slider_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["raw_slider_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["raw_slider_layout"].setSpacing(2)
|
||||
|
||||
# 添加数值显示标签
|
||||
self.controls["raw_slider_value"] = QtWidgets.QLabel("0.000")
|
||||
self.controls["raw_slider_value"].setObjectName("rawSliderValue")
|
||||
self.controls["raw_slider_value"].setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.controls["raw_slider_value"].setFixedWidth(40)
|
||||
self.layouts["raw_slider_layout"].addWidget(self.controls["raw_slider_value"])
|
||||
|
||||
# 添加滑块
|
||||
self.layouts["raw_slider_layout"].addWidget(self.controls["raw_slider"])
|
||||
|
||||
# 添加"All"勾选框和标签
|
||||
self.controls["raw_slider_all_check"] = QtWidgets.QCheckBox("All")
|
||||
self.controls["raw_slider_all_check"].setObjectName("rawSliderAllCheck")
|
||||
self.layouts["raw_slider_layout"].addWidget(self.controls["raw_slider_all_check"])
|
||||
|
||||
# 页码按钮
|
||||
self.buttons["prev_page"] = QtWidgets.QPushButton("上一页")
|
||||
self.buttons["prev_page"].setObjectName("prevPageButton")
|
||||
self.buttons["prev_page"].setIcon(ui_utils.get_icon("arrowLeft.png"))
|
||||
|
||||
self.buttons["next_page"] = QtWidgets.QPushButton("下一页")
|
||||
self.buttons["next_page"].setObjectName("nextPageButton")
|
||||
self.buttons["next_page"].setIcon(ui_utils.get_icon("arrowRight.png"))
|
||||
|
||||
self.buttons["page_all"] = QtWidgets.QPushButton("All")
|
||||
self.buttons["page_all"].setObjectName("pageAllButton")
|
||||
self.buttons["page_all"].setCheckable(True)
|
||||
@@ -146,119 +214,204 @@ class BehaviourUI(ui_utils.BaseUI):
|
||||
self.buttons["page_6"].setObjectName("page6Button")
|
||||
self.buttons["page_6"].setCheckable(True)
|
||||
|
||||
# 左下角按钮
|
||||
self.buttons["range_minus"] = QtWidgets.QPushButton("-")
|
||||
self.buttons["range_minus"].setObjectName("rangeMinusButton")
|
||||
|
||||
self.buttons["range_plus"] = QtWidgets.QPushButton("+")
|
||||
# 左下角Range按钮
|
||||
self.buttons["range_plus"] = QtWidgets.QPushButton("Range +")
|
||||
self.buttons["range_plus"].setObjectName("rangePlusButton")
|
||||
self.buttons["range_plus"].setIcon(ui_utils.get_icon("behaviour.png"))
|
||||
|
||||
self.buttons["range_minus"] = QtWidgets.QPushButton("Range -")
|
||||
self.buttons["range_minus"].setObjectName("rangeMinusButton")
|
||||
self.buttons["range_minus"].setIcon(ui_utils.get_icon("behaviour.png"))
|
||||
|
||||
# 右侧面板控件 - Related BlendShapes
|
||||
self.controls["blendshapes_group"] = QtWidgets.QGroupBox("Related BlendShapes [000]")
|
||||
self.controls["blendshapes_group"].setObjectName("blendshapesGroup")
|
||||
self.controls["blendshapes_group"].setMinimumWidth(0) # 设置最小宽度为零
|
||||
self.controls["blendshapes_group"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# BlendShapes列表
|
||||
self.controls["blendshapes_list"] = QtWidgets.QListWidget()
|
||||
self.controls["blendshapes_list"].setObjectName("blendshapesList")
|
||||
self.controls["blendshapes_list"].setMinimumWidth(0) # 设置最小宽度为零
|
||||
self.controls["blendshapes_list"].setMinimumHeight(100) # 设置最小高度,确保列表可见
|
||||
self.controls["blendshapes_list"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 底部滑块和按钮
|
||||
# 底部滑块
|
||||
self.controls["bs_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.controls["bs_slider"].setObjectName("bsSlider")
|
||||
self.controls["bs_slider"].setMinimum(0)
|
||||
self.controls["bs_slider"].setMaximum(100)
|
||||
self.controls["bs_slider"].setValue(0)
|
||||
|
||||
# 创建BS滑块布局,包含数值显示和滑块
|
||||
self.layouts["bs_slider_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["bs_slider_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["bs_slider_layout"].setSpacing(2)
|
||||
|
||||
# 添加数值显示标签
|
||||
self.controls["bs_slider_value"] = QtWidgets.QLabel("0.000")
|
||||
self.controls["bs_slider_value"].setObjectName("bsSliderValue")
|
||||
self.controls["bs_slider_value"].setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.controls["bs_slider_value"].setFixedWidth(40)
|
||||
self.layouts["bs_slider_layout"].addWidget(self.controls["bs_slider_value"])
|
||||
|
||||
# 添加滑块
|
||||
self.layouts["bs_slider_layout"].addWidget(self.controls["bs_slider"])
|
||||
|
||||
# 添加"All"勾选框和标签
|
||||
self.controls["bs_slider_all_check"] = QtWidgets.QCheckBox("All")
|
||||
self.controls["bs_slider_all_check"].setObjectName("bsSliderAllCheck")
|
||||
self.layouts["bs_slider_layout"].addWidget(self.controls["bs_slider_all_check"])
|
||||
|
||||
# BlendShape操作按钮
|
||||
self.buttons["reset_blendshape"] = QtWidgets.QPushButton(LANG.get("reset_blendshape", "重置混合形状"))
|
||||
self.buttons["reset_blendshape"].setObjectName("resetBlendshapeButton")
|
||||
self.buttons["flip_target"] = QtWidgets.QPushButton("Flip Target")
|
||||
self.buttons["flip_target"].setObjectName("flipTargetButton")
|
||||
self.buttons["flip_target"].setIcon(ui_utils.get_icon("mirrorL.png"))
|
||||
self.buttons["flip_target"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
self.buttons["mirror_blendshape"] = QtWidgets.QPushButton(LANG.get("mirror_blendshape", "镜像混合形状"))
|
||||
self.buttons["mirror_blendshape"].setObjectName("mirrorBlendshapeButton")
|
||||
self.buttons["mirror_target"] = QtWidgets.QPushButton("Mirror Target")
|
||||
self.buttons["mirror_target"].setObjectName("mirrorTargetButton")
|
||||
self.buttons["mirror_target"].setIcon(ui_utils.get_icon("mirror.png"))
|
||||
self.buttons["mirror_target"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
self.buttons["add_blendshape"] = QtWidgets.QPushButton(LANG.get("add_blendshape", "添加混合形状"))
|
||||
self.buttons["find_flip_target"] = QtWidgets.QPushButton("Find Flip Target")
|
||||
self.buttons["find_flip_target"].setObjectName("findFlipTargetButton")
|
||||
self.buttons["find_flip_target"].setIcon(ui_utils.get_icon("mirrorR.png"))
|
||||
self.buttons["find_flip_target"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
self.buttons["add_blendshape"] = QtWidgets.QPushButton("Add BlendShape")
|
||||
self.buttons["add_blendshape"].setObjectName("addBlendshapeButton")
|
||||
self.buttons["add_blendshape"].setIcon(ui_utils.get_icon("blendShape.png"))
|
||||
self.buttons["add_blendshape"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
self.buttons["remove_blendshape"] = QtWidgets.QPushButton(LANG.get("remove_blendshape", "移除混合形状"))
|
||||
self.buttons["remove_blendshape"].setObjectName("removeBlendshapeButton")
|
||||
self.buttons["delete_blendshape"] = QtWidgets.QPushButton("Delete BlendShape")
|
||||
self.buttons["delete_blendshape"].setObjectName("deleteBlendshapeButton")
|
||||
self.buttons["delete_blendshape"].setIcon(ui_utils.get_icon("blendShape.png"))
|
||||
self.buttons["delete_blendshape"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
self.buttons["update_blendshape"] = QtWidgets.QPushButton(LANG.get("update_blendshape", "更新混合形状"))
|
||||
self.buttons["update_blendshape"].setObjectName("updateBlendshapeButton")
|
||||
self.buttons["batch_blendshape"] = QtWidgets.QPushButton("Batch BlendShape")
|
||||
self.buttons["batch_blendshape"].setObjectName("batchBlendshapeButton")
|
||||
self.buttons["batch_blendshape"].setIcon(ui_utils.get_icon("blendShape.png"))
|
||||
self.buttons["batch_blendshape"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
self.buttons["isolate_blendshape"] = QtWidgets.QPushButton(LANG.get("isolate_blendshape", "隔离混合形状"))
|
||||
self.buttons["isolate_blendshape"].setObjectName("isolateBlendshapeButton")
|
||||
self.buttons["rebuild_select"] = QtWidgets.QPushButton("Rebuild Select")
|
||||
self.buttons["rebuild_select"].setObjectName("rebuildSelectButton")
|
||||
self.buttons["rebuild_select"].setIcon(ui_utils.get_icon("loading.png"))
|
||||
self.buttons["rebuild_select"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
self.buttons["new_blendshape"] = QtWidgets.QPushButton(LANG.get("new_blendshape", "新建混合形状"))
|
||||
self.buttons["new_blendshape"].setObjectName("newBlendshapeButton")
|
||||
self.buttons["reposition_joints"] = QtWidgets.QPushButton("Reposition Joints")
|
||||
self.buttons["reposition_joints"].setObjectName("repositionJointsButton")
|
||||
self.buttons["reposition_joints"].setIcon(ui_utils.get_icon("loading.png"))
|
||||
self.buttons["reposition_joints"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
self.buttons["combine_blendshape"] = QtWidgets.QPushButton(LANG.get("combine_blendshape", "组合混合形状"))
|
||||
self.buttons["combine_blendshape"].setObjectName("combineBlendshapeButton")
|
||||
self.buttons["blend_select"] = QtWidgets.QPushButton("Blend Select")
|
||||
self.buttons["blend_select"].setObjectName("blendSelectButton")
|
||||
self.buttons["blend_select"].setIcon(ui_utils.get_icon("loading.png"))
|
||||
self.buttons["blend_select"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
|
||||
# 右侧Range按钮
|
||||
self.buttons["bs_range_plus"] = QtWidgets.QPushButton("Range +")
|
||||
self.buttons["bs_range_plus"].setObjectName("bsRangePlusButton")
|
||||
self.buttons["bs_range_plus"].setIcon(ui_utils.get_icon("behaviour.png"))
|
||||
|
||||
self.buttons["bs_range_minus"] = QtWidgets.QPushButton("Range -")
|
||||
self.buttons["bs_range_minus"].setObjectName("bsRangeMinusButton")
|
||||
self.buttons["bs_range_minus"].setIcon(ui_utils.get_icon("behaviour.png"))
|
||||
|
||||
# 底部标签页按钮
|
||||
self.buttons["tab_bs"] = QtWidgets.QPushButton("BS")
|
||||
self.buttons["tab_bs"].setObjectName("tabBsButton")
|
||||
self.buttons["tab_bs"].setCheckable(True)
|
||||
self.buttons["tab_bs"].setChecked(True)
|
||||
|
||||
self.buttons["tab_psd"] = QtWidgets.QPushButton("PSD")
|
||||
self.buttons["tab_psd"].setIcon(ui_utils.get_icon("psd.png"))
|
||||
self.buttons["tab_psd"].setObjectName("tabPsdButton")
|
||||
self.buttons["tab_psd"].setCheckable(True)
|
||||
|
||||
self.buttons["tab_bse"] = QtWidgets.QPushButton("BSE")
|
||||
self.buttons["tab_bse"].setIcon(ui_utils.get_icon("blendShape.png"))
|
||||
self.buttons["tab_bse"].setObjectName("tabBseButton")
|
||||
self.buttons["tab_bse"].setCheckable(True)
|
||||
|
||||
self.buttons["tab_key"] = QtWidgets.QPushButton("KEY")
|
||||
self.buttons["tab_key"].setIcon(ui_utils.get_icon("setKeyOnAnim.png"))
|
||||
self.buttons["tab_key"].setObjectName("tabKeyButton")
|
||||
self.buttons["tab_key"].setCheckable(True)
|
||||
|
||||
self.buttons["tab_jnt"] = QtWidgets.QPushButton("JNT")
|
||||
self.buttons["tab_jnt"].setObjectName("tabJntButton")
|
||||
self.buttons["tab_jnt"].setCheckable(True)
|
||||
|
||||
|
||||
self.buttons["tab_mir"] = QtWidgets.QPushButton("MIR")
|
||||
self.buttons["tab_mir"].setIcon(ui_utils.get_icon("mirrorR.png"))
|
||||
self.buttons["tab_mir"].setObjectName("tabMirButton")
|
||||
self.buttons["tab_mir"].setCheckable(True)
|
||||
|
||||
self.buttons["tab_ark"] = QtWidgets.QPushButton("ARK")
|
||||
self.buttons["tab_ark"].setIcon(ui_utils.get_icon("ARKit52.png"))
|
||||
self.buttons["tab_ark"].setObjectName("tabArkButton")
|
||||
self.buttons["tab_ark"].setCheckable(True)
|
||||
|
||||
self.buttons["tab_ctr"] = QtWidgets.QPushButton("CTR")
|
||||
self.buttons["tab_ctr"].setIcon(ui_utils.get_icon("ctrl_hide.png"))
|
||||
self.buttons["tab_ctr"].setObjectName("tabCtrButton")
|
||||
self.buttons["tab_ctr"].setCheckable(True)
|
||||
|
||||
# 底部滑块
|
||||
# 底部主滑块
|
||||
self.controls["bottom_main_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.controls["bottom_main_slider"].setObjectName("bottomMainSlider")
|
||||
self.controls["bottom_main_slider"].setMinimum(0)
|
||||
self.controls["bottom_main_slider"].setMaximum(100)
|
||||
self.controls["bottom_main_slider"].setValue(0)
|
||||
self.controls["bottom_main_slider"].setFixedHeight(20)
|
||||
|
||||
# 底部按钮
|
||||
self.buttons["exchange_from_expression"] = QtWidgets.QPushButton(LANG.get("exchange_from_expression", "交换从表情"))
|
||||
self.buttons["exchange_from_expression"].setObjectName("exchangeFromExpressionButton")
|
||||
# 底部主滑块布局,包含数值显示和All勾选框
|
||||
self.layouts["bottom_slider_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["bottom_slider_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["bottom_slider_layout"].setSpacing(2)
|
||||
|
||||
self.buttons["reset_selected_expression"] = QtWidgets.QPushButton(LANG.get("reset_selected_expression", "重置选定表情"))
|
||||
self.buttons["reset_selected_expression"].setObjectName("resetSelectedExpressionButton")
|
||||
# 添加数值显示标签
|
||||
self.controls["bottom_slider_value"] = QtWidgets.QLabel("0.000")
|
||||
self.controls["bottom_slider_value"].setObjectName("bottomSliderValue")
|
||||
self.controls["bottom_slider_value"].setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.controls["bottom_slider_value"].setFixedWidth(40)
|
||||
self.layouts["bottom_slider_layout"].addWidget(self.controls["bottom_slider_value"])
|
||||
|
||||
self.buttons["import_expression"] = QtWidgets.QPushButton(LANG.get("import_expression", "导入表情"))
|
||||
self.buttons["import_expression"].setObjectName("importExpressionButton")
|
||||
# 添加滑块
|
||||
self.layouts["bottom_slider_layout"].addWidget(self.controls["bottom_main_slider"])
|
||||
|
||||
self.buttons["control_panel_search"] = QtWidgets.QPushButton(LANG.get("control_panel_search", "控制面板搜索"))
|
||||
self.buttons["control_panel_search"].setObjectName("controlPanelSearchButton")
|
||||
# 添加"All"勾选框
|
||||
self.controls["bottom_slider_all_check"] = QtWidgets.QCheckBox("All")
|
||||
self.controls["bottom_slider_all_check"].setObjectName("bottomSliderAllCheck")
|
||||
self.layouts["bottom_slider_layout"].addWidget(self.controls["bottom_slider_all_check"])
|
||||
|
||||
self.buttons["select_related_keys"] = QtWidgets.QPushButton(LANG.get("select_related_keys", "选择相关键值"))
|
||||
self.buttons["select_related_keys"].setObjectName("selectRelatedKeysButton")
|
||||
# 底部功能按钮
|
||||
self.buttons["reset_default_expression"] = QtWidgets.QPushButton("Reset Default Expression")
|
||||
self.buttons["reset_default_expression"].setIcon(ui_utils.get_icon("reset.png"))
|
||||
self.buttons["reset_default_expression"].setObjectName("resetDefaultExpressionButton")
|
||||
|
||||
self.buttons["import_map_expression"] = QtWidgets.QPushButton(LANG.get("import_map_expression", "导入表情映射"))
|
||||
self.buttons["import_map_expression"].setObjectName("importMapExpressionButton")
|
||||
# 表情控制按钮
|
||||
self.buttons["reset_expression"] = QtWidgets.QPushButton(LANG.get("reset_expression", "还原默认表情"))
|
||||
self.buttons["find_expression"] = QtWidgets.QPushButton(LANG.get("find_expression", "查找选择表情"))
|
||||
self.buttons["find_control_panel"] = QtWidgets.QPushButton(LANG.get("find_control_panel", "控制面板查找"))
|
||||
self.buttons["find_select_expression"] = QtWidgets.QPushButton("Find Select Expression")
|
||||
self.buttons["find_select_expression"].setIcon(ui_utils.get_icon("expressions_current.png"))
|
||||
self.buttons["find_select_expression"].setObjectName("findSelectExpressionButton")
|
||||
|
||||
self.buttons["write_current_expressions"] = QtWidgets.QPushButton("Write Current Expressions")
|
||||
self.buttons["write_current_expressions"].setIcon(ui_utils.get_icon("expression.png"))
|
||||
self.buttons["write_current_expressions"].setObjectName("writeCurrentExpressionsButton")
|
||||
|
||||
self.buttons["controller_find"] = QtWidgets.QPushButton("Controller Find")
|
||||
self.buttons["controller_find"].setIcon(ui_utils.get_icon("controller.png"))
|
||||
self.buttons["controller_find"].setObjectName("controllerFindButton")
|
||||
|
||||
self.buttons["select_associated_joint"] = QtWidgets.QPushButton("Select Associated Joint")
|
||||
self.buttons["select_associated_joint"].setIcon(ui_utils.get_icon("out_joint.png"))
|
||||
self.buttons["select_associated_joint"].setObjectName("selectAssociatedJointButton")
|
||||
|
||||
self.buttons["write_find_mirror"] = QtWidgets.QPushButton("Write Find Mirror")
|
||||
self.buttons["write_find_mirror"].setIcon(ui_utils.get_icon("mirror.png"))
|
||||
self.buttons["write_find_mirror"].setObjectName("writeFindMirrorButton")
|
||||
|
||||
#========================================= LAYOUT =======================================
|
||||
def create_layouts(self):
|
||||
"""
|
||||
创建行为系统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)
|
||||
self.layouts["main_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["main_layout"].setSpacing(0)
|
||||
|
||||
# 添加标题标签
|
||||
self.layouts["main_layout"].addWidget(self.controls["title_label"])
|
||||
@@ -266,70 +419,136 @@ class BehaviourUI(ui_utils.BaseUI):
|
||||
# 创建主分割器
|
||||
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
|
||||
self.splitters["main_splitter"].setObjectName("behaviourMainSplitter")
|
||||
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
|
||||
self.splitters["main_splitter"].setHandleWidth(6) # 设置分割器手柄宽度
|
||||
self.splitters["main_splitter"].setChildrenCollapsible(False) # 禁止子部件折叠
|
||||
self.splitters["main_splitter"].setOpaqueResize(True) # 实时显示调整效果,更丝滑
|
||||
|
||||
# 添加主分割器
|
||||
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"], 1) # 设置伸缩因子为1,使其占据剩余空间
|
||||
|
||||
# 左侧面板
|
||||
self.controls["left_panel"] = QtWidgets.QWidget()
|
||||
self.controls["left_panel"].setObjectName("behaviourLeftPanel")
|
||||
self.controls["left_panel"].setMinimumWidth(0)
|
||||
self.controls["left_panel"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 右侧面板
|
||||
self.controls["right_panel"] = QtWidgets.QWidget()
|
||||
self.controls["right_panel"].setObjectName("behaviourRightPanel")
|
||||
self.controls["right_panel"].setMinimumWidth(0)
|
||||
self.controls["right_panel"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 将左右面板添加到分割器
|
||||
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
|
||||
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
|
||||
|
||||
# 左侧面板布局
|
||||
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)
|
||||
|
||||
# Raw Control组布局
|
||||
self.layouts["raw_control_layout"] = QtWidgets.QVBoxLayout(self.controls["raw_control_group"])
|
||||
self.layouts["raw_control_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["raw_control_layout"].setSpacing(5)
|
||||
|
||||
# 搜索框
|
||||
self.layouts["raw_control_layout"].addWidget(self.controls["search_input"])
|
||||
|
||||
# 控制列表
|
||||
self.layouts["raw_control_layout"].addWidget(self.controls["control_list"])
|
||||
|
||||
# 底部滑块
|
||||
self.layouts["raw_control_layout"].addWidget(self.controls["bottom_slider"])
|
||||
|
||||
# 页码按钮行
|
||||
self.layouts["page_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["page_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["page_buttons_layout"].setSpacing(2)
|
||||
|
||||
self.layouts["page_buttons_layout"].addWidget(self.buttons["page_all"])
|
||||
self.layouts["page_buttons_layout"].addWidget(self.buttons["page_2"])
|
||||
self.layouts["page_buttons_layout"].addWidget(self.buttons["page_3"])
|
||||
self.layouts["page_buttons_layout"].addWidget(self.buttons["page_4"])
|
||||
self.layouts["page_buttons_layout"].addWidget(self.buttons["page_5"])
|
||||
self.layouts["page_buttons_layout"].addWidget(self.buttons["page_6"])
|
||||
|
||||
self.layouts["raw_control_layout"].addLayout(self.layouts["page_buttons_layout"])
|
||||
|
||||
# 左下角按钮行
|
||||
self.layouts["range_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["range_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["range_buttons_layout"].setSpacing(2)
|
||||
|
||||
self.layouts["range_buttons_layout"].addWidget(self.buttons["range_minus"])
|
||||
self.layouts["range_buttons_layout"].addWidget(self.buttons["range_plus"])
|
||||
self.layouts["range_buttons_layout"].addStretch()
|
||||
|
||||
self.layouts["raw_control_layout"].addLayout(self.layouts["range_buttons_layout"])
|
||||
|
||||
# 添加Raw Control组到左侧面板
|
||||
self.layouts["left_layout"].addWidget(self.controls["raw_control_group"])
|
||||
|
||||
# 右侧面板布局
|
||||
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)
|
||||
|
||||
# BlendShapes组布局
|
||||
self.layouts["blendshapes_layout"] = QtWidgets.QVBoxLayout(self.controls["blendshapes_group"])
|
||||
self.layouts["blendshapes_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["blendshapes_layout"].setSpacing(5)
|
||||
# 左侧面板控件 - Raw Control
|
||||
self.controls["raw_control_group"] = QtWidgets.QGroupBox("Raw Control")
|
||||
self.controls["raw_control_group"].setObjectName("rawControlGroup")
|
||||
self.controls["raw_control_group"].setMinimumWidth(0) # 设置最小宽度为零
|
||||
self.controls["raw_control_group"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# BlendShapes列表
|
||||
self.layouts["blendshapes_layout"].addWidget(self.controls["blendshapes_list"])
|
||||
# 左侧面板控件布局
|
||||
self.layouts["raw_control_layout"] = QtWidgets.QVBoxLayout()
|
||||
self.layouts["raw_control_layout"].setContentsMargins(2, 2, 2, 2)
|
||||
self.layouts["raw_control_layout"].setSpacing(2)
|
||||
self.controls["raw_control_group"].setLayout(self.layouts["raw_control_layout"])
|
||||
|
||||
# 滑块
|
||||
self.layouts["blendshapes_layout"].addWidget(self.controls["bs_slider"])
|
||||
# 添加控制列表到Raw Control布局
|
||||
self.layouts["raw_control_layout"].addWidget(self.controls["control_list"])
|
||||
|
||||
# 左侧滑块布局
|
||||
self.layouts["raw_control_layout"].addLayout(self.layouts["raw_slider_layout"])
|
||||
|
||||
# 范围调整按钮布局
|
||||
self.layouts["range_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["range_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["range_buttons_layout"].setSpacing(2)
|
||||
|
||||
# 设置Range按钮的策略,使其均等撑满一行
|
||||
size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
self.buttons["range_plus"].setSizePolicy(size_policy)
|
||||
self.buttons["range_minus"].setSizePolicy(size_policy)
|
||||
|
||||
self.layouts["range_buttons_layout"].addWidget(self.buttons["range_plus"])
|
||||
self.layouts["range_buttons_layout"].addWidget(self.buttons["range_minus"])
|
||||
|
||||
# 添加范围按钮布局到Raw Control布局
|
||||
self.layouts["raw_control_layout"].addLayout(self.layouts["range_buttons_layout"])
|
||||
|
||||
# 页码按钮布局
|
||||
self.layouts["page_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["page_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["page_buttons_layout"].setSpacing(2)
|
||||
|
||||
# 设置页码按钮的策略,使其均等撑满一行
|
||||
for button_name in ["prev_page", "next_page", "page_all", "page_2", "page_3", "page_4", "page_5", "page_6"]:
|
||||
if button_name in self.buttons:
|
||||
self.buttons[button_name].setSizePolicy(size_policy)
|
||||
|
||||
# 添加页码按钮到布局
|
||||
for button_name in ["prev_page", "next_page", "page_all", "page_2", "page_3", "page_4", "page_5", "page_6"]:
|
||||
if button_name in self.buttons:
|
||||
self.layouts["page_buttons_layout"].addWidget(self.buttons[button_name])
|
||||
|
||||
# 添加页码按钮布局到Raw Control布局
|
||||
self.layouts["raw_control_layout"].addLayout(self.layouts["page_buttons_layout"])
|
||||
|
||||
# 添加Raw Control组到左侧面板
|
||||
self.layouts["left_layout"].addWidget(self.controls["raw_control_group"])
|
||||
|
||||
# 右侧面板控件 - Related BlendShapes
|
||||
self.controls["blendshapes_group"] = QtWidgets.QGroupBox("Related BlendShapes")
|
||||
self.controls["blendshapes_group"].setObjectName("blendshapesGroup")
|
||||
self.controls["blendshapes_group"].setMinimumWidth(0) # 设置最小宽度为零
|
||||
self.controls["blendshapes_group"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 右侧面板控件布局
|
||||
self.layouts["blendshapes_layout"] = QtWidgets.QVBoxLayout()
|
||||
self.layouts["blendshapes_layout"].setContentsMargins(2, 2, 2, 2)
|
||||
self.layouts["blendshapes_layout"].setSpacing(2)
|
||||
self.controls["blendshapes_group"].setLayout(self.layouts["blendshapes_layout"])
|
||||
|
||||
# 添加BlendShapes列表到BlendShapes布局
|
||||
self.layouts["blendshapes_layout"].addWidget(self.controls["blendshapes_list"], 1) # 设置伸缩因子为1,使其占据更多空间
|
||||
|
||||
# 右侧滑块布局
|
||||
self.layouts["blendshapes_layout"].addLayout(self.layouts["bs_slider_layout"])
|
||||
|
||||
# BS范围调整按钮布局
|
||||
self.layouts["bs_range_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["bs_range_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["bs_range_buttons_layout"].setSpacing(2)
|
||||
|
||||
# 设置BS Range按钮的策略,使其均等撑满一行
|
||||
size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
self.buttons["bs_range_plus"].setSizePolicy(size_policy)
|
||||
self.buttons["bs_range_minus"].setSizePolicy(size_policy)
|
||||
|
||||
self.layouts["bs_range_buttons_layout"].addWidget(self.buttons["bs_range_plus"])
|
||||
self.layouts["bs_range_buttons_layout"].addWidget(self.buttons["bs_range_minus"])
|
||||
|
||||
# 添加BS范围按钮布局到BlendShapes布局
|
||||
self.layouts["blendshapes_layout"].addLayout(self.layouts["bs_range_buttons_layout"])
|
||||
|
||||
# 为所有按钮设置统一的大小策略
|
||||
for button_name in ["flip_target", "mirror_target", "find_flip_target",
|
||||
"add_blendshape", "delete_blendshape", "batch_blendshape",
|
||||
"rebuild_select", "reposition_joints", "blend_select"]:
|
||||
if button_name in self.buttons:
|
||||
self.buttons[button_name].setMinimumWidth(0)
|
||||
self.buttons[button_name].setMinimumHeight(25) # 设置最小高度,确保按钮可见
|
||||
self.buttons[button_name].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
|
||||
# BlendShape操作按钮网格
|
||||
self.layouts["bs_buttons_grid"] = QtWidgets.QGridLayout()
|
||||
@@ -337,136 +556,123 @@ class BehaviourUI(ui_utils.BaseUI):
|
||||
self.layouts["bs_buttons_grid"].setSpacing(2)
|
||||
|
||||
# 添加按钮到网格
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["reset_blendshape"], 0, 0)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["mirror_blendshape"], 0, 1)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["flip_target"], 0, 0)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["mirror_target"], 0, 1)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["find_flip_target"], 0, 2)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["add_blendshape"], 1, 0)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["remove_blendshape"], 1, 1)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["update_blendshape"], 2, 0)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["isolate_blendshape"], 2, 1)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["new_blendshape"], 3, 0)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["combine_blendshape"], 3, 1)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["delete_blendshape"], 1, 1)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["batch_blendshape"], 1, 2)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["rebuild_select"], 2, 0)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["reposition_joints"], 2, 1)
|
||||
self.layouts["bs_buttons_grid"].addWidget(self.buttons["blend_select"], 2, 2)
|
||||
|
||||
# 添加按钮网格到BlendShapes布局
|
||||
self.layouts["blendshapes_layout"].addLayout(self.layouts["bs_buttons_grid"])
|
||||
|
||||
# 标签页按钮行
|
||||
# 添加BlendShapes组到右侧面板
|
||||
self.layouts["right_layout"].addWidget(self.controls["blendshapes_group"], 1) # 设置伸缩因子为1,使其占据更多空间
|
||||
|
||||
# 底部标签页按钮行
|
||||
self.layouts["tab_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["tab_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["tab_buttons_layout"].setSpacing(2)
|
||||
self.layouts["tab_buttons_layout"].setSpacing(0)
|
||||
|
||||
self.layouts["tab_buttons_layout"].addWidget(self.buttons["tab_bs"])
|
||||
self.layouts["tab_buttons_layout"].addWidget(self.buttons["tab_psd"])
|
||||
self.layouts["tab_buttons_layout"].addWidget(self.buttons["tab_key"])
|
||||
self.layouts["tab_buttons_layout"].addWidget(self.buttons["tab_jnt"])
|
||||
self.layouts["tab_buttons_layout"].addWidget(self.buttons["tab_ark"])
|
||||
self.layouts["tab_buttons_layout"].addWidget(self.buttons["tab_ctr"])
|
||||
# 设置标签页按钮的策略,使其均等撑满一行
|
||||
for button_name in ["tab_psd", "tab_bse", "tab_key", "tab_mir", "tab_ark", "tab_ctr"]:
|
||||
if button_name in self.buttons:
|
||||
self.buttons[button_name].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
self.layouts["tab_buttons_layout"].addWidget(self.buttons[button_name])
|
||||
|
||||
self.layouts["blendshapes_layout"].addLayout(self.layouts["tab_buttons_layout"])
|
||||
# 添加标签页按钮行到主布局
|
||||
self.layouts["main_layout"].addLayout(self.layouts["tab_buttons_layout"])
|
||||
|
||||
# 添加BlendShapes组到右侧面板
|
||||
self.layouts["right_layout"].addWidget(self.controls["blendshapes_group"])
|
||||
# 底部按钮布局
|
||||
self.layouts["bottom_buttons_layout"] = QtWidgets.QVBoxLayout()
|
||||
self.layouts["bottom_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["bottom_buttons_layout"].setSpacing(5)
|
||||
|
||||
# 底部工具面板
|
||||
self.layouts["bottom_panel"] = QtWidgets.QVBoxLayout()
|
||||
self.layouts["bottom_panel"].setContentsMargins(2, 2, 2, 2)
|
||||
self.layouts["bottom_panel"].setSpacing(2)
|
||||
# 第一行按钮
|
||||
self.layouts["bottom_buttons_row1"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["bottom_buttons_row1"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["bottom_buttons_row1"].setSpacing(5)
|
||||
|
||||
# 底部滑块
|
||||
self.layouts["bottom_panel"].addWidget(self.controls["bottom_main_slider"])
|
||||
self.layouts["bottom_buttons_row1"].addWidget(self.buttons["reset_default_expression"])
|
||||
self.layouts["bottom_buttons_row1"].addWidget(self.buttons["find_select_expression"])
|
||||
self.layouts["bottom_buttons_row1"].addWidget(self.buttons["write_current_expressions"])
|
||||
|
||||
# 底部按钮网格
|
||||
self.layouts["bottom_buttons_grid"] = QtWidgets.QGridLayout()
|
||||
self.layouts["bottom_buttons_grid"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["bottom_buttons_grid"].setSpacing(2)
|
||||
# 第二行按钮
|
||||
self.layouts["bottom_buttons_row2"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["bottom_buttons_row2"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["bottom_buttons_row2"].setSpacing(5)
|
||||
|
||||
# 添加底部按钮
|
||||
self.layouts["bottom_buttons_grid"].addWidget(self.buttons["exchange_from_expression"], 0, 0)
|
||||
self.layouts["bottom_buttons_grid"].addWidget(self.buttons["reset_selected_expression"], 0, 1)
|
||||
self.layouts["bottom_buttons_grid"].addWidget(self.buttons["import_expression"], 0, 2)
|
||||
self.layouts["bottom_buttons_grid"].addWidget(self.buttons["control_panel_search"], 1, 0)
|
||||
self.layouts["bottom_buttons_grid"].addWidget(self.buttons["select_related_keys"], 1, 1)
|
||||
self.layouts["bottom_buttons_grid"].addWidget(self.buttons["import_map_expression"], 1, 2)
|
||||
self.layouts["bottom_buttons_row2"].addWidget(self.buttons["controller_find"])
|
||||
self.layouts["bottom_buttons_row2"].addWidget(self.buttons["select_associated_joint"])
|
||||
self.layouts["bottom_buttons_row2"].addWidget(self.buttons["write_find_mirror"])
|
||||
|
||||
self.layouts["bottom_panel"].addLayout(self.layouts["bottom_buttons_grid"])
|
||||
# 将两行按钮添加到底部按钮布局
|
||||
self.layouts["bottom_buttons_layout"].addLayout(self.layouts["bottom_buttons_row1"])
|
||||
self.layouts["bottom_buttons_layout"].addLayout(self.layouts["bottom_buttons_row2"])
|
||||
|
||||
# 添加底部面板到主布局
|
||||
self.layouts["main_layout"].addLayout(self.layouts["bottom_panel"])
|
||||
# 添加底部按钮布局到主布局
|
||||
self.layouts["main_layout"].addLayout(self.layouts["bottom_buttons_layout"])
|
||||
|
||||
# 将左右面板添加到主分割器
|
||||
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
|
||||
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
|
||||
# 底部主滑块布局
|
||||
self.layouts["main_layout"].addLayout(self.layouts["bottom_slider_layout"])
|
||||
|
||||
# 设置分割器初始大小和伸缩因子
|
||||
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控件的交互行为
|
||||
创建信号连接
|
||||
连接按钮点击事件和其他UI事件
|
||||
"""
|
||||
# 导入行为工具函数
|
||||
from scripts.utils import utils_behaviour
|
||||
# 创建信号映射字典
|
||||
signal_mapping = {
|
||||
'buttons': {
|
||||
# 底部标签页按钮
|
||||
'tab_psd': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(0)},
|
||||
'tab_bse': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(1)},
|
||||
'tab_key': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(2)},
|
||||
'tab_mir': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(3)},
|
||||
'tab_ark': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(4)},
|
||||
'tab_ctr': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(5)},
|
||||
|
||||
# 功能按钮
|
||||
'flip_target': {'signal': 'clicked', 'handler': utils_behaviour.flip_target},
|
||||
'mirror_target': {'signal': 'clicked', 'handler': utils_behaviour.mirror_target},
|
||||
'find_flip_target': {'signal': 'clicked', 'handler': utils_behaviour.find_flip_target},
|
||||
'add_blendshape': {'signal': 'clicked', 'handler': utils_behaviour.add_blendshape},
|
||||
'delete_blendshape': {'signal': 'clicked', 'handler': utils_behaviour.delete_blendshape},
|
||||
'batch_blendshape': {'signal': 'clicked', 'handler': utils_behaviour.batch_blendshape},
|
||||
'rebuild_select': {'signal': 'clicked', 'handler': utils_behaviour.rebuild_select},
|
||||
'reposition_joints': {'signal': 'clicked', 'handler': utils_behaviour.reposition_joints},
|
||||
'blend_select': {'signal': 'clicked', 'handler': utils_behaviour.blend_select},
|
||||
'reset_default_expression': {'signal': 'clicked', 'handler': utils_behaviour.reset_default_expression},
|
||||
'find_select_expression': {'signal': 'clicked', 'handler': utils_behaviour.find_select_expression},
|
||||
'write_current_expressions': {'signal': 'clicked', 'handler': utils_behaviour.write_current_expressions},
|
||||
'controller_find': {'signal': 'clicked', 'handler': utils_behaviour.controller_find},
|
||||
'select_associated_joint': {'signal': 'clicked', 'handler': utils_behaviour.select_associated_joint},
|
||||
'write_find_mirror': {'signal': 'clicked', 'handler': utils_behaviour.write_find_mirror},
|
||||
|
||||
# 范围按钮
|
||||
'range_plus': {'signal': 'clicked', 'handler': lambda: utils_behaviour.adjust_range(0.1)},
|
||||
'range_minus': {'signal': 'clicked', 'handler': lambda: utils_behaviour.adjust_range(-0.1)},
|
||||
'bs_range_plus': {'signal': 'clicked', 'handler': lambda: utils_behaviour.adjust_bs_range(0.1)},
|
||||
'bs_range_minus': {'signal': 'clicked', 'handler': lambda: utils_behaviour.adjust_bs_range(-0.1)},
|
||||
},
|
||||
'controls': {
|
||||
# 滑块控件
|
||||
'raw_slider': {'signal': 'valueChanged', 'handler': utils_behaviour.on_raw_slider_changed},
|
||||
'bs_slider': {'signal': 'valueChanged', 'handler': utils_behaviour.on_bs_slider_changed},
|
||||
'bottom_main_slider': {'signal': 'valueChanged', 'handler': utils_behaviour.on_bottom_slider_changed},
|
||||
|
||||
# 列表控件
|
||||
'control_list': {'signal': 'itemSelectionChanged', 'handler': utils_behaviour.on_control_selection_changed},
|
||||
'blendshapes_list': {'signal': 'itemSelectionChanged', 'handler': utils_behaviour.on_blendshape_selection_changed},
|
||||
}
|
||||
}
|
||||
|
||||
# 左侧面板连接
|
||||
# 搜索框连接
|
||||
self.controls["search_input"].textChanged.connect(utils_behaviour.filter_controls)
|
||||
# 使用ui_utils中的函数连接信号
|
||||
ui_utils.connect_ui_signals(self, signal_mapping)
|
||||
|
||||
# 控制列表连接
|
||||
self.controls["control_list"].itemClicked.connect(utils_behaviour.control_selected)
|
||||
self.controls["control_list"].itemSelectionChanged.connect(utils_behaviour.update_control_selection)
|
||||
|
||||
# 底部滑块连接
|
||||
self.controls["bottom_slider"].valueChanged.connect(utils_behaviour.update_control_value)
|
||||
|
||||
# 页码按钮连接
|
||||
self.buttons["page_all"].clicked.connect(lambda: utils_behaviour.switch_page("all"))
|
||||
self.buttons["page_2"].clicked.connect(lambda: utils_behaviour.switch_page("2"))
|
||||
self.buttons["page_3"].clicked.connect(lambda: utils_behaviour.switch_page("3"))
|
||||
self.buttons["page_4"].clicked.connect(lambda: utils_behaviour.switch_page("4"))
|
||||
self.buttons["page_5"].clicked.connect(lambda: utils_behaviour.switch_page("5"))
|
||||
self.buttons["page_6"].clicked.connect(lambda: utils_behaviour.switch_page("6"))
|
||||
|
||||
# 左下角按钮连接
|
||||
self.buttons["range_minus"].clicked.connect(utils_behaviour.decrease_range)
|
||||
self.buttons["range_plus"].clicked.connect(utils_behaviour.increase_range)
|
||||
|
||||
# 右侧面板连接
|
||||
# BlendShapes列表连接
|
||||
self.controls["blendshapes_list"].itemClicked.connect(utils_behaviour.blendshape_selected)
|
||||
self.controls["blendshapes_list"].itemSelectionChanged.connect(utils_behaviour.update_blendshape_selection)
|
||||
|
||||
# 滑块连接
|
||||
self.controls["bs_slider"].valueChanged.connect(utils_behaviour.update_blendshape_value)
|
||||
|
||||
# BlendShape操作按钮连接
|
||||
self.buttons["reset_blendshape"].clicked.connect(utils_behaviour.reset_blendshape)
|
||||
self.buttons["mirror_blendshape"].clicked.connect(utils_behaviour.mirror_blendshape)
|
||||
self.buttons["add_blendshape"].clicked.connect(utils_behaviour.add_blendshape)
|
||||
self.buttons["remove_blendshape"].clicked.connect(utils_behaviour.remove_blendshape)
|
||||
self.buttons["update_blendshape"].clicked.connect(utils_behaviour.update_blendshape)
|
||||
self.buttons["isolate_blendshape"].clicked.connect(utils_behaviour.isolate_blendshape)
|
||||
self.buttons["new_blendshape"].clicked.connect(utils_behaviour.new_blendshape)
|
||||
self.buttons["combine_blendshape"].clicked.connect(utils_behaviour.combine_blendshape)
|
||||
|
||||
# 标签页按钮连接
|
||||
self.buttons["tab_bs"].clicked.connect(lambda: utils_behaviour.switch_tab("bs"))
|
||||
self.buttons["tab_psd"].clicked.connect(lambda: utils_behaviour.switch_tab("psd"))
|
||||
self.buttons["tab_key"].clicked.connect(lambda: utils_behaviour.switch_tab("key"))
|
||||
self.buttons["tab_jnt"].clicked.connect(lambda: utils_behaviour.switch_tab("jnt"))
|
||||
self.buttons["tab_ark"].clicked.connect(lambda: utils_behaviour.switch_tab("ark"))
|
||||
self.buttons["tab_ctr"].clicked.connect(lambda: utils_behaviour.switch_tab("ctr"))
|
||||
|
||||
# 底部滑块连接
|
||||
self.controls["bottom_main_slider"].valueChanged.connect(utils_behaviour.update_main_value)
|
||||
|
||||
# 底部按钮连接
|
||||
self.buttons["exchange_from_expression"].clicked.connect(utils_behaviour.exchange_from_expression)
|
||||
self.buttons["reset_selected_expression"].clicked.connect(utils_behaviour.reset_selected_expression)
|
||||
self.buttons["import_expression"].clicked.connect(utils_behaviour.import_expression)
|
||||
self.buttons["control_panel_search"].clicked.connect(utils_behaviour.control_panel_search)
|
||||
self.buttons["select_related_keys"].clicked.connect(utils_behaviour.select_related_keys)
|
||||
self.buttons["import_map_expression"].clicked.connect(utils_behaviour.import_map_expression)
|
||||
# 连接Maya选择变化事件
|
||||
ui_utils.connect_maya_selection_changed(self, lambda: utils_behaviour.on_selection_changed(self), self.main_widget)
|
@@ -47,6 +47,8 @@ ASSETS_PATH = config.ASSETS_PATH
|
||||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||||
DNA_IMG_PATH = config.DNA_IMG_PATH
|
||||
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
||||
TOOL_WIDTH = config.TOOL_WIDTH
|
||||
TOOL_HEIGHT = config.TOOL_HEIGHT
|
||||
#========================================= LOCATION =======================================
|
||||
from scripts.ui import localization
|
||||
LANG = localization.LANG
|
||||
@@ -64,15 +66,37 @@ class DefinitionUI(ui_utils.BaseUI):
|
||||
"""
|
||||
super(DefinitionUI, self).__init__()
|
||||
|
||||
# 设置单例实例
|
||||
DefinitionUI._instance = self
|
||||
|
||||
# 创建主控件
|
||||
self.main_widget = QtWidgets.QWidget()
|
||||
self.main_widget.setObjectName("definitionMainWidget")
|
||||
|
||||
# 初始化字典
|
||||
self.controls = {}
|
||||
self.layouts = {}
|
||||
self.splitters = {}
|
||||
self.buttons = {}
|
||||
|
||||
# 初始化UI
|
||||
self.create_widgets()
|
||||
self.create_layouts()
|
||||
self.create_connections()
|
||||
|
||||
|
||||
# 添加左右面板到分割器
|
||||
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
|
||||
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
|
||||
|
||||
# 设置分割器所有子元素的最小尺寸为0,确保可以自由调整
|
||||
ui_utils.set_splitter_children_minimum_size(self, recursive=True)
|
||||
|
||||
# 设置所有控件的最小尺寸为0,确保分割器可以自由移动
|
||||
ui_utils.set_all_controls_minimum_size(self)
|
||||
|
||||
# 使用ui_utils中的函数强制设置均等大小
|
||||
ui_utils.force_equal_splitter_sizes(self)
|
||||
|
||||
#========================================= WIDGET =======================================
|
||||
def create_widgets(self):
|
||||
"""
|
||||
@@ -89,6 +113,9 @@ class DefinitionUI(ui_utils.BaseUI):
|
||||
# 主分割器
|
||||
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
|
||||
self.splitters["main_splitter"].setObjectName("definitionMainSplitter")
|
||||
self.splitters["main_splitter"].setHandleWidth(6) # 设置分割器手柄宽度
|
||||
self.splitters["main_splitter"].setChildrenCollapsible(False) # 禁止子部件折叠
|
||||
self.splitters["main_splitter"].setOpaqueResize(True) # 实时显示调整效果
|
||||
|
||||
# 左侧面板
|
||||
self.controls["left_panel"] = QtWidgets.QWidget()
|
||||
@@ -221,8 +248,14 @@ class DefinitionUI(ui_utils.BaseUI):
|
||||
# 添加标题标签
|
||||
self.layouts["main_layout"].addWidget(self.controls["title_label"])
|
||||
|
||||
# 添加主分割器
|
||||
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
|
||||
# 主分割器布局
|
||||
self.layouts["main_splitter_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["main_splitter_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["main_splitter_layout"].setSpacing(0)
|
||||
self.layouts["main_splitter_layout"].addWidget(self.splitters["main_splitter"])
|
||||
|
||||
# 添加主分割器布局到主布局
|
||||
self.layouts["main_layout"].addLayout(self.layouts["main_splitter_layout"])
|
||||
|
||||
# 左侧面板布局
|
||||
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
|
||||
@@ -338,23 +371,6 @@ class DefinitionUI(ui_utils.BaseUI):
|
||||
|
||||
# 添加底部面板到主布局
|
||||
self.layouts["main_layout"].addLayout(self.layouts["bottom_panel"])
|
||||
|
||||
# 设置分割器初始大小
|
||||
# 主分割器左右各半
|
||||
self.splitters["main_splitter"].setSizes([500, 500])
|
||||
# 左侧分割器上下各半
|
||||
self.splitters["left_splitter"].setSizes([250, 250])
|
||||
# 右侧分割器均匀分配
|
||||
right_item_height = 1000 // self.splitters["right_splitter"].count()
|
||||
self.splitters["right_splitter"].setSizes([right_item_height] * self.splitters["right_splitter"].count())
|
||||
|
||||
# 设置分割器的伸缩因子,确保左右栏能够自动调整宽度
|
||||
for i in range(self.splitters["main_splitter"].count()):
|
||||
self.splitters["main_splitter"].setStretchFactor(i, 1)
|
||||
|
||||
# 将左右面板添加到主分割器
|
||||
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
|
||||
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
|
||||
|
||||
#======================================= CONNECTION =====================================
|
||||
def create_connections(self):
|
||||
|
@@ -52,6 +52,8 @@ ASSETS_PATH = config.ASSETS_PATH
|
||||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||||
DNA_IMG_PATH = config.DNA_IMG_PATH
|
||||
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
||||
TOOL_WIDTH = config.TOOL_WIDTH
|
||||
TOOL_HEIGHT = config.TOOL_HEIGHT
|
||||
#========================================= LOCATION =======================================
|
||||
from scripts.ui import localization
|
||||
LANG = localization.LANG
|
||||
@@ -265,10 +267,10 @@ class GeometryUI(ui_utils.BaseUI):
|
||||
input_field.setPlaceholderText(LANG.get("enter_model_name", "输入模型名称"))
|
||||
|
||||
# 创建加载按钮
|
||||
load_button = QtWidgets.QPushButton(LANG.get("load", "加载"))
|
||||
load_button = QtWidgets.QPushButton(LANG.get(" load ", " 加 载 "))
|
||||
load_button.setObjectName(f"{lod_name}_{part}_load_button")
|
||||
load_button.setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "loading.png")))
|
||||
load_button.setFixedSize(60, 24) # 增加宽度以容纳文字
|
||||
load_button.setFixedSize(120, 24)
|
||||
load_button.setToolTip(LANG.get("load_model", "加载模型"))
|
||||
|
||||
# 将控件添加到布局
|
||||
@@ -294,8 +296,8 @@ class GeometryUI(ui_utils.BaseUI):
|
||||
trash_icon = QtGui.QIcon(os.path.join(ICONS_PATH, "delete.png"))
|
||||
trash_button = QtWidgets.QPushButton()
|
||||
trash_button.setIcon(trash_icon)
|
||||
trash_button.setIconSize(QtCore.QSize(32, 32)) # 设置图标大小为32x32
|
||||
trash_button.setFixedSize(32, 32) # 增大按钮尺寸
|
||||
trash_button.setIconSize(QtCore.QSize(28, 28))
|
||||
trash_button.setFixedSize(28, 28)
|
||||
trash_button.setToolTip(LANG.get("delete", "删除"))
|
||||
trash_button.setStyleSheet("QPushButton { border: none; background-color: transparent; }")
|
||||
self.controls["tab_widget"].setCornerWidget(trash_button, QtCore.Qt.TopRightCorner)
|
||||
|
@@ -50,6 +50,8 @@ ASSETS_PATH = config.ASSETS_PATH
|
||||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||||
DNA_IMG_PATH = config.DNA_IMG_PATH
|
||||
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
||||
TOOL_WIDTH = config.TOOL_WIDTH
|
||||
TOOL_HEIGHT = config.TOOL_HEIGHT
|
||||
#========================================= LOCATION =======================================
|
||||
from scripts.ui import localization
|
||||
LANG = localization.LANG
|
||||
@@ -643,12 +645,12 @@ class RiggingUI(ui_utils.BaseUI):
|
||||
#======================================= FUNCTIONS ======================================
|
||||
def create_connections(self):
|
||||
"""
|
||||
连接UI信号和槽
|
||||
设置UI控件的事件处理函数
|
||||
创建信号连接
|
||||
"""
|
||||
# 创建信号映射字典
|
||||
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},
|
||||
@@ -658,6 +660,12 @@ class RiggingUI(ui_utils.BaseUI):
|
||||
'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},
|
||||
|
||||
# 已创建的按钮
|
||||
'browse_path': {'signal': 'clicked', 'handler': lambda: utils_rigging.browse_file(self, "项目路径", self.controls["project_path_input"])},
|
||||
'browse_dna': {'signal': 'clicked', 'handler': lambda: utils_rigging.browse_file(self, "DNA文件", self.controls["presets_dna_input"], "dna")},
|
||||
'export_presets': {'signal': 'clicked', 'handler': utils_rigging.export_presets},
|
||||
'import_presets': {'signal': 'clicked', 'handler': utils_rigging.import_presets},
|
||||
},
|
||||
'splitters': {
|
||||
'main_splitter': {'signal': 'splitterMoved', 'handler': lambda pos, index: ui_utils.on_splitter_moved(self, pos, index)},
|
||||
@@ -667,46 +675,5 @@ class RiggingUI(ui_utils.BaseUI):
|
||||
# 使用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)
|
||||
# 连接Maya选择变化事件
|
||||
ui_utils.connect_maya_selection_changed(self, lambda: utils_rigging.on_selection_changed(self), self.main_widget)
|
@@ -1,4 +1,4 @@
|
||||
/* MetaFusion 插件样式表 */
|
||||
/* 插件样式表 */
|
||||
/* 作者: CGNICO */
|
||||
/* 版本: Alpha v1.0.0 */
|
||||
|
||||
@@ -276,17 +276,26 @@ QSplitter::handle {
|
||||
}
|
||||
|
||||
QSplitter::handle:horizontal {
|
||||
width: 2px;
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
QSplitter::handle:vertical {
|
||||
height: 2px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
QSplitter::handle:hover {
|
||||
background-color: #007ACC;
|
||||
}
|
||||
|
||||
QSplitter {
|
||||
border: none;
|
||||
}
|
||||
|
||||
QSplitter > QWidget {
|
||||
min-width: 0px;
|
||||
min-height: 0px;
|
||||
}
|
||||
|
||||
/* ==================== 滑块样式 ==================== */
|
||||
QSlider::groove:horizontal {
|
||||
border: 1px solid #1E1E1E;
|
||||
|
@@ -49,6 +49,8 @@ ASSETS_PATH = config.ASSETS_PATH
|
||||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||||
DNA_IMG_PATH = config.DNA_IMG_PATH
|
||||
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
||||
TOOL_WIDTH = config.TOOL_WIDTH
|
||||
TOOL_HEIGHT = config.TOOL_HEIGHT
|
||||
#========================================= LOCATION =======================================
|
||||
from scripts.ui import localization
|
||||
LANG = localization.LANG
|
||||
|
@@ -19,6 +19,8 @@ import traceback
|
||||
import locale
|
||||
import sys
|
||||
import os
|
||||
import weakref
|
||||
|
||||
#========================================== CONFIG ========================================
|
||||
import config
|
||||
TOOL_NAME = config.TOOL_NAME
|
||||
@@ -40,81 +42,21 @@ ASSETS_PATH = config.ASSETS_PATH
|
||||
DNA_FILE_PATH = config.DNA_FILE_PATH
|
||||
DNA_IMG_PATH = config.DNA_IMG_PATH
|
||||
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
||||
TOOL_WIDTH = config.TOOL_WIDTH
|
||||
TOOL_HEIGHT = config.TOOL_HEIGHT
|
||||
|
||||
#========================================= LOCATION =======================================
|
||||
from scripts.ui import localization
|
||||
LANG = localization.LANG
|
||||
|
||||
#============================================ INIT ==========================================
|
||||
# 定义窗口大小变化事件处理类
|
||||
# 用于监听窗口大小变化并调整分割器宽度
|
||||
class SplitterResizeHandler(QtCore.QObject):
|
||||
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)
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
# 监听大小变化事件
|
||||
if obj == self.parent_tab and event.type() == QtCore.QEvent.Resize:
|
||||
# 当窗口大小变化时,调整分割器宽度
|
||||
self.adjustSplitterSizes()
|
||||
return super(SplitterResizeHandler, self).eventFilter(obj, event)
|
||||
|
||||
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()
|
||||
# 根据面板数量设置分割器大小
|
||||
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()
|
||||
# 根据面板数量设置分割器大小
|
||||
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控件,避免全局变量
|
||||
#============================================ UI BASE ==========================================
|
||||
class BaseUI(object):
|
||||
"""
|
||||
UI基类
|
||||
所有UI面板的基类,提供通用的UI功能
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
初始化UI基类
|
||||
"""
|
||||
"""初始化UI基类"""
|
||||
# 初始化字典
|
||||
self.controls = {}
|
||||
self.layouts = {}
|
||||
@@ -126,214 +68,333 @@ class BaseUI(object):
|
||||
# 创建主控件
|
||||
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控件并存储到字典中
|
||||
"""
|
||||
# 子类实现
|
||||
"""创建UI控件"""
|
||||
pass
|
||||
|
||||
def create_layouts(self):
|
||||
"""
|
||||
创建UI布局
|
||||
创建所有UI布局并存储到字典中
|
||||
"""
|
||||
# 子类实现
|
||||
"""创建UI布局"""
|
||||
pass
|
||||
|
||||
def connect_ui_signals(self):
|
||||
"""
|
||||
连接UI信号和槽
|
||||
设置UI控件的事件处理函数
|
||||
"""
|
||||
# 子类实现
|
||||
def create_connections(self):
|
||||
"""连接UI信号和槽"""
|
||||
pass
|
||||
|
||||
def showEvent(self, event):
|
||||
"""
|
||||
显示事件
|
||||
当面板显示时调用on_show_event方法
|
||||
"""显示事件处理函数"""
|
||||
# 调用父类的showEvent方法
|
||||
super(BaseUI, self).showEvent(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"])
|
||||
# 强制设置分割器均等大小
|
||||
if hasattr(self, 'splitters') and 'main_splitter' in self.splitters:
|
||||
setup_splitter(self, 'main_splitter', equal_sizes=True)
|
||||
|
||||
#============================================ UI HELPERS ==========================================
|
||||
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, ...] # 可选,处理函数的参数
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
"""连接UI信号和槽"""
|
||||
# 遍历信号映射字典
|
||||
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', [])
|
||||
# 获取控件
|
||||
widget = widget_dict.get(widget_name)
|
||||
if not widget:
|
||||
# 静默处理未找到的控件,不显示警告
|
||||
# print(f"警告: 未找到控件 {widget_name}")
|
||||
continue
|
||||
|
||||
# 获取信号对象
|
||||
signal = getattr(widget, signal_name, None)
|
||||
# 获取信号名称和处理函数
|
||||
signal_name = signal_info.get('signal')
|
||||
handler = signal_info.get('handler')
|
||||
|
||||
if not signal_name or not handler:
|
||||
print(f"警告: 信号名称或处理函数未指定 {widget_name}")
|
||||
continue
|
||||
|
||||
# 连接信号和槽
|
||||
if signal and handler:
|
||||
if args:
|
||||
signal.connect(lambda *extra, h=handler, a=args: h(*a))
|
||||
else:
|
||||
signal.connect(handler)
|
||||
# 获取信号对象
|
||||
signal = getattr(widget, signal_name, None)
|
||||
if not signal:
|
||||
print(f"警告: 未找到信号 {signal_name} 在控件 {widget_name} 中")
|
||||
continue
|
||||
|
||||
# 获取可选参数
|
||||
args = signal_info.get('args', [])
|
||||
|
||||
# 连接信号和槽
|
||||
if args:
|
||||
signal.connect(lambda *_, handler=handler, args=args: handler(*args))
|
||||
else:
|
||||
signal.connect(handler)
|
||||
|
||||
def connect_maya_selection_changed(ui_instance, handler, parent_widget=None):
|
||||
"""
|
||||
连接Maya选择变化事件
|
||||
"""连接Maya选择变化事件"""
|
||||
# 如果已经有scriptJob,先删除
|
||||
if hasattr(ui_instance, 'selection_job') and ui_instance.selection_job > 0:
|
||||
try:
|
||||
cmds.scriptJob(kill=ui_instance.selection_job, force=True)
|
||||
except:
|
||||
pass
|
||||
|
||||
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
|
||||
parent_arg = {}
|
||||
if parent_widget and parent_widget.objectName():
|
||||
parent_arg = {"parent": parent_widget.objectName()}
|
||||
|
||||
# 创建scriptJob
|
||||
if parent_widget:
|
||||
job_id = cmds.scriptJob(event=["SelectionChanged", handler], parent=parent_widget.objectName())
|
||||
return job_id
|
||||
return None
|
||||
ui_instance.selection_job = cmds.scriptJob(
|
||||
event=["SelectionChanged", handler],
|
||||
protected=True,
|
||||
**parent_arg
|
||||
)
|
||||
print(f"已连接选择变化事件, scriptJob ID: {ui_instance.selection_job}")
|
||||
|
||||
# 获取Maya主窗口
|
||||
#============================================ MAYA HELPERS ==========================================
|
||||
def get_maya_main_window():
|
||||
"""
|
||||
获取Maya主窗口
|
||||
|
||||
Returns:
|
||||
QWidget: Maya主窗口控件
|
||||
"""
|
||||
main_window_ptr = omui.MQtUtil.mainWindow()
|
||||
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
|
||||
"""获取Maya主窗口"""
|
||||
ptr = omui.MQtUtil.mainWindow()
|
||||
if ptr is not None:
|
||||
return wrapInstance(int(ptr), QtWidgets.QWidget)
|
||||
|
||||
def get_parent_widget(widget_name):
|
||||
"""
|
||||
根据控件名称查找父容器控件
|
||||
|
||||
Args:
|
||||
widget_name (str): 控件名称
|
||||
|
||||
Returns:
|
||||
QWidget: 找到的父容器控件,如果未找到则返回None
|
||||
"""
|
||||
# 查找主窗口中的所有控件
|
||||
main_window = None
|
||||
for widget in QtWidgets.QApplication.topLevelWidgets():
|
||||
if widget.objectName() == f"{TOOL_NAME}MainWindow" or widget.objectName().endswith("MainWindow"):
|
||||
main_window = widget
|
||||
break
|
||||
|
||||
"""根据控件名称查找父容器控件"""
|
||||
# 获取Maya主窗口
|
||||
main_window = get_maya_main_window()
|
||||
if not main_window:
|
||||
print(f"无法找到主窗口,无法获取父容器: {widget_name}")
|
||||
return None
|
||||
|
||||
# 查找所有子控件
|
||||
def find_widget(parent, name):
|
||||
# 检查当前控件
|
||||
if parent.objectName() == name:
|
||||
return parent
|
||||
|
||||
# 递归查找子控件
|
||||
for child in parent.children():
|
||||
if isinstance(child, QtWidgets.QWidget):
|
||||
# 检查子控件
|
||||
if child.objectName() == name:
|
||||
return child
|
||||
|
||||
# 递归查找
|
||||
result = find_widget(child, name)
|
||||
if result:
|
||||
return result
|
||||
|
||||
return None
|
||||
|
||||
# 在主窗口中查找指定名称的控件
|
||||
found_widget = main_window.findChild(QtWidgets.QWidget, widget_name)
|
||||
if found_widget:
|
||||
return found_widget
|
||||
# 从主窗口开始查找
|
||||
return find_widget(main_window, widget_name)
|
||||
|
||||
def load_icon(icon_name):
|
||||
"""
|
||||
加载图标,支持多种来源
|
||||
|
||||
# 如果未找到精确匹配,尝试模糊匹配
|
||||
for child in main_window.findChildren(QtWidgets.QWidget):
|
||||
if widget_name.lower() in child.objectName().lower():
|
||||
return child
|
||||
Args:
|
||||
icon_name (str): 图标名称
|
||||
|
||||
Returns:
|
||||
QIcon: 加载的图标对象
|
||||
"""
|
||||
if not icon_name:
|
||||
return QtGui.QIcon()
|
||||
|
||||
print(f"无法找到控件: {widget_name}")
|
||||
return None
|
||||
# 尝试从插件图标路径加载
|
||||
if ICONS_PATH and os.path.exists(ICONS_PATH):
|
||||
# 检查不同的文件扩展名
|
||||
extensions = ['', '.png', '.jpg', '.svg', '.ico']
|
||||
for ext in extensions:
|
||||
path = os.path.join(ICONS_PATH, icon_name + ext)
|
||||
if os.path.exists(path):
|
||||
return QtGui.QIcon(path)
|
||||
|
||||
# 尝试从Maya内置图标加载
|
||||
for prefix in [':', ':/']:
|
||||
try:
|
||||
icon = QtGui.QIcon(QtGui.QPixmap(f"{prefix}{icon_name}"))
|
||||
if not icon.isNull():
|
||||
return icon
|
||||
except:
|
||||
continue
|
||||
|
||||
# 如果都失败,返回一个空图标
|
||||
return QtGui.QIcon()
|
||||
|
||||
#============================================ SPLITTER ==========================================
|
||||
def setup_splitter(ui_instance, splitter_name="main_splitter", equal_sizes=True):
|
||||
"""
|
||||
设置分割器的属性和大小,确保完全自由调整
|
||||
|
||||
Args:
|
||||
ui_instance: UI实例对象
|
||||
splitter_name (str): 分割器名称
|
||||
equal_sizes (bool): 是否设置均等大小
|
||||
|
||||
Returns:
|
||||
bool: 是否成功设置
|
||||
"""
|
||||
# 检查分割器是否存在
|
||||
if not hasattr(ui_instance, 'splitters') or splitter_name not in ui_instance.splitters:
|
||||
return False
|
||||
|
||||
# 获取分割器
|
||||
splitter = ui_instance.splitters[splitter_name]
|
||||
|
||||
# 设置分割器属性
|
||||
splitter.setOpaqueResize(True)
|
||||
splitter.setChildrenCollapsible(False)
|
||||
|
||||
# 设置伸缩因子和子部件属性
|
||||
for i in range(splitter.count()):
|
||||
# 设置伸缩因子
|
||||
splitter.setStretchFactor(i, 1)
|
||||
|
||||
# 设置子部件属性
|
||||
widget = splitter.widget(i)
|
||||
if widget:
|
||||
widget.setMinimumWidth(0)
|
||||
widget.setMinimumHeight(0)
|
||||
widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 设置均等大小
|
||||
if equal_sizes and splitter.count() > 0:
|
||||
sizes = [1] * splitter.count()
|
||||
splitter.setSizes(sizes)
|
||||
splitter.update()
|
||||
|
||||
# 延迟设置确保生效
|
||||
QtCore.QTimer.singleShot(500, lambda: splitter.setSizes(sizes))
|
||||
|
||||
return True
|
||||
|
||||
def force_equal_splitter_sizes(ui_instance, splitter_name="main_splitter"):
|
||||
"""
|
||||
强制设置分割器大小为均等,并确保完全自由调整
|
||||
|
||||
Args:
|
||||
ui_instance: UI实例对象
|
||||
splitter_name (str): 分割器名称
|
||||
"""
|
||||
# 调用通用的分割器设置函数,设置均等大小
|
||||
return setup_splitter(ui_instance, splitter_name, equal_sizes=True)
|
||||
|
||||
def set_splitter_children_minimum_size(ui_instance, splitter_name="main_splitter", recursive=True):
|
||||
"""
|
||||
设置分割器所有子元素的最小宽度和高度为0,允许完全自由调整
|
||||
|
||||
Args:
|
||||
ui_instance: UI实例对象
|
||||
splitter_name (str): 分割器名称
|
||||
recursive (bool): 是否递归设置所有子元素
|
||||
"""
|
||||
# 检查分割器是否存在
|
||||
if not hasattr(ui_instance, 'splitters') or splitter_name not in ui_instance.splitters:
|
||||
return
|
||||
|
||||
# 获取分割器
|
||||
splitter = ui_instance.splitters[splitter_name]
|
||||
|
||||
# 设置分割器属性
|
||||
splitter.setOpaqueResize(True)
|
||||
splitter.setChildrenCollapsible(False)
|
||||
|
||||
# 设置所有子部件的最小尺寸为0
|
||||
for i in range(splitter.count()):
|
||||
widget = splitter.widget(i)
|
||||
if widget and recursive:
|
||||
# 设置最小尺寸为0
|
||||
widget.setMinimumWidth(0)
|
||||
widget.setMinimumHeight(0)
|
||||
widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 递归设置子控件
|
||||
_set_widget_children_minimum_size(widget)
|
||||
|
||||
def _set_widget_children_minimum_size(widget):
|
||||
"""
|
||||
递归设置控件及其所有子控件的最小尺寸为0
|
||||
|
||||
Args:
|
||||
widget: 要设置的控件
|
||||
"""
|
||||
# 递归设置所有子部件
|
||||
for child in widget.findChildren(QtWidgets.QWidget):
|
||||
# 设置每个子控件的最小宽度为0
|
||||
child.setMinimumWidth(0)
|
||||
|
||||
# 对于按钮、标签等控件,不应该设置最小高度为0,否则会导致界面异常
|
||||
if isinstance(child, (QtWidgets.QPushButton, QtWidgets.QToolButton,
|
||||
QtWidgets.QLabel, QtWidgets.QLineEdit,
|
||||
QtWidgets.QComboBox, QtWidgets.QCheckBox,
|
||||
QtWidgets.QRadioButton)):
|
||||
# 这些控件应该保持其默认高度,只设置水平方向的策略为Expanding
|
||||
policy = child.sizePolicy()
|
||||
policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Expanding)
|
||||
child.setSizePolicy(policy)
|
||||
else:
|
||||
# 其他控件可以设置最小高度为0
|
||||
child.setMinimumHeight(0)
|
||||
child.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 特别处理容器控件
|
||||
if isinstance(child, (QtWidgets.QSplitter, QtWidgets.QScrollArea,
|
||||
QtWidgets.QGroupBox, QtWidgets.QFrame,
|
||||
QtWidgets.QTabWidget, QtWidgets.QStackedWidget)) and hasattr(child, 'layout') and child.layout():
|
||||
child.layout().setContentsMargins(0, 0, 0, 0)
|
||||
child.layout().setSpacing(0)
|
||||
|
||||
# 特别处理列表、树和表格控件
|
||||
elif isinstance(child, (QtWidgets.QListWidget, QtWidgets.QTreeWidget,
|
||||
QtWidgets.QTableWidget, QtWidgets.QListView,
|
||||
QtWidgets.QTreeView, QtWidgets.QTableView)):
|
||||
child.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
||||
child.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
||||
|
||||
def set_all_controls_minimum_size(ui_instance):
|
||||
"""
|
||||
设置UI实例中所有控件的最小尺寸为0,确保分割器可以自由移动
|
||||
|
||||
Args:
|
||||
ui_instance: UI实例对象,必须包含controls和buttons字典
|
||||
"""
|
||||
# 设置所有按钮的最小尺寸
|
||||
if hasattr(ui_instance, 'buttons'):
|
||||
for button in ui_instance.buttons.values():
|
||||
_set_control_minimum_size(button)
|
||||
|
||||
# 设置所有控件的最小尺寸
|
||||
if hasattr(ui_instance, 'controls'):
|
||||
for control in ui_instance.controls.values():
|
||||
_set_control_minimum_size(control)
|
||||
|
||||
def _set_control_minimum_size(control):
|
||||
"""
|
||||
设置单个控件的最小尺寸为0
|
||||
|
||||
Args:
|
||||
control: 要设置的控件
|
||||
"""
|
||||
control.setMinimumWidth(0)
|
||||
|
||||
# 对于按钮、标签等控件,不应该设置最小高度为0,否则会导致界面异常
|
||||
if isinstance(control, (QtWidgets.QPushButton, QtWidgets.QToolButton,
|
||||
QtWidgets.QLabel, QtWidgets.QLineEdit,
|
||||
QtWidgets.QComboBox, QtWidgets.QCheckBox,
|
||||
QtWidgets.QRadioButton)):
|
||||
# 这些控件应该保持其默认高度,只设置水平方向的策略为Expanding
|
||||
policy = control.sizePolicy()
|
||||
policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Expanding)
|
||||
control.setSizePolicy(policy)
|
||||
else:
|
||||
# 其他控件可以设置最小高度为0
|
||||
control.setMinimumHeight(0)
|
||||
control.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
# 特别处理列表、树和表格控件
|
||||
if isinstance(control, (QtWidgets.QListWidget, QtWidgets.QTreeWidget,
|
||||
QtWidgets.QTableWidget, QtWidgets.QListView,
|
||||
QtWidgets.QTreeView, QtWidgets.QTableView)):
|
||||
# 确保这些控件可以自由调整大小
|
||||
control.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
||||
control.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
|
Reference in New Issue
Block a user