EG/ui/assembly_disassembly_config.py
2025-12-12 16:16:15 +08:00

944 lines
38 KiB
Python

# -*- coding: utf-8 -*-
"""
拆装交互配置界面
实现模型的分步拆装交互功能配置
"""
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QTabWidget,
QWidget, QLabel, QListWidget, QListWidgetItem,
QPushButton, QComboBox, QSpinBox, QLineEdit,
QTextEdit, QGroupBox, QGridLayout, QCheckBox,
QSplitter, QTreeWidget, QTreeWidgetItem,
QMessageBox, QFileDialog, QScrollArea,
QFrame, QDoubleSpinBox, QSlider, QProgressBar)
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5.QtGui import QIcon, QPixmap, QFont
import os
import json
class AssemblyDisassemblyConfigDialog(QDialog):
"""拆装配置主对话框"""
def __init__(self, parent=None, world=None):
super().__init__(parent)
self.world = world
self.config_data = {
'models': [], # 参与拆装的模型列表
'steps': [], # 拆装步骤配置
'tools': [], # 使用的工具列表
'settings': {} # 全局设置
}
self.setupUI()
self.loadSceneModels()
def setupUI(self):
"""设置界面"""
self.setWindowTitle("拆装交互配置")
self.setModal(False) # 设置为非模态对话框
self.resize(1200, 800)
# 主布局
main_layout = QVBoxLayout(self)
# 创建分割器
splitter = QSplitter(Qt.Horizontal)
main_layout.addWidget(splitter)
# 左侧面板 - 模型和工具选择
left_panel = self.createLeftPanel()
splitter.addWidget(left_panel)
# 右侧面板 - 步骤配置
right_panel = self.createRightPanel()
splitter.addWidget(right_panel)
# 设置分割器比例
splitter.setSizes([400, 800])
# 底部按钮
button_layout = QHBoxLayout()
self.save_button = QPushButton("保存配置")
self.load_button = QPushButton("加载配置")
self.preview_button = QPushButton("预览效果")
self.apply_button = QPushButton("应用配置")
button_layout.addWidget(self.save_button)
button_layout.addWidget(self.load_button)
button_layout.addStretch()
button_layout.addWidget(self.preview_button)
button_layout.addWidget(self.apply_button)
main_layout.addLayout(button_layout)
# 连接信号
self.connectSignals()
def createLeftPanel(self):
"""创建左侧面板"""
left_widget = QWidget()
left_layout = QVBoxLayout(left_widget)
# 场景模型选择区域
models_group = QGroupBox("场景模型")
models_layout = QVBoxLayout(models_group)
# 模型搜索框
search_layout = QHBoxLayout()
search_label = QLabel("搜索:")
self.model_search_edit = QLineEdit()
self.model_search_edit.setPlaceholderText("输入模型名称搜索...")
search_layout.addWidget(search_label)
search_layout.addWidget(self.model_search_edit)
models_layout.addLayout(search_layout)
# 场景模型列表
self.scene_models_list = QTreeWidget()
self.scene_models_list.setHeaderLabel("场景中的模型")
self.scene_models_list.setSelectionMode(QTreeWidget.ExtendedSelection)
models_layout.addWidget(self.scene_models_list)
# 选中模型操作按钮
model_buttons_layout = QHBoxLayout()
self.add_to_config_button = QPushButton("添加到配置")
self.remove_from_config_button = QPushButton("从配置移除")
model_buttons_layout.addWidget(self.add_to_config_button)
model_buttons_layout.addWidget(self.remove_from_config_button)
models_layout.addLayout(model_buttons_layout)
left_layout.addWidget(models_group)
# 已配置模型列表
config_models_group = QGroupBox("已配置模型")
config_models_layout = QVBoxLayout(config_models_group)
self.config_models_list = QListWidget()
config_models_layout.addWidget(self.config_models_list)
left_layout.addWidget(config_models_group)
# 工具配置区域
tools_group = QGroupBox("工具配置")
tools_layout = QVBoxLayout(tools_group)
# 工具添加
tool_add_layout = QHBoxLayout()
self.tool_name_edit = QLineEdit()
self.tool_name_edit.setPlaceholderText("工具名称")
self.add_tool_button = QPushButton("添加工具")
tool_add_layout.addWidget(self.tool_name_edit)
tool_add_layout.addWidget(self.add_tool_button)
tools_layout.addLayout(tool_add_layout)
# 工具列表
self.tools_list = QListWidget()
tools_layout.addWidget(self.tools_list)
# 工具操作按钮
tool_buttons_layout = QHBoxLayout()
self.edit_tool_button = QPushButton("编辑")
self.remove_tool_button = QPushButton("删除")
tool_buttons_layout.addWidget(self.edit_tool_button)
tool_buttons_layout.addWidget(self.remove_tool_button)
tools_layout.addLayout(tool_buttons_layout)
left_layout.addWidget(tools_group)
return left_widget
def createRightPanel(self):
"""创建右侧面板"""
right_widget = QWidget()
right_layout = QVBoxLayout(right_widget)
# 步骤配置标签页
self.tab_widget = QTabWidget()
# 步骤列表标签页
self.steps_tab = self.createStepsTab()
self.tab_widget.addTab(self.steps_tab, "步骤配置")
# 全局设置标签页
self.settings_tab = self.createSettingsTab()
self.tab_widget.addTab(self.settings_tab, "全局设置")
right_layout.addWidget(self.tab_widget)
return right_widget
def createStepsTab(self):
"""创建步骤配置标签页"""
steps_widget = QWidget()
steps_layout = QHBoxLayout(steps_widget)
# 左侧步骤列表
steps_list_layout = QVBoxLayout()
# 步骤列表标题和操作按钮
steps_header_layout = QHBoxLayout()
steps_label = QLabel("拆装步骤")
steps_label.setFont(QFont("", 12, QFont.Bold))
self.add_step_button = QPushButton("添加步骤")
self.remove_step_button = QPushButton("删除步骤")
steps_header_layout.addWidget(steps_label)
steps_header_layout.addStretch()
steps_header_layout.addWidget(self.add_step_button)
steps_header_layout.addWidget(self.remove_step_button)
steps_list_layout.addLayout(steps_header_layout)
# 步骤列表
self.steps_list = QListWidget()
steps_list_layout.addWidget(self.steps_list)
# 步骤顺序调整按钮
step_order_layout = QHBoxLayout()
self.move_step_up_button = QPushButton("上移")
self.move_step_down_button = QPushButton("下移")
step_order_layout.addWidget(self.move_step_up_button)
step_order_layout.addWidget(self.move_step_down_button)
steps_list_layout.addLayout(step_order_layout)
# 右侧步骤详细配置
self.step_config_widget = self.createStepConfigWidget()
# 添加到布局
steps_layout.addLayout(steps_list_layout, 1)
steps_layout.addWidget(self.step_config_widget, 2)
return steps_widget
def createStepConfigWidget(self):
"""创建步骤详细配置部件"""
config_widget = QWidget()
config_layout = QVBoxLayout(config_widget)
# 滚动区域
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
scroll_content = QWidget()
scroll_layout = QVBoxLayout(scroll_content)
# 步骤基本信息
basic_info_group = QGroupBox("基本信息")
basic_info_layout = QGridLayout(basic_info_group)
# 步骤名称
basic_info_layout.addWidget(QLabel("步骤名称:"), 0, 0)
self.step_name_edit = QLineEdit()
basic_info_layout.addWidget(self.step_name_edit, 0, 1)
# 步骤描述
basic_info_layout.addWidget(QLabel("步骤描述:"), 1, 0)
self.step_description_edit = QTextEdit()
self.step_description_edit.setMaximumHeight(80)
basic_info_layout.addWidget(self.step_description_edit, 1, 1)
# 步骤类型
basic_info_layout.addWidget(QLabel("步骤类型:"), 2, 0)
self.step_type_combo = QComboBox()
self.step_type_combo.addItems(["拆卸", "安装"])
basic_info_layout.addWidget(self.step_type_combo, 2, 1)
scroll_layout.addWidget(basic_info_group)
# 目标模型配置
target_model_group = QGroupBox("目标模型")
target_model_layout = QGridLayout(target_model_group)
# 目标模型选择
target_model_layout.addWidget(QLabel("目标模型:"), 0, 0)
self.target_model_combo = QComboBox()
target_model_layout.addWidget(self.target_model_combo, 0, 1)
# 交互方式
target_model_layout.addWidget(QLabel("交互方式:"), 1, 0)
self.interaction_type_combo = QComboBox()
self.interaction_type_combo.addItems(["鼠标拖拽", "点击触发"])
target_model_layout.addWidget(self.interaction_type_combo, 1, 1)
scroll_layout.addWidget(target_model_group)
# 拖拽交互配置
self.drag_config_group = QGroupBox("拖拽交互配置")
drag_config_layout = QGridLayout(self.drag_config_group)
# 目标位置
drag_config_layout.addWidget(QLabel("目标位置 X:"), 0, 0)
self.target_pos_x_spin = QDoubleSpinBox()
self.target_pos_x_spin.setRange(-1000, 1000)
self.target_pos_x_spin.setSingleStep(0.1)
drag_config_layout.addWidget(self.target_pos_x_spin, 0, 1)
drag_config_layout.addWidget(QLabel("目标位置 Y:"), 1, 0)
self.target_pos_y_spin = QDoubleSpinBox()
self.target_pos_y_spin.setRange(-1000, 1000)
self.target_pos_y_spin.setSingleStep(0.1)
drag_config_layout.addWidget(self.target_pos_y_spin, 1, 1)
drag_config_layout.addWidget(QLabel("目标位置 Z:"), 2, 0)
self.target_pos_z_spin = QDoubleSpinBox()
self.target_pos_z_spin.setRange(-1000, 1000)
self.target_pos_z_spin.setSingleStep(0.1)
drag_config_layout.addWidget(self.target_pos_z_spin, 2, 1)
# 拖拽约束
self.constrain_x_check = QCheckBox("约束X轴")
self.constrain_y_check = QCheckBox("约束Y轴")
self.constrain_z_check = QCheckBox("约束Z轴")
constraint_layout = QHBoxLayout()
constraint_layout.addWidget(self.constrain_x_check)
constraint_layout.addWidget(self.constrain_y_check)
constraint_layout.addWidget(self.constrain_z_check)
drag_config_layout.addWidget(QLabel("拖拽约束:"), 3, 0)
drag_config_layout.addLayout(constraint_layout, 3, 1)
scroll_layout.addWidget(self.drag_config_group)
# 点击触发配置
self.click_config_group = QGroupBox("点击触发配置")
click_config_layout = QGridLayout(self.click_config_group)
# 位移距离
click_config_layout.addWidget(QLabel("位移距离 X:"), 0, 0)
self.move_distance_x_spin = QDoubleSpinBox()
self.move_distance_x_spin.setRange(-100, 100)
self.move_distance_x_spin.setSingleStep(0.1)
click_config_layout.addWidget(self.move_distance_x_spin, 0, 1)
click_config_layout.addWidget(QLabel("位移距离 Y:"), 1, 0)
self.move_distance_y_spin = QDoubleSpinBox()
self.move_distance_y_spin.setRange(-100, 100)
self.move_distance_y_spin.setSingleStep(0.1)
click_config_layout.addWidget(self.move_distance_y_spin, 1, 1)
click_config_layout.addWidget(QLabel("位移距离 Z:"), 2, 0)
self.move_distance_z_spin = QDoubleSpinBox()
self.move_distance_z_spin.setRange(-100, 100)
self.move_distance_z_spin.setSingleStep(0.1)
click_config_layout.addWidget(self.move_distance_z_spin, 2, 1)
# 位移时间
click_config_layout.addWidget(QLabel("位移时间(秒):"), 3, 0)
self.move_duration_spin = QDoubleSpinBox()
self.move_duration_spin.setRange(0.1, 10.0)
self.move_duration_spin.setSingleStep(0.1)
self.move_duration_spin.setValue(1.0)
click_config_layout.addWidget(self.move_duration_spin, 3, 1)
# 完成后隐藏
self.hide_after_move_check = QCheckBox("位移完成后隐藏模型")
click_config_layout.addWidget(self.hide_after_move_check, 4, 0, 1, 2)
scroll_layout.addWidget(self.click_config_group)
# 提示音频配置
audio_config_group = QGroupBox("步骤提示")
audio_config_layout = QGridLayout(audio_config_group)
# 提示音频文件
audio_config_layout.addWidget(QLabel("提示音频:"), 0, 0)
audio_file_layout = QHBoxLayout()
self.audio_file_edit = QLineEdit()
self.browse_audio_button = QPushButton("浏览...")
audio_file_layout.addWidget(self.audio_file_edit)
audio_file_layout.addWidget(self.browse_audio_button)
audio_config_layout.addLayout(audio_file_layout, 0, 1)
# 提示文字
audio_config_layout.addWidget(QLabel("提示文字:"), 1, 0)
self.hint_text_edit = QTextEdit()
self.hint_text_edit.setMaximumHeight(60)
audio_config_layout.addWidget(self.hint_text_edit, 1, 1)
scroll_layout.addWidget(audio_config_group)
# 使用工具配置
tool_config_group = QGroupBox("使用工具")
tool_config_layout = QGridLayout(tool_config_group)
tool_config_layout.addWidget(QLabel("所需工具:"), 0, 0)
self.required_tool_combo = QComboBox()
self.required_tool_combo.addItem("")
tool_config_layout.addWidget(self.required_tool_combo, 0, 1)
scroll_layout.addWidget(tool_config_group)
# 设置滚动区域
scroll_area.setWidget(scroll_content)
config_layout.addWidget(scroll_area)
# 默认隐藏点击配置
self.click_config_group.setVisible(False)
return config_widget
def createSettingsTab(self):
"""创建全局设置标签页"""
settings_widget = QWidget()
settings_layout = QVBoxLayout(settings_widget)
# 全局设置组
global_settings_group = QGroupBox("全局设置")
global_settings_layout = QGridLayout(global_settings_group)
# 自动播放提示音
self.auto_play_audio_check = QCheckBox("自动播放步骤提示音")
self.auto_play_audio_check.setChecked(True)
global_settings_layout.addWidget(self.auto_play_audio_check, 0, 0, 1, 2)
# 显示步骤提示文字
self.show_hint_text_check = QCheckBox("显示步骤提示文字")
self.show_hint_text_check.setChecked(True)
global_settings_layout.addWidget(self.show_hint_text_check, 1, 0, 1, 2)
# 步骤完成确认
self.require_confirmation_check = QCheckBox("步骤完成需要确认")
global_settings_layout.addWidget(self.require_confirmation_check, 2, 0, 1, 2)
# 拖拽灵敏度
global_settings_layout.addWidget(QLabel("拖拽灵敏度:"), 3, 0)
self.drag_sensitivity_slider = QSlider(Qt.Horizontal)
self.drag_sensitivity_slider.setRange(1, 10)
self.drag_sensitivity_slider.setValue(5)
global_settings_layout.addWidget(self.drag_sensitivity_slider, 3, 1)
# 动画速度
global_settings_layout.addWidget(QLabel("动画速度:"), 4, 0)
self.animation_speed_slider = QSlider(Qt.Horizontal)
self.animation_speed_slider.setRange(1, 10)
self.animation_speed_slider.setValue(5)
global_settings_layout.addWidget(self.animation_speed_slider, 4, 1)
settings_layout.addWidget(global_settings_group)
# 预设配置组
presets_group = QGroupBox("预设配置")
presets_layout = QVBoxLayout(presets_group)
# 预设列表
self.presets_list = QListWidget()
presets_layout.addWidget(self.presets_list)
# 预设操作按钮
preset_buttons_layout = QHBoxLayout()
self.save_preset_button = QPushButton("保存为预设")
self.load_preset_button = QPushButton("加载预设")
self.delete_preset_button = QPushButton("删除预设")
preset_buttons_layout.addWidget(self.save_preset_button)
preset_buttons_layout.addWidget(self.load_preset_button)
preset_buttons_layout.addWidget(self.delete_preset_button)
presets_layout.addLayout(preset_buttons_layout)
settings_layout.addWidget(presets_group)
# 添加弹性空间
settings_layout.addStretch()
return settings_widget
def connectSignals(self):
"""连接信号槽"""
# 模型搜索
self.model_search_edit.textChanged.connect(self.filterSceneModels)
# 模型操作
self.add_to_config_button.clicked.connect(self.addModelsToConfig)
self.remove_from_config_button.clicked.connect(self.removeModelsFromConfig)
# 工具操作
self.add_tool_button.clicked.connect(self.addTool)
self.edit_tool_button.clicked.connect(self.editTool)
self.remove_tool_button.clicked.connect(self.removeTool)
# 步骤操作
self.add_step_button.clicked.connect(self.addStep)
self.remove_step_button.clicked.connect(self.removeStep)
self.move_step_up_button.clicked.connect(self.moveStepUp)
self.move_step_down_button.clicked.connect(self.moveStepDown)
self.steps_list.itemSelectionChanged.connect(self.onStepSelectionChanged)
# 步骤配置变化
self.interaction_type_combo.currentTextChanged.connect(self.onInteractionTypeChanged)
self.browse_audio_button.clicked.connect(self.browseAudioFile)
# 步骤配置实时更新
self.step_name_edit.textChanged.connect(self.updateCurrentStep)
self.step_description_edit.textChanged.connect(self.updateCurrentStep)
self.step_type_combo.currentTextChanged.connect(self.updateCurrentStep)
self.target_model_combo.currentTextChanged.connect(self.updateCurrentStep)
# 按钮操作
self.save_button.clicked.connect(self.saveConfiguration)
self.load_button.clicked.connect(self.loadConfiguration)
self.preview_button.clicked.connect(self.previewConfiguration)
self.apply_button.clicked.connect(self.applyConfiguration)
def loadSceneModels(self):
"""加载场景中的模型"""
if not self.world:
return
# 清空现有列表
self.scene_models_list.clear()
# 遍历场景中的所有节点
self._addNodeToTree(self.world.render, self.scene_models_list)
# 展开根节点
self.scene_models_list.expandAll()
def _addNodeToTree(self, node, parent_item):
"""递归添加节点到树形控件"""
if node.getName() in ['render', 'camera', 'aspect2d', 'pixel2d']:
# 跳过系统节点
for child in node.getChildren():
self._addNodeToTree(child, parent_item)
return
# 创建树形项
if isinstance(parent_item, QTreeWidget):
item = QTreeWidgetItem(parent_item)
else:
item = QTreeWidgetItem(parent_item)
item.setText(0, node.getName())
item.setData(0, Qt.UserRole, node)
# 添加子节点
for child in node.getChildren():
self._addNodeToTree(child, item)
def filterSceneModels(self, text):
"""过滤场景模型列表"""
# 简单的文本过滤实现
def filterItems(item):
item_text = item.text(0).lower()
text_lower = text.lower()
# 检查当前项是否匹配
matches = text_lower in item_text
# 检查子项
child_matches = False
for i in range(item.childCount()):
child_item = item.child(i)
if filterItems(child_item):
child_matches = True
# 显示/隐藏项
item.setHidden(not (matches or child_matches))
return matches or child_matches
# 从根项开始过滤
for i in range(self.scene_models_list.topLevelItemCount()):
filterItems(self.scene_models_list.topLevelItem(i))
def addModelsToConfig(self):
"""添加选中的模型到配置"""
selected_items = self.scene_models_list.selectedItems()
for item in selected_items:
node = item.data(0, Qt.UserRole)
if node:
model_name = node.getName()
# 检查是否已经存在
existing_items = self.config_models_list.findItems(model_name, Qt.MatchExactly)
if not existing_items:
# 添加到配置模型列表
list_item = QListWidgetItem(model_name)
list_item.setData(Qt.UserRole, node)
self.config_models_list.addItem(list_item)
# 添加到配置数据
self.config_data['models'].append({
'name': model_name,
'node': node,
'original_pos': node.getPos(),
'original_hpr': node.getHpr()
})
# 更新目标模型下拉框
self.target_model_combo.addItem(model_name)
def removeModelsFromConfig(self):
"""从配置中移除选中的模型"""
selected_items = self.config_models_list.selectedItems()
for item in selected_items:
model_name = item.text()
# 从列表中移除
row = self.config_models_list.row(item)
self.config_models_list.takeItem(row)
# 从配置数据中移除
self.config_data['models'] = [
model for model in self.config_data['models']
if model['name'] != model_name
]
# 从目标模型下拉框中移除
index = self.target_model_combo.findText(model_name)
if index >= 0:
self.target_model_combo.removeItem(index)
def addTool(self):
"""添加工具"""
tool_name = self.tool_name_edit.text().strip()
if not tool_name:
QMessageBox.warning(self, "警告", "请输入工具名称")
return
# 检查是否已存在
existing_items = self.tools_list.findItems(tool_name, Qt.MatchExactly)
if existing_items:
QMessageBox.warning(self, "警告", "工具已存在")
return
# 添加到工具列表
self.tools_list.addItem(tool_name)
self.required_tool_combo.addItem(tool_name)
# 添加到配置数据
self.config_data['tools'].append({
'name': tool_name,
'description': '',
'icon': ''
})
# 清空输入框
self.tool_name_edit.clear()
def editTool(self):
"""编辑工具"""
current_item = self.tools_list.currentItem()
if not current_item:
QMessageBox.warning(self, "警告", "请选择要编辑的工具")
return
# 这里可以添加工具编辑对话框
QMessageBox.information(self, "提示", "工具编辑功能待实现")
def removeTool(self):
"""删除工具"""
current_item = self.tools_list.currentItem()
if not current_item:
QMessageBox.warning(self, "警告", "请选择要删除的工具")
return
tool_name = current_item.text()
# 从列表中移除
row = self.tools_list.row(current_item)
self.tools_list.takeItem(row)
# 从下拉框中移除
index = self.required_tool_combo.findText(tool_name)
if index >= 0:
self.required_tool_combo.removeItem(index)
# 从配置数据中移除
self.config_data['tools'] = [
tool for tool in self.config_data['tools']
if tool['name'] != tool_name
]
def addStep(self):
"""添加步骤"""
step_count = len(self.config_data['steps']) + 1
step_name = f"步骤 {step_count}"
# 创建新步骤数据
step_data = {
'name': step_name,
'description': '',
'type': '拆卸',
'target_model': '',
'interaction_type': '鼠标拖拽',
'target_position': [0, 0, 0],
'constraints': {'x': False, 'y': False, 'z': False},
'move_distance': [0, 0, 0],
'move_duration': 1.0,
'hide_after_move': False,
'audio_file': '',
'hint_text': '',
'required_tool': ''
}
# 添加到配置数据
self.config_data['steps'].append(step_data)
# 添加到步骤列表
list_item = QListWidgetItem(step_name)
list_item.setData(Qt.UserRole, step_data)
self.steps_list.addItem(list_item)
# 选中新添加的步骤
self.steps_list.setCurrentItem(list_item)
def removeStep(self):
"""删除步骤"""
current_item = self.steps_list.currentItem()
if not current_item:
QMessageBox.warning(self, "警告", "请选择要删除的步骤")
return
# 从列表中移除
row = self.steps_list.row(current_item)
self.steps_list.takeItem(row)
# 从配置数据中移除
self.config_data['steps'].pop(row)
# 重新编号步骤
self.renumberSteps()
def moveStepUp(self):
"""上移步骤"""
current_row = self.steps_list.currentRow()
if current_row <= 0:
return
# 交换数据
self.config_data['steps'][current_row], self.config_data['steps'][current_row - 1] = \
self.config_data['steps'][current_row - 1], self.config_data['steps'][current_row]
# 交换列表项
current_item = self.steps_list.takeItem(current_row)
self.steps_list.insertItem(current_row - 1, current_item)
self.steps_list.setCurrentRow(current_row - 1)
# 重新编号
self.renumberSteps()
def moveStepDown(self):
"""下移步骤"""
current_row = self.steps_list.currentRow()
if current_row >= self.steps_list.count() - 1:
return
# 交换数据
self.config_data['steps'][current_row], self.config_data['steps'][current_row + 1] = \
self.config_data['steps'][current_row + 1], self.config_data['steps'][current_row]
# 交换列表项
current_item = self.steps_list.takeItem(current_row)
self.steps_list.insertItem(current_row + 1, current_item)
self.steps_list.setCurrentRow(current_row + 1)
# 重新编号
self.renumberSteps()
def renumberSteps(self):
"""重新编号步骤"""
for i in range(self.steps_list.count()):
item = self.steps_list.item(i)
step_data = item.data(Qt.UserRole)
new_name = f"步骤 {i + 1}"
step_data['name'] = new_name
item.setText(new_name)
def onStepSelectionChanged(self):
"""步骤选择改变"""
current_item = self.steps_list.currentItem()
if not current_item:
return
step_data = current_item.data(Qt.UserRole)
if not step_data:
return
# 更新步骤配置界面
self.loadStepConfiguration(step_data)
def loadStepConfiguration(self, step_data):
"""加载步骤配置到界面"""
# 基本信息
self.step_name_edit.setText(step_data.get('name', ''))
self.step_description_edit.setPlainText(step_data.get('description', ''))
self.step_type_combo.setCurrentText(step_data.get('type', '拆卸'))
# 目标模型
target_model = step_data.get('target_model', '')
index = self.target_model_combo.findText(target_model)
if index >= 0:
self.target_model_combo.setCurrentIndex(index)
# 交互方式
interaction_type = step_data.get('interaction_type', '鼠标拖拽')
self.interaction_type_combo.setCurrentText(interaction_type)
self.onInteractionTypeChanged(interaction_type)
# 拖拽配置
target_pos = step_data.get('target_position', [0, 0, 0])
self.target_pos_x_spin.setValue(target_pos[0])
self.target_pos_y_spin.setValue(target_pos[1])
self.target_pos_z_spin.setValue(target_pos[2])
constraints = step_data.get('constraints', {'x': False, 'y': False, 'z': False})
self.constrain_x_check.setChecked(constraints.get('x', False))
self.constrain_y_check.setChecked(constraints.get('y', False))
self.constrain_z_check.setChecked(constraints.get('z', False))
# 点击触发配置
move_distance = step_data.get('move_distance', [0, 0, 0])
self.move_distance_x_spin.setValue(move_distance[0])
self.move_distance_y_spin.setValue(move_distance[1])
self.move_distance_z_spin.setValue(move_distance[2])
self.move_duration_spin.setValue(step_data.get('move_duration', 1.0))
self.hide_after_move_check.setChecked(step_data.get('hide_after_move', False))
# 提示配置
self.audio_file_edit.setText(step_data.get('audio_file', ''))
self.hint_text_edit.setPlainText(step_data.get('hint_text', ''))
# 工具配置
required_tool = step_data.get('required_tool', '')
index = self.required_tool_combo.findText(required_tool)
if index >= 0:
self.required_tool_combo.setCurrentIndex(index)
def onInteractionTypeChanged(self, interaction_type):
"""交互方式改变"""
if interaction_type == "鼠标拖拽":
self.drag_config_group.setVisible(True)
self.click_config_group.setVisible(False)
else: # 点击触发
self.drag_config_group.setVisible(False)
self.click_config_group.setVisible(True)
def updateCurrentStep(self):
"""更新当前步骤数据"""
current_item = self.steps_list.currentItem()
if not current_item:
return
step_data = current_item.data(Qt.UserRole)
if not step_data:
return
# 更新步骤数据
step_data['name'] = self.step_name_edit.text()
step_data['description'] = self.step_description_edit.toPlainText()
step_data['type'] = self.step_type_combo.currentText()
step_data['target_model'] = self.target_model_combo.currentText()
step_data['interaction_type'] = self.interaction_type_combo.currentText()
# 更新列表项显示
current_item.setText(step_data['name'])
def browseAudioFile(self):
"""浏览音频文件"""
file_path, _ = QFileDialog.getOpenFileName(
self, "选择音频文件", "",
"音频文件 (*.wav *.mp3 *.ogg *.flac);;所有文件 (*)"
)
if file_path:
self.audio_file_edit.setText(file_path)
def saveConfiguration(self):
"""保存配置"""
file_path, _ = QFileDialog.getSaveFileName(
self, "保存拆装配置", "",
"JSON文件 (*.json);;所有文件 (*)"
)
if file_path:
try:
# 准备保存的数据(去除不能序列化的对象)
save_data = {
'models': [
{
'name': model['name'],
'original_pos': list(model['original_pos']),
'original_hpr': list(model['original_hpr'])
} for model in self.config_data['models']
],
'steps': self.config_data['steps'],
'tools': self.config_data['tools'],
'settings': {
'auto_play_audio': self.auto_play_audio_check.isChecked(),
'show_hint_text': self.show_hint_text_check.isChecked(),
'require_confirmation': self.require_confirmation_check.isChecked(),
'drag_sensitivity': self.drag_sensitivity_slider.value(),
'animation_speed': self.animation_speed_slider.value()
}
}
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(save_data, f, ensure_ascii=False, indent=2)
QMessageBox.information(self, "成功", "配置保存成功")
except Exception as e:
QMessageBox.critical(self, "错误", f"保存配置失败: {str(e)}")
def loadConfiguration(self):
"""加载配置"""
file_path, _ = QFileDialog.getOpenFileName(
self, "加载拆装配置", "",
"JSON文件 (*.json);;所有文件 (*)"
)
if file_path:
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
# 加载配置数据
self.loadConfigurationData(data)
QMessageBox.information(self, "成功", "配置加载成功")
except Exception as e:
QMessageBox.critical(self, "错误", f"加载配置失败: {str(e)}")
def loadConfigurationData(self, data):
"""加载配置数据到界面"""
# 清空现有配置
self.config_models_list.clear()
self.target_model_combo.clear()
self.steps_list.clear()
# 加载模型配置
# 注意:这里需要重新匹配场景中的模型节点
# 加载步骤配置
self.config_data['steps'] = data.get('steps', [])
for step_data in self.config_data['steps']:
list_item = QListWidgetItem(step_data['name'])
list_item.setData(Qt.UserRole, step_data)
self.steps_list.addItem(list_item)
# 加载工具配置
self.tools_list.clear()
self.required_tool_combo.clear()
self.required_tool_combo.addItem("")
self.config_data['tools'] = data.get('tools', [])
for tool in self.config_data['tools']:
self.tools_list.addItem(tool['name'])
self.required_tool_combo.addItem(tool['name'])
# 加载全局设置
settings = data.get('settings', {})
self.auto_play_audio_check.setChecked(settings.get('auto_play_audio', True))
self.show_hint_text_check.setChecked(settings.get('show_hint_text', True))
self.require_confirmation_check.setChecked(settings.get('require_confirmation', False))
self.drag_sensitivity_slider.setValue(settings.get('drag_sensitivity', 5))
self.animation_speed_slider.setValue(settings.get('animation_speed', 5))
def previewConfiguration(self):
"""预览配置效果"""
QMessageBox.information(self, "提示", "预览功能待实现")
def applyConfiguration(self):
"""应用配置"""
QMessageBox.information(self, "提示", "应用配置功能待实现")