Commit 872a1442 by Yuhaibo

1

parent dde5f108
...@@ -1311,30 +1311,15 @@ class MainWindow( ...@@ -1311,30 +1311,15 @@ class MainWindow(
def showVideoPage(self): def showVideoPage(self):
"""显示实时检测管理页面""" """显示实时检测管理页面"""
print(f"\n{'='*60}")
print(f"[showVideoPage] ========== 切换到实时检测管理页面 ==========")
print(f"{'='*60}")
self.stackedWidget.setCurrentWidget(self.videoPage) self.stackedWidget.setCurrentWidget(self.videoPage)
# 🔥 确保切换到默认布局(videoLayoutStack 索引0) # 🔥 确保切换到默认布局(videoLayoutStack 索引0)
if hasattr(self, 'videoLayoutStack'): if hasattr(self, 'videoLayoutStack'):
print(f"[showVideoPage] videoLayoutStack 当前索引: {self.videoLayoutStack.currentIndex()}")
print(f"[showVideoPage] 切换 videoLayoutStack 到索引 0(默认布局)...")
self.videoLayoutStack.setCurrentIndex(0) self.videoLayoutStack.setCurrentIndex(0)
self._video_layout_mode = 0 self._video_layout_mode = 0
print(f"[showVideoPage] 切换后索引: {self.videoLayoutStack.currentIndex()}")
# 显示当前控件信息
current_widget = self.videoLayoutStack.currentWidget()
print(f"[showVideoPage] 当前控件: {current_widget}")
if current_widget:
print(f" - 可见性: {current_widget.isVisible()}")
print(f" - 大小: {current_widget.size()}")
# 🔥 确保所有通道面板在默认布局中可见 # 🔥 确保所有通道面板在默认布局中可见
if hasattr(self, 'channelPanels'): if hasattr(self, 'channelPanels'):
print(f"[showVideoPage] 确保所有通道面板可见...")
for i, channel_panel in enumerate(self.channelPanels): for i, channel_panel in enumerate(self.channelPanels):
if hasattr(self, 'default_channel_positions') and i < len(self.default_channel_positions): if hasattr(self, 'default_channel_positions') and i < len(self.default_channel_positions):
# 确保通道面板在正确的父容器中 # 确保通道面板在正确的父容器中
...@@ -1345,10 +1330,8 @@ class MainWindow( ...@@ -1345,10 +1330,8 @@ class MainWindow(
# 显示通道面板 # 显示通道面板
channel_panel.show() channel_panel.show()
print(f" - 通道{i+1}: 可见性={channel_panel.isVisible()}, 父容器={channel_panel.parent()}")
self.statusBar().showMessage(self.tr("当前页面: 实时检测管理")) self.statusBar().showMessage(self.tr("当前页面: 实时检测管理"))
print(f"[showVideoPage] ========== 切换完成 ==========\n")
def showModelPage(self): def showModelPage(self):
"""显示模型管理页面""" """显示模型管理页面"""
......
...@@ -112,10 +112,14 @@ ...@@ -112,10 +112,14 @@
13.**widgets/videopage/missionpanel.py** - 删除约20处print语句 13.**widgets/videopage/missionpanel.py** - 删除约20处print语句
14.**widgets/videopage/general_set.py** - 删除约30处print语句 14.**widgets/videopage/general_set.py** - 删除约30处print语句
15.**widgets/videopage/curvepanel.py** - 删除4处print语句 15.**widgets/videopage/curvepanel.py** - 删除4处print语句
16.**widgets/videopage/historyvideopanel.py** - 删除约15处print语句 16.**widgets/videopage/historyvideopanel.py** - 删除约16处print语句和3处DEBUG注释
### 部分清理 ### 部分清理
17. 🔄 **handlers/videopage/missionpanel_handler.py** - 已清理前330行,删除约20处print语句(文件共2050行,需继续清理) 17. 🔄 **handlers/videopage/missionpanel_handler.py** - 已清理前880行,删除约50处print语句(文件共2004行,需继续清理)
### 新增完成清理
18.**widgets/datasetpage/crop_preview_panel.py** - 删除约47处print语句和2处DEBUG注释
19.**widgets/datasetpage/datacollection_panel.py** - 删除约20处print语句和1处DEBUG注释
## 清理进度说明 ## 清理进度说明
...@@ -146,13 +150,13 @@ ...@@ -146,13 +150,13 @@
- ⏳ widgets/datasetpage/test_*.py - ⏳ widgets/datasetpage/test_*.py
### 剩余工作量估算 ### 剩余工作量估算
- 已清理: 约283处调试语句 (16个文件完全清理 + 1个文件部分清理) - 已清理: 约384处调试语句 (18个文件完全清理 + 1个文件部分清理)
- 剩余: 约3158处调试语句 - 剩余: 约3057处调试语句
- 预计需要: 继续手动清理约47个文件 - 预计需要: 继续手动清理约45个文件
### 本次清理总结 (2025-11-26 20:30) ### 本次清理总结 (2025-11-26 20:46)
- 完成文件数: 16个完全清理 + 1个部分清理 - 完成文件数: 18个完全清理 + 1个部分清理
- 删除调试语句: 约283处 - 删除调试语句: 约384处(包含print语句和DEBUG注释)
- 主要清理内容: - 主要清理内容:
- 核心应用入口和窗口管理 (app.py) - 核心应用入口和窗口管理 (app.py)
- 视图布局切换管理 (view_handler.py) - 视图布局切换管理 (view_handler.py)
...@@ -161,8 +165,9 @@ ...@@ -161,8 +165,9 @@
- 曲线面板Handler (curvepanel_handler.py) - 曲线面板Handler (curvepanel_handler.py)
- 完整线程管理系统 (thread_manager.py, curve_thread.py, global_detection_thread.py, storage_thread.py, display_thread.py) - 完整线程管理系统 (thread_manager.py, curve_thread.py, global_detection_thread.py, storage_thread.py, display_thread.py)
- 完整UI组件系统 (missionpanel.py, general_set.py, curvepanel.py, historyvideopanel.py) - 完整UI组件系统 (missionpanel.py, general_set.py, curvepanel.py, historyvideopanel.py)
- 数据集页面组件 (crop_preview_panel.py, datacollection_panel.py)
- 部分任务面板Handler (missionpanel_handler.py) - 部分任务面板Handler (missionpanel_handler.py)
--- ---
*最后更新: 2025-11-26 20:30* *最后更新: 2025-11-26 20:46*
...@@ -337,21 +337,17 @@ class MissionPanelHandler: ...@@ -337,21 +337,17 @@ class MissionPanelHandler:
# 读取YAML文件 # 读取YAML文件
if not os.path.exists(file_path): if not os.path.exists(file_path):
print(f"任务配置文件不存在: {filename}")
return None return None
with open(file_path, 'r', encoding='utf-8') as f: with open(file_path, 'r', encoding='utf-8') as f:
config_data = yaml.safe_load(f) config_data = yaml.safe_load(f)
if not config_data: if not config_data:
print(f"任务配置文件为空: {filename}")
return None return None
print(f"已加载任务配置: {filename}")
return config_data return config_data
except Exception as e: except Exception as e:
print(f"加载任务配置失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return None return None
...@@ -375,7 +371,6 @@ class MissionPanelHandler: ...@@ -375,7 +371,6 @@ class MissionPanelHandler:
config_file = os.path.join(project_root, 'database', 'config', 'channel_config.yaml') config_file = os.path.join(project_root, 'database', 'config', 'channel_config.yaml')
if not os.path.exists(config_file): if not os.path.exists(config_file):
print(f"配置文件不存在: {config_file}")
return False return False
# 读取现有配置 # 读取现有配置
...@@ -407,14 +402,9 @@ class MissionPanelHandler: ...@@ -407,14 +402,9 @@ class MissionPanelHandler:
with open(config_file, 'w', encoding='utf-8') as f: with open(config_file, 'w', encoding='utf-8') as f:
yaml.dump(channel_config, f, allow_unicode=True, default_flow_style=False, sort_keys=False) yaml.dump(channel_config, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
print(f"已同步任务信息到配置文件 {channel_id}:")
print(f" - task_id: {task_id}")
print(f" - task_name: {task_name}")
print(f" - save_liquid_data_path: {save_liquid_data_path}")
return True return True
except Exception as e: except Exception as e:
print(f"同步任务配置到文件失败 ({channel_id}): {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return False return False
...@@ -437,27 +427,19 @@ class MissionPanelHandler: ...@@ -437,27 +427,19 @@ class MissionPanelHandler:
# 🔥 第一步:同步到 channel_config.yaml(独立业务,无论通道是否打开都执行) # 🔥 第一步:同步到 channel_config.yaml(独立业务,无论通道是否打开都执行)
sync_success = self._syncTaskToConfigFile(channel_id, task_id, task_name, save_liquid_data_path) sync_success = self._syncTaskToConfigFile(channel_id, task_id, task_name, save_liquid_data_path)
if sync_success: pass
print(f"✅ 已同步任务到配置文件 {channel_id}: [{task_id}] {task_name}")
else:
print(f"⚠️ 同步任务到配置文件失败 {channel_id}")
# 🔥 第二步:更新通道面板UI(可选操作,仅在通道已打开时执行) # 🔥 第二步:更新通道面板UI(可选操作,仅在通道已打开时执行)
# 检查是否有通道面板映射(从ChannelPanelHandler获取) # 检查是否有通道面板映射(从ChannelPanelHandler获取)
if not hasattr(self, '_channel_panels_map'): if not hasattr(self, '_channel_panels_map'):
print(f"⚠️ _channel_panels_map 不存在,跳过UI更新")
return return
# 获取对应的通道面板 # 获取对应的通道面板
channel_panel = self._channel_panels_map.get(channel_id) channel_panel = self._channel_panels_map.get(channel_id)
if not channel_panel: if not channel_panel:
print(f"ℹ️ 通道 {channel_id} 未打开,仅同步到配置文件")
return return
# 通道面板存在,更新UI显示
print(f"🔄 通道 {channel_id} 已打开,同时更新UI显示")
# 更新通道的channel_data,添加任务信息 # 更新通道的channel_data,添加任务信息
channel_data = { channel_data = {
'task_id': task_id, 'task_id': task_id,
...@@ -468,8 +450,6 @@ class MissionPanelHandler: ...@@ -468,8 +450,6 @@ class MissionPanelHandler:
# 调用通道面板的updateChannel方法(更新内部存储) # 调用通道面板的updateChannel方法(更新内部存储)
if hasattr(channel_panel, 'updateChannel'): if hasattr(channel_panel, 'updateChannel'):
success = channel_panel.updateChannel(channel_id, channel_data) success = channel_panel.updateChannel(channel_id, channel_data)
if success:
print(f"✅ 已同步任务数据到通道面板内存 {channel_id}")
# 🔥 多任务支持:不再从全局 current_mission 读取,而是使用传入的任务信息 # 🔥 多任务支持:不再从全局 current_mission 读取,而是使用传入的任务信息
# 更新UI显示(从 save_liquid_data_path 提取文件夹名称) # 更新UI显示(从 save_liquid_data_path 提取文件夹名称)
...@@ -485,18 +465,14 @@ class MissionPanelHandler: ...@@ -485,18 +465,14 @@ class MissionPanelHandler:
# 如果文件夹名称为空或为"None",使用任务名称 # 如果文件夹名称为空或为"None",使用任务名称
if folder_name and folder_name.lower() != "none": if folder_name and folder_name.lower() != "none":
channel_panel.setTaskInfo(folder_name) channel_panel.setTaskInfo(folder_name)
print(f"✅ [多任务] 已更新通道面板UI显示 {channel_id}: {folder_name}")
else: else:
# 使用任务名称作为备选 # 使用任务名称作为备选
channel_panel.setTaskInfo(f"{task_id}_{task_name}") channel_panel.setTaskInfo(f"{task_id}_{task_name}")
print(f"✅ [多任务] 已更新通道面板UI显示 {channel_id}: {task_id}_{task_name}")
else: else:
# 没有路径,使用任务名称 # 没有路径,使用任务名称
channel_panel.setTaskInfo(f"{task_id}_{task_name}") channel_panel.setTaskInfo(f"{task_id}_{task_name}")
print(f"✅ [多任务] 已更新通道面板UI显示 {channel_id}: {task_id}_{task_name}")
except Exception as e: except Exception as e:
print(f"❌ 更新通道任务信息失败 ({channel_id}): {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -517,12 +493,10 @@ class MissionPanelHandler: ...@@ -517,12 +493,10 @@ class MissionPanelHandler:
# 确保目录存在 # 确保目录存在
if not os.path.exists(mission_dir): if not os.path.exists(mission_dir):
os.makedirs(mission_dir) os.makedirs(mission_dir)
print(f" 创建任务配置目录: {mission_dir}")
return mission_dir return mission_dir
except Exception as e: except Exception as e:
print(f" 获取任务配置路径失败: {e}")
return None return None
def _saveMissionConfig(self, task_info): def _saveMissionConfig(self, task_info):
...@@ -576,11 +550,9 @@ class MissionPanelHandler: ...@@ -576,11 +550,9 @@ class MissionPanelHandler:
with open(file_path, 'w', encoding='utf-8') as f: with open(file_path, 'w', encoding='utf-8') as f:
yaml.dump(config_data, f, allow_unicode=True, default_flow_style=False, sort_keys=False) yaml.dump(config_data, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
print(f" 任务配置已保存: {file_path}")
return True return True
except Exception as e: except Exception as e:
print(f" 保存任务配置失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return False return False
...@@ -621,12 +593,10 @@ class MissionPanelHandler: ...@@ -621,12 +593,10 @@ class MissionPanelHandler:
# 确保目录存在 # 确保目录存在
if not os.path.exists(mission_result_dir): if not os.path.exists(mission_result_dir):
os.makedirs(mission_result_dir) os.makedirs(mission_result_dir)
print(f"📁 创建结果目录: {mission_result_dir}")
return mission_result_dir return mission_result_dir
except Exception as e: except Exception as e:
print(f"❌ 获取结果路径失败: {e}")
return None return None
def _getYamlFilePath(self, task_info): def _getYamlFilePath(self, task_info):
...@@ -672,7 +642,6 @@ class MissionPanelHandler: ...@@ -672,7 +642,6 @@ class MissionPanelHandler:
# 获取结果目录路径 # 获取结果目录路径
mission_result_dir = self._getmission_resultPath() mission_result_dir = self._getmission_resultPath()
if not mission_result_dir: if not mission_result_dir:
print("❌ 无法获取结果目录路径")
return None return None
# 构建任务文件夹名称:任务编号_任务名称 # 构建任务文件夹名称:任务编号_任务名称
...@@ -680,7 +649,6 @@ class MissionPanelHandler: ...@@ -680,7 +649,6 @@ class MissionPanelHandler:
task_name = task_info.get('task_name', '') task_name = task_info.get('task_name', '')
if not task_id or not task_name: if not task_id or not task_name:
print("❌ 任务编号或任务名称为空")
return None return None
# 清理文件夹名称中的非法字符 # 清理文件夹名称中的非法字符
...@@ -693,15 +661,11 @@ class MissionPanelHandler: ...@@ -693,15 +661,11 @@ class MissionPanelHandler:
# 创建任务文件夹 # 创建任务文件夹
if not os.path.exists(task_folder_path): if not os.path.exists(task_folder_path):
os.makedirs(task_folder_path) os.makedirs(task_folder_path)
print(f"📁 创建任务文件夹: {task_folder_path}")
else:
print(f"📁 任务文件夹已存在: {task_folder_path}")
# 返回创建的文件夹路径 # 返回创建的文件夹路径
return task_folder_path return task_folder_path
except Exception as e: except Exception as e:
print(f"❌ 创建结果文件夹失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return None return None
...@@ -719,11 +683,9 @@ class MissionPanelHandler: ...@@ -719,11 +683,9 @@ class MissionPanelHandler:
""" """
try: try:
if not yaml_file_path or not os.path.exists(yaml_file_path): if not yaml_file_path or not os.path.exists(yaml_file_path):
print("⚠️ YAML文件不存在,跳过复制")
return False return False
if not mission_result_folder_path or not os.path.exists(mission_result_folder_path): if not mission_result_folder_path or not os.path.exists(mission_result_folder_path):
print("⚠️ 结果文件夹不存在,跳过复制")
return False return False
# 复制YAML文件到结果文件夹 # 复制YAML文件到结果文件夹
...@@ -731,11 +693,9 @@ class MissionPanelHandler: ...@@ -731,11 +693,9 @@ class MissionPanelHandler:
dest_yaml_path = os.path.join(mission_result_folder_path, yaml_filename) dest_yaml_path = os.path.join(mission_result_folder_path, yaml_filename)
shutil.copy2(yaml_file_path, dest_yaml_path) shutil.copy2(yaml_file_path, dest_yaml_path)
print(f"📄 YAML文件已复制: {dest_yaml_path}")
return True return True
except Exception as e: except Exception as e:
print(f"❌ 复制YAML文件失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return False return False
...@@ -767,15 +727,11 @@ class MissionPanelHandler: ...@@ -767,15 +727,11 @@ class MissionPanelHandler:
# 删除对应的YAML配置文件 # 删除对应的YAML配置文件
self._deleteMissionConfig(task_id, task_name) self._deleteMissionConfig(task_id, task_name)
# 🔥 重新加载任务列表(而不是只删除单行) # 重新加载任务列表(而不是只删除单行)
# 这样可以确保分页数据和UI完全同步 # 这样可以确保分页数据和UI完全同步
self._loadAllMissions() self._loadAllMissions()
print(f"✅ [任务删除] 成功删除任务: {task_id}_{task_name}")
print(f"✅ [任务删除] 已重新加载任务列表")
except Exception as e: except Exception as e:
print(f"❌ [任务删除] 删除任务失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -798,7 +754,6 @@ class MissionPanelHandler: ...@@ -798,7 +754,6 @@ class MissionPanelHandler:
# 清空表格 # 清空表格
self.mission_panel.clearTable() self.mission_panel.clearTable()
print("🗑️ 表格已清空,所有任务配置文件和结果文件夹已删除")
def showMissionPanel(self): def showMissionPanel(self):
"""显示任务面板""" """显示任务面板"""
...@@ -826,7 +781,6 @@ class MissionPanelHandler: ...@@ -826,7 +781,6 @@ class MissionPanelHandler:
# 获取任务配置路径 # 获取任务配置路径
mission_dir = self._getMissionConfigPath() mission_dir = self._getMissionConfigPath()
if not mission_dir or not os.path.exists(mission_dir): if not mission_dir or not os.path.exists(mission_dir):
print("️ 任务配置目录不存在,跳过加载")
return return
# 扫描所有 .yaml 文件 # 扫描所有 .yaml 文件
...@@ -848,7 +802,6 @@ class MissionPanelHandler: ...@@ -848,7 +802,6 @@ class MissionPanelHandler:
config_data = yaml.safe_load(f) config_data = yaml.safe_load(f)
if not config_data: if not config_data:
print(f"️ 跳过空文件: {yaml_file}")
continue continue
# 构建任务信息 # 构建任务信息
...@@ -862,13 +815,11 @@ class MissionPanelHandler: ...@@ -862,13 +815,11 @@ class MissionPanelHandler:
# 验证必填字段 # 验证必填字段
if not task_info['task_id'] or not task_info['task_name']: if not task_info['task_id'] or not task_info['task_name']:
print(f"️ 跳过无效配置: {yaml_file} (缺少task_id或task_name)")
continue continue
tasks_to_load.append(task_info) tasks_to_load.append(task_info)
except Exception as e: except Exception as e:
print(f" 解析任务配置失败 ({yaml_file}): {e}")
continue continue
# 第二步:批量添加到任务面板(禁用实时刷新) # 第二步:批量添加到任务面板(禁用实时刷新)
...@@ -918,7 +869,6 @@ class MissionPanelHandler: ...@@ -918,7 +869,6 @@ class MissionPanelHandler:
self._updateChannelCellColors() self._updateChannelCellColors()
except Exception as e: except Exception as e:
print(f" 加载任务配置失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
......
...@@ -43,10 +43,6 @@ class DisplayThread: ...@@ -43,10 +43,6 @@ class DisplayThread:
# 保存上次的液位线数据(用于历史数据回退) # 保存上次的液位线数据(用于历史数据回退)
last_liquid_positions = {} last_liquid_positions = {}
# 调试计数器(用于追踪检测启动后的帧数)
debug_frame_count = 0
last_detection_enabled = False
while context.display_flag: while context.display_flag:
try: try:
frame_start_time = time.time() frame_start_time = time.time()
...@@ -63,13 +59,7 @@ class DisplayThread: ...@@ -63,13 +59,7 @@ class DisplayThread:
display_frame = frame display_frame = frame
# 检测状态变化时重置调试计数器 # 检测状态变化时重置调试计数器
if context.detection_enabled and not last_detection_enabled:
debug_frame_count = 0
last_detection_enabled = context.detection_enabled
# 如果检测已启动,叠加液位线
if context.detection_enabled: if context.detection_enabled:
debug_frame_count += 1
# 从 detection_mission_results 队列读取液位线数据(非阻塞) # 从 detection_mission_results 队列读取液位线数据(非阻塞)
liquid_positions = {} liquid_positions = {}
......
...@@ -63,21 +63,8 @@ class StorageThread: ...@@ -63,21 +63,8 @@ class StorageThread:
if not save_liquid_data_path or save_liquid_data_path == "0000": if not save_liquid_data_path or save_liquid_data_path == "0000":
return return
# print(f" [存储线程-{channel_id}] 初始化")
# print(f" - 通道名称: {channel_name}")
# print(f" - 检测区域数: {len(area_names)}")
# print(f" - 曲线存储路径: {save_liquid_data_path}")
# 创建曲线存储目录
os.makedirs(save_liquid_data_path, exist_ok=True) os.makedirs(save_liquid_data_path, exist_ok=True)
# ========== 视频保存功能(占坑,暂不实现) ==========
# TODO: 未来实现检测结果视频的保存
# timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# video_path = context.storage_path if context.storage_path else save_liquid_data_path
# display_video_path = os.path.join(video_path, f"display_{timestamp}.mp4")
# 创建CSV文件写入器(每个检测区域一个文件)
csv_files = {} csv_files = {}
csv_writers = {} csv_writers = {}
...@@ -94,9 +81,6 @@ class StorageThread: ...@@ -94,9 +81,6 @@ class StorageThread:
# 存储线程不受 save_data_rate 限制,全速消费队列,避免数据丢失 # 存储线程不受 save_data_rate 限制,全速消费队列,避免数据丢失
# save_data_rate 仅用于配置文件记录,实际存储线程会保存所有检测结果 # save_data_rate 仅用于配置文件记录,实际存储线程会保存所有检测结果
# print(f" [存储线程-{channel_id}] 启动成功")
# print(f" - 注意:存储线程全速运行,保存所有检测结果(不受save_data_rate限制)")
data_count = 0 data_count = 0
last_log_time = time.time() last_log_time = time.time()
last_flush_time = time.time() # 记录上次刷新时间 last_flush_time = time.time() # 记录上次刷新时间
...@@ -109,44 +93,18 @@ class StorageThread: ...@@ -109,44 +93,18 @@ class StorageThread:
# 从独立的 storage_data 队列读取,避免与曲线线程竞争 # 从独立的 storage_data 队列读取,避免与曲线线程竞争
detection_mission_result = context.storage_data.get(timeout=0.1) detection_mission_result = context.storage_data.get(timeout=0.1)
# # 调试信息:存储线程接收数据
# print(f"\n [存储线程-{channel_id}] 接收到检测结果:")
# print(f" - detection_mission_result类型: {type(detection_mission_result)}")
# if detection_mission_result:
# print(f" - 包含的键: {detection_mission_result.keys()}")
# 解析液位高度数据 # 解析液位高度数据
if detection_mission_result and 'liquid_line_positions' in detection_mission_result: if detection_mission_result and 'liquid_line_positions' in detection_mission_result:
liquid_positions = detection_mission_result['liquid_line_positions'] liquid_positions = detection_mission_result['liquid_line_positions']
current_time = datetime.now().strftime("%Y-%m-%d-%H:%M:%S.%f")[:-3] current_time = datetime.now().strftime("%Y-%m-%d-%H:%M:%S.%f")[:-3]
# # 调试信息:液位位置数据
# print(f" [存储线程-{channel_id}] 液位位置数据:")
# for area_idx, position_data in liquid_positions.items():
# print(f" 目标{area_idx}:")
# print(f" - position_data键: {position_data.keys()}")
# print(f" - 包含'height_cm'? {'height_cm' in position_data}")
# print(f" - 包含'height_mm'? {'height_mm' in position_data}")
# if 'height_cm' in position_data:
# print(f" - height_cm值: {position_data['height_cm']}")
# if 'height_mm' in position_data:
# print(f" - height_mm值: {position_data['height_mm']}")
# 为每个检测区域写入数据 # 为每个检测区域写入数据
for area_idx, position_data in liquid_positions.items(): for area_idx, position_data in liquid_positions.items():
if area_idx in csv_writers: if area_idx in csv_writers:
# 统一使用mm单位,直接读取height_mm # 统一使用mm单位,直接读取height_mm
height_mm = position_data.get('height_mm', 0.0) height_mm = position_data.get('height_mm', 0.0)
# # 调试信息:读取到的高度值
# print(f" [存储线程-{channel_id}] 目标{area_idx} 读取高度:")
# print(f" - height_mm: {height_mm:.2f}mm")
# 存储mm值(保留1位小数,精度0.1mm)
height_decimal = round(height_mm, 1) height_decimal = round(height_mm, 1)
# print(f" - 最终写入CSV: {height_decimal}mm")
# 写入格式:时间戳 高度值(mm, 保留1位小数) # 写入格式:时间戳 高度值(mm, 保留1位小数)
csv_writers[area_idx].write(f"{current_time} {height_decimal:.1f}\n") csv_writers[area_idx].write(f"{current_time} {height_decimal:.1f}\n")
# 不再立即刷新,改为批量刷新 # 不再立即刷新,改为批量刷新
...@@ -154,22 +112,20 @@ class StorageThread: ...@@ -154,22 +112,20 @@ class StorageThread:
data_count += 1 data_count += 1
# 定时批量刷新到磁盘(每0.5秒一次) # 定时批量刷新到磁盘(每0.5秒一次)
# 定时批量刷新到磁盘(每0.5秒一次)
current_time_check = time.time() current_time_check = time.time()
if current_time_check - last_flush_time >= flush_interval: if current_time_check - last_flush_time >= flush_interval:
for csv_file in csv_writers.values(): for csv_file in csv_writers.values():
csv_file.flush() csv_file.flush()
last_flush_time = current_time_check last_flush_time = current_time_check
# 每5秒打印一次统计
if time.time() - last_log_time > 5.0: if time.time() - last_log_time > 5.0:
# print(f" [存储线程-{channel_id}] 已保存 {data_count} 条数据,队列大小: {context.storage_data.qsize()}")
last_log_time = time.time() last_log_time = time.time()
except queue.Empty: except queue.Empty:
# 队列为空,继续等待 # 队列为空,继续等待
pass pass
except Exception as e: except Exception as e:
# print(f" [存储线程-{channel_id}] CSV写入错误: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -180,21 +136,15 @@ class StorageThread: ...@@ -180,21 +136,15 @@ class StorageThread:
# 队列的 get(timeout=0.1) 已经提供了适当的等待 # 队列的 get(timeout=0.1) 已经提供了适当的等待
except Exception as e: except Exception as e:
# print(f" [存储线程-{channel_id}] 错误: {e}")
time.sleep(0.1) time.sleep(0.1)
# 清理资源 # 清理资源
# print(f" [存储线程-{channel_id}] 正在停止...")
# 关闭CSV文件 # 关闭CSV文件
for csv_file in csv_files.values(): for csv_file in csv_files.values():
csv_file.close() csv_file.close()
# TODO: 未来需要释放视频写入器 # TODO: 未来需要释放视频写入器
# if display_writer: # TODO: 未来需要释放视频写入器
# display_writer.release()
# print(f" [存储线程-{channel_id}] 已停止")
@staticmethod @staticmethod
def _load_channel_config(channel_id: str): def _load_channel_config(channel_id: str):
......
# -*- coding: utf-8 -*-
"""
模型加载诊断脚本
用于测试检测线程的模型配置加载是否正常
"""
import os
import sys
import yaml
# 添加项目根目录到路径
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(current_dir))))
sys.path.insert(0, project_root)
from detection_thread import DetectionThread
def test_model_config_loading():
"""测试模型配置加载"""
print("=" * 80)
print("模型配置加载测试")
print("=" * 80)
# 测试各个通道
for channel_id in ['channel1', 'channel2', 'channel3', 'channel4']:
print(f"\n{'='*80}")
print(f"测试 {channel_id}")
print('='*80)
# 加载模型配置
model_config = DetectionThread._load_model_config(channel_id)
if model_config:
print(f"[OK] [{channel_id}] 模型配置加载成功")
print(f" 配置内容:")
for key, value in model_config.items():
if key == 'model_path':
print(f" - {key}: {value}")
# 检查文件是否存在
if os.path.exists(value):
file_size = os.path.getsize(value) / (1024 * 1024) # MB
print(f" [OK] 文件存在 ({file_size:.2f} MB)")
else:
print(f" [ERROR] 文件不存在!")
else:
print(f" - {key}: {value}")
else:
print(f"[ERROR] [{channel_id}] 模型配置加载失败")
# 加载标注配置
print(f"\n尝试加载 {channel_id} 的标注配置...")
annotation_config = DetectionThread._load_annotation_config(channel_id)
if annotation_config:
print(f"[OK] [{channel_id}] 标注配置加载成功")
boxes = annotation_config.get('boxes', [])
print(f" - 检测区域数: {len(boxes)}")
print(f" - 实际高度: {annotation_config.get('actual_heights', [])}")
else:
print(f"[ERROR] [{channel_id}] 标注配置加载失败")
def test_default_config_structure():
"""测试 default_config.yaml 的结构"""
print("\n" + "=" * 80)
print("检查 default_config.yaml 配置结构")
print("=" * 80)
config_file = os.path.join(project_root, 'database', 'config', 'default_config.yaml')
if not os.path.exists(config_file):
print(f" 配置文件不存在: {config_file}")
return
print(f" 配置文件存在: {config_file}\n")
with open(config_file, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
# 检查各通道的模型路径配置
print("检查各通道模型路径配置:")
for i in range(1, 5):
channel_id = f'channel{i}'
model_path_key = f'{channel_id}_model_path'
if model_path_key in config:
model_path = config[model_path_key]
print(f" {model_path_key}: {model_path}")
# 转换为绝对路径
if not os.path.isabs(model_path):
model_path = model_path.replace('/', os.sep).replace('\\', os.sep)
full_path = os.path.join(project_root, model_path)
full_path = os.path.normpath(full_path)
else:
full_path = model_path
# 检查文件是否存在
if os.path.exists(full_path):
file_size = os.path.getsize(full_path) / (1024 * 1024) # MB
print(f" 文件存在: {full_path} ({file_size:.2f} MB)")
else:
print(f" 文件不存在: {full_path}")
else:
print(f" {model_path_key}: 未配置")
# 检查全局模型配置
print("\n检查全局模型配置:")
if 'model' in config:
model_config = config['model']
for key, value in model_config.items():
print(f" - {key}: {value}")
else:
print(" 未找到全局 model 配置")
# 检查GPU配置
print("\n检查GPU配置:")
print(f" - gpu_enabled: {config.get('gpu_enabled', '未配置')}")
print(f" - default_device: {config.get('default_device', '未配置')}")
print(f" - batch_processing_enabled: {config.get('batch_processing_enabled', '未配置')}")
print(f" - default_batch_size: {config.get('default_batch_size', '未配置')}")
if __name__ == '__main__':
print(f"项目根目录: {project_root}\n")
test_default_config_structure()
print("\n")
test_model_config_loading()
print("\n" + "=" * 80)
print("测试完成")
print("=" * 80)
...@@ -43,7 +43,6 @@ except ImportError: ...@@ -43,7 +43,6 @@ except ImportError:
try: try:
from datasetpage import AnnotationHandler from datasetpage import AnnotationHandler
except ImportError as e: except ImportError as e:
print(f"Warning: AnnotationHandler not available: {e}")
AnnotationHandler = None AnnotationHandler = None
# 导入labelme # 导入labelme
...@@ -57,7 +56,6 @@ try: ...@@ -57,7 +56,6 @@ try:
from labelme.config import get_config as labelme_get_config # 重命名避免冲突 from labelme.config import get_config as labelme_get_config # 重命名避免冲突
LABELME_AVAILABLE = True LABELME_AVAILABLE = True
except ImportError as e: except ImportError as e:
print(f"Warning: Labelme not available: {e}")
LABELME_AVAILABLE = False LABELME_AVAILABLE = False
LabelmeMainWindow = None LabelmeMainWindow = None
labelme_get_config = None labelme_get_config = None
...@@ -298,7 +296,6 @@ class AnnotationTool(QtWidgets.QWidget): ...@@ -298,7 +296,6 @@ class AnnotationTool(QtWidgets.QWidget):
def _initLabelme(self): def _initLabelme(self):
"""初始化并嵌入Labelme标注工具""" """初始化并嵌入Labelme标注工具"""
if not LABELME_AVAILABLE: if not LABELME_AVAILABLE:
print("Labelme未安装,无法初始化标注工具")
return return
try: try:
...@@ -382,8 +379,6 @@ class AnnotationTool(QtWidgets.QWidget): ...@@ -382,8 +379,6 @@ class AnnotationTool(QtWidgets.QWidget):
} }
""") """)
print("[AnnotationTool] 已优化形状列表显示")
# 优化唯一标签列表的显示 # 优化唯一标签列表的显示
if hasattr(self.labelme_widget, 'uniqLabelList'): if hasattr(self.labelme_widget, 'uniqLabelList'):
uniq_list = self.labelme_widget.uniqLabelList uniq_list = self.labelme_widget.uniqLabelList
...@@ -413,8 +408,6 @@ class AnnotationTool(QtWidgets.QWidget): ...@@ -413,8 +408,6 @@ class AnnotationTool(QtWidgets.QWidget):
} }
""") """)
print("[AnnotationTool] 已优化标签列表显示")
# 调整dock面板的大小 - 这是关键! # 调整dock面板的大小 - 这是关键!
if hasattr(self.labelme_widget, 'shape_dock'): if hasattr(self.labelme_widget, 'shape_dock'):
shape_dock = self.labelme_widget.shape_dock shape_dock = self.labelme_widget.shape_dock
...@@ -426,16 +419,13 @@ class AnnotationTool(QtWidgets.QWidget): ...@@ -426,16 +419,13 @@ class AnnotationTool(QtWidgets.QWidget):
if current_width < 260: if current_width < 260:
shape_dock.resize(260, shape_dock.height()) shape_dock.resize(260, shape_dock.height())
print(f"[AnnotationTool] 已调整形状面板宽度: {shape_dock.width()}px")
# 也调整标签dock面板(如果显示的话) # 也调整标签dock面板(如果显示的话)
if hasattr(self.labelme_widget, 'label_dock'): if hasattr(self.labelme_widget, 'label_dock'):
label_dock = self.labelme_widget.label_dock label_dock = self.labelme_widget.label_dock
label_dock.setMinimumWidth(scale_w(220)) # 🔥 响应式宽度 label_dock.setMinimumWidth(scale_w(220)) # 🔥 响应式宽度
print(f"[AnnotationTool] 已调整标签面板宽度")
except Exception as e: except Exception as e:
print(f"[AnnotationTool] 优化标签显示失败: {e}") pass
def _connectLabelmeActions(self): def _connectLabelmeActions(self):
"""连接工具栏按钮到labelme的功能""" """连接工具栏按钮到labelme的功能"""
...@@ -458,7 +448,7 @@ class AnnotationTool(QtWidgets.QWidget): ...@@ -458,7 +448,7 @@ class AnnotationTool(QtWidgets.QWidget):
self.labelme_widget.adjustScale self.labelme_widget.adjustScale
) )
except Exception as e: except Exception as e:
print(f"连接labelme操作失败: {e}") pass
def _connectSignals(self): def _connectSignals(self):
"""连接UI信号和槽""" """连接UI信号和槽"""
...@@ -521,8 +511,6 @@ class AnnotationTool(QtWidgets.QWidget): ...@@ -521,8 +511,6 @@ class AnnotationTool(QtWidgets.QWidget):
if not dir_path or not osp.exists(dir_path): if not dir_path or not osp.exists(dir_path):
return return
print(f"检测到labelme打开目录: {dir_path}")
# 使用handler加载目录 # 使用handler加载目录
if self.annotation_handler: if self.annotation_handler:
self.annotation_handler.setDirectory(dir_path) self.annotation_handler.setDirectory(dir_path)
...@@ -708,15 +696,12 @@ class AnnotationTool(QtWidgets.QWidget): ...@@ -708,15 +696,12 @@ class AnnotationTool(QtWidgets.QWidget):
json_path: JSON标注文件路径(可选) json_path: JSON标注文件路径(可选)
""" """
if self.labelme_widget is None: if self.labelme_widget is None:
print("Labelme未初始化")
return return
try: try:
# 使用labelme的loadFile方法加载图片 # 使用labelme的loadFile方法加载图片
self.labelme_widget.loadFile(image_path) self.labelme_widget.loadFile(image_path)
print(f"已加载图片: {image_path}")
except Exception as e: except Exception as e:
print(f"加载图片失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -796,45 +781,6 @@ if __name__ == "__main__": ...@@ -796,45 +781,6 @@ if __name__ == "__main__":
annotation_tool.lbl_total_stats.setText(f"总数: {total}") annotation_tool.lbl_total_stats.setText(f"总数: {total}")
annotation_tool.lbl_annotated_stats.setText(f"已标注: {annotated}") annotation_tool.lbl_annotated_stats.setText(f"已标注: {annotated}")
# 打印测试说明
print("\n" + "="*70)
print(" AnnotationTool 数据标注工具组件测试程序")
print("="*70)
print(" 界面布局(两栏):")
print("\n 左侧面板 - 标注数据列表:")
print(" - 搜索框:支持按图片名称搜索")
print(" - 筛选选项:全部/已标注/未标注/待审核")
print(" - 标注列表:显示图片缩略图和基本信息")
print(" - 操作按钮:编辑、删除、导出")
print(" - 底部统计:总数、已标注数量")
print("\n 右侧面板 - Labelme标注工具区域:")
print(" - Labelme已完整嵌入到右侧面板")
print(" - 工具栏:放大、缩小、适应窗口(已连接到labelme功能)")
print(" - 包含labelme的全部标注功能:")
print(" * 多边形/矩形标注")
print(" * 标签管理")
print(" * 文件列表")
print(" * 标注列表")
print("\n 布局特点:")
print(" - 使用 QSplitter 实现可调整宽度的两栏布局")
print(" - 默认比例: 左:右 = 1:3")
print(" - 可以拖拽分割线调整各面板宽度")
print("\n Labelme集成完成:")
print(" - self.labelme_widget: 嵌入的labelme主窗口实例")
print(" - self.labelme_container: labelme的容器")
print(" - self.labelme_layout: 容器的布局管理器")
print(" - loadImageForAnnotation(): 加载图片到labelme进行标注")
print("\n 使用方法:")
print(" - 左侧列表选择图片")
print(" - 调用 loadImageForAnnotation(image_path) 加载到labelme")
print(" - 在右侧labelme面板中进行标注")
print(" - Labelme保持独立性,所有原生功能完整保留")
print("\n 说明:")
print(" - Labelme已完整嵌入,功能独立完整")
print(" - 左侧面板按钮功能可后续完善")
print(" - 界面风格统一,适配现有系统")
print("="*70 + "\n")
window.show() window.show()
sys.exit(app.exec_()) sys.exit(app.exec_())
...@@ -341,7 +341,7 @@ class CropConfigDialog(QtWidgets.QDialog): ...@@ -341,7 +341,7 @@ class CropConfigDialog(QtWidgets.QDialog):
self.format_combo.setCurrentText(saved_format) self.format_combo.setCurrentText(saved_format)
except Exception as e: except Exception as e:
print(f" 加载设置失败: {e}") pass
def _saveSettings(self): def _saveSettings(self):
"""保存当前设置""" """保存当前设置"""
...@@ -352,7 +352,7 @@ class CropConfigDialog(QtWidgets.QDialog): ...@@ -352,7 +352,7 @@ class CropConfigDialog(QtWidgets.QDialog):
settings.setValue("file_prefix", self.prefix_edit.text()) settings.setValue("file_prefix", self.prefix_edit.text())
settings.setValue("image_format", self.format_combo.currentText()) settings.setValue("image_format", self.format_combo.currentText())
except Exception as e: except Exception as e:
print(f" 保存设置失败: {e}") pass
def _onBrowse(self): def _onBrowse(self):
"""浏览文件夹""" """浏览文件夹"""
...@@ -441,8 +441,6 @@ class CropConfigDialog(QtWidgets.QDialog): ...@@ -441,8 +441,6 @@ class CropConfigDialog(QtWidgets.QDialog):
self.format_combo.setCurrentText(config['image_format']) self.format_combo.setCurrentText(config['image_format'])
# ==================== 独立运行测试 ====================
if __name__ == "__main__": if __name__ == "__main__":
"""独立运行测试""" """独立运行测试"""
import sys import sys
...@@ -455,54 +453,7 @@ if __name__ == "__main__": ...@@ -455,54 +453,7 @@ if __name__ == "__main__":
default_frequency=10 default_frequency=10
) )
# 打印测试说明
print("\n" + "="*70)
print(" 裁剪配置对话框测试程序")
print("="*70)
print(" 功能列表:")
print("\n 保存路径设置:")
print(" - 文本框显示当前路径")
print(" - 浏览按钮打开文件夹选择对话框")
print(" - 自动验证路径有效性")
print("\n 裁剪频率设置:")
print(" - SpinBox 设置裁剪间隔(1-1000帧)")
print(" - 快捷按钮:每帧、每5帧、每10帧、每30帧、每60帧")
print(" - 实时显示频率说明")
print("\n 文件命名设置:")
print(" - 设置文件名前缀")
print(" - 选择图片格式(jpg/png/bmp/tiff)")
print(" - 显示命名示例")
print("\n 设置持久化:")
print(" - 使用 QSettings 自动保存设置")
print(" - 下次打开自动恢复上次配置")
print("\n 界面特点:")
print(" - 分组布局,层次清晰")
print(" - 图标和emoji装饰")
print(" - 现代化的配色和圆角设计")
print(" - 响应式布局")
print("="*70 + "\n")
# 显示对话框
mission_result = dialog.exec_() mission_result = dialog.exec_()
# 打印结果
if mission_result == QtWidgets.QDialog.Accepted:
config = dialog.getConfig()
print("\n 用户点击了【确定】按钮")
print(" 配置信息:")
print(f" 保存路径: {config['save_liquid_data_path']}")
print(f" 裁剪频率: 每 {config['crop_frequency']} 帧")
print(f" 文件前缀: {config['file_prefix']}")
print(f" 图片格式: {config['image_format']}")
print(f"\n 文件命名示例:")
print(f" {config['file_prefix']}_0001.{config['image_format']}")
print(f" {config['file_prefix']}_0002.{config['image_format']}")
print(f" {config['file_prefix']}_0003.{config['image_format']}")
print(" ...")
else:
print("\n 用户点击了【取消】按钮")
print("\n" + "="*70 + "\n")
sys.exit(0) sys.exit(0)
...@@ -252,10 +252,6 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -252,10 +252,6 @@ class CropPreviewPanel(QtWidgets.QWidget):
auto_refresh: 是否自动刷新图片列表(默认True) auto_refresh: 是否自动刷新图片列表(默认True)
video_name: 视频名称,如果提供则只显示该视频的区域文件夹 video_name: 视频名称,如果提供则只显示该视频的区域文件夹
""" """
print(f"[CropPreview] ========== 设置保存路径 ==========")
print(f"[CropPreview] 保存路径: {save_liquid_data_path}")
print(f"[CropPreview] 视频名称: {video_name}")
print(f"[CropPreview] 自动刷新: {auto_refresh}")
self._save_liquid_data_path = save_liquid_data_path self._save_liquid_data_path = save_liquid_data_path
self._video_name = video_name # 保存视频名称 self._video_name = video_name # 保存视频名称
...@@ -284,15 +280,11 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -284,15 +280,11 @@ class CropPreviewPanel(QtWidgets.QWidget):
if auto_refresh: if auto_refresh:
self.refreshImages() self.refreshImages()
print(f"[CropPreview] 找到 {len([p for p in self._region_paths if p])} 个区域文件夹")
print(f"[CropPreview] ========== 设置完成 ==========")
def _findRegionPaths(self): def _findRegionPaths(self):
"""查找所有区域文件夹(支持新旧命名格式,可根据视频名称过滤)""" """查找所有区域文件夹(支持新旧命名格式,可根据视频名称过滤)"""
self._region_paths = [] self._region_paths = []
if not self._save_liquid_data_path or not osp.exists(self._save_liquid_data_path): if not self._save_liquid_data_path or not osp.exists(self._save_liquid_data_path):
print(f"[CropPreview] 保存路径无效或不存在")
return return
try: try:
...@@ -300,10 +292,6 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -300,10 +292,6 @@ class CropPreviewPanel(QtWidgets.QWidget):
subdirs = [d for d in os.listdir(self._save_liquid_data_path) subdirs = [d for d in os.listdir(self._save_liquid_data_path)
if osp.isdir(osp.join(self._save_liquid_data_path, d))] if osp.isdir(osp.join(self._save_liquid_data_path, d))]
print(f"[CropPreview] 扫描目录: {self._save_liquid_data_path}")
print(f"[CropPreview] 发现子文件夹: {subdirs}")
print(f"[CropPreview] 当前视频名称过滤: {self._video_name}")
# 筛选出区域文件夹 # 筛选出区域文件夹
region_folders = [] region_folders = []
for subdir in subdirs: for subdir in subdirs:
...@@ -312,22 +300,14 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -312,22 +300,14 @@ class CropPreviewPanel(QtWidgets.QWidget):
# 匹配格式:视频名_区域X # 匹配格式:视频名_区域X
if subdir.startswith(f"{self._video_name}_") and '区域' in subdir: if subdir.startswith(f"{self._video_name}_") and '区域' in subdir:
region_folders.append(subdir) region_folders.append(subdir)
print(f"[CropPreview] 匹配视频文件夹: {subdir}")
else:
print(f"[CropPreview] 跳过文件夹(不匹配当前视频): {subdir}")
else: else:
# 未指定视频名称时,查找所有区域文件夹 # 未指定视频名称时,查找所有区域文件夹
if '区域' in subdir or 'region' in subdir.lower(): if '区域' in subdir or 'region' in subdir.lower():
region_folders.append(subdir) region_folders.append(subdir)
print(f"[CropPreview] 匹配区域文件夹: {subdir}")
# 按文件夹名排序 # 按文件夹名排序
region_folders.sort() region_folders.sort()
if self._video_name:
print(f"[CropPreview] ==> 只显示视频 '{self._video_name}' 的区域文件夹")
print(f"[CropPreview] ==> 最终找到 {len(region_folders)} 个区域文件夹: {region_folders}")
# 初始化所有区域为None # 初始化所有区域为None
for i in range(3): for i in range(3):
self._region_paths.append(None) self._region_paths.append(None)
...@@ -345,14 +325,8 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -345,14 +325,8 @@ class CropPreviewPanel(QtWidgets.QWidget):
if 0 <= region_index < 3: if 0 <= region_index < 3:
region_path = osp.join(self._save_liquid_data_path, folder) region_path = osp.join(self._save_liquid_data_path, folder)
self._region_paths[region_index] = region_path self._region_paths[region_index] = region_path
print(f"[CropPreview] 区域{region_num} -> {folder} (索引{region_index})")
else:
print(f"[CropPreview] 跳过无效区域编号: {folder}")
else:
print(f"[CropPreview] 无法解析区域编号: {folder}")
except Exception as e: except Exception as e:
print(f"[CropPreview] 查找区域文件夹失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
# 降级到旧的查找方式 # 降级到旧的查找方式
...@@ -360,7 +334,6 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -360,7 +334,6 @@ class CropPreviewPanel(QtWidgets.QWidget):
region_path = osp.join(self._save_liquid_data_path, f"region{i+1}") region_path = osp.join(self._save_liquid_data_path, f"region{i+1}")
if osp.exists(region_path): if osp.exists(region_path):
self._region_paths.append(region_path) self._region_paths.append(region_path)
print(f"[CropPreview] (旧格式) 找到区域文件夹: region{i+1}")
else: else:
self._region_paths.append(None) self._region_paths.append(None)
...@@ -383,8 +356,6 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -383,8 +356,6 @@ class CropPreviewPanel(QtWidgets.QWidget):
# 更新统计 # 更新统计
self._updateStats() self._updateStats()
print(f"[CropPreview] 刷新完成")
def _loadRegionImages(self, region_index, region_path): def _loadRegionImages(self, region_index, region_path):
""" """
加载指定区域的图片 加载指定区域的图片
...@@ -428,7 +399,6 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -428,7 +399,6 @@ class CropPreviewPanel(QtWidgets.QWidget):
font = placeholder_item.font() font = placeholder_item.font()
font.setPointSize(10) font.setPointSize(10)
placeholder_item.setFont(font) placeholder_item.setFont(font)
print(f"[CropPreview] 区域{region_index+1} 等待图片生成...")
return return
# 添加到网格(只显示最新的100张,避免加载过多) # 添加到网格(只显示最新的100张,避免加载过多)
...@@ -458,10 +428,8 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -458,10 +428,8 @@ class CropPreviewPanel(QtWidgets.QWidget):
# 设置文本居中对齐 # 设置文本居中对齐
item.setTextAlignment(Qt.AlignCenter) item.setTextAlignment(Qt.AlignCenter)
print(f"[CropPreview] 区域{region_index+1} 加载 {len(files)} 张图片 (显示最新{len(display_files)}张)")
except Exception as e: except Exception as e:
print(f"[CropPreview] 加载区域{region_index+1}图片失败: {e}") pass
def _generateThumbnail(self, image_path): def _generateThumbnail(self, image_path):
""" """
...@@ -490,7 +458,6 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -490,7 +458,6 @@ class CropPreviewPanel(QtWidgets.QWidget):
return scaled_pixmap return scaled_pixmap
except Exception as e: except Exception as e:
print(f"[CropPreview] 生成缩略图失败: {e}")
return None return None
def clearImages(self): def clearImages(self):
...@@ -523,8 +490,6 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -523,8 +490,6 @@ class CropPreviewPanel(QtWidgets.QWidget):
# 更新统计 # 更新统计
self._updateStats() self._updateStats()
print(f"[CropPreview] 清空图片列表,准备新任务")
def addImage(self, region_index, image_path): def addImage(self, region_index, image_path):
""" """
添加单张图片到指定区域(用于实时更新) 添加单张图片到指定区域(用于实时更新)
...@@ -597,7 +562,6 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -597,7 +562,6 @@ class CropPreviewPanel(QtWidgets.QWidget):
self._current_region = index self._current_region = index
self._updateStats() self._updateStats()
self.regionChanged.emit(index) self.regionChanged.emit(index)
print(f"[CropPreview] 切换到区域 {index+1}")
def _onImageDoubleClicked(self, item): def _onImageDoubleClicked(self, item):
"""图片被双击 - 显示大图""" """图片被双击 - 显示大图"""
...@@ -710,14 +674,11 @@ class CropPreviewPanel(QtWidgets.QWidget): ...@@ -710,14 +674,11 @@ class CropPreviewPanel(QtWidgets.QWidget):
# 更新统计 # 更新统计
self._updateStats() self._updateStats()
print(f"[CropPreview] 已删除区域 {current_region + 1} 的文件")
except Exception as e: except Exception as e:
if DialogManager: if DialogManager:
DialogManager.show_critical(self, "错误", f"删除失败: {str(e)}") DialogManager.show_critical(self, "错误", f"删除失败: {str(e)}")
else: else:
QtWidgets.QMessageBox.critical(self, "错误", f"删除失败: {str(e)}") QtWidgets.QMessageBox.critical(self, "错误", f"删除失败: {str(e)}")
print(f"[CropPreview] 删除区域文件失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -799,7 +760,6 @@ class ImageViewDialog(QtWidgets.QDialog): ...@@ -799,7 +760,6 @@ class ImageViewDialog(QtWidgets.QDialog):
except Exception as e: except Exception as e:
self.image_label.setText(f"加载失败: {e}") self.image_label.setText(f"加载失败: {e}")
print(f"[ImageViewDialog] 加载图片失败: {e}")
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -101,12 +101,9 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -101,12 +101,9 @@ class DataCollectionPanel(QtWidgets.QWidget):
def _showWarning(self, title, message): def _showWarning(self, title, message):
"""显示警告对话框""" """显示警告对话框"""
print(f"[DEBUG] _showWarning 被调用, DialogManager={'存在' if DialogManager else '不存在'}")
if DialogManager: if DialogManager:
print(f"[DEBUG] 使用 DialogManager.show_warning")
DialogManager.show_warning(self, title, message) DialogManager.show_warning(self, title, message)
else: else:
print(f"[DEBUG] 使用原生 QMessageBox.warning")
QtWidgets.QMessageBox.warning(self, title, message) QtWidgets.QMessageBox.warning(self, title, message)
def _showInformation(self, title, message): def _showInformation(self, title, message):
...@@ -261,10 +258,10 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -261,10 +258,10 @@ class DataCollectionPanel(QtWidgets.QWidget):
from ..responsive_layout import scale_spacing from ..responsive_layout import scale_spacing
channel_select_layout.setSpacing(scale_spacing(5)) channel_select_layout.setSpacing(scale_spacing(5))
channel_label = QtWidgets.QLabel("选择通道:") channel_label = QtWidgets.QLabel("选择通道:")
channel_label.setFixedWidth(scale_w(75)) # 🔥 响应式宽度 channel_label.setFixedWidth(scale_w(75)) # 响应式宽度
self.channel_combo = QtWidgets.QComboBox() self.channel_combo = QtWidgets.QComboBox()
self.channel_combo.setFixedWidth(scale_w(90)) # 🔥 响应式宽度 self.channel_combo.setFixedWidth(scale_w(90)) # 响应式宽度
# 向右移动5px # 向右移动5px
from ..responsive_layout import scale_margin from ..responsive_layout import scale_margin
margin = scale_margin(5) margin = scale_margin(5)
...@@ -389,7 +386,7 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -389,7 +386,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
# 右侧:通道预览区域 - 响应式布局 # 右侧:通道预览区域 - 响应式布局
self.channel_preview = QtWidgets.QLabel() self.channel_preview = QtWidgets.QLabel()
self.channel_preview.setFixedSize(scale_w(640), scale_h(480)) # 🔥 响应式尺寸 self.channel_preview.setFixedSize(scale_w(640), scale_h(480)) # 响应式尺寸
self.channel_preview.setAlignment(QtCore.Qt.AlignCenter) self.channel_preview.setAlignment(QtCore.Qt.AlignCenter)
self.channel_preview.setStyleSheet(""" self.channel_preview.setStyleSheet("""
QLabel { QLabel {
...@@ -455,10 +452,8 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -455,10 +452,8 @@ class DataCollectionPanel(QtWidgets.QWidget):
if osp.exists(path) and osp.isdir(path): if osp.exists(path) and osp.isdir(path):
self._root_path = path self._root_path = path
self._loadFolders() self._loadFolders()
pass
return True return True
else: else:
pass
return False return False
def getRootPath(self): def getRootPath(self):
...@@ -719,7 +714,7 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -719,7 +714,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
return return
# 检查是否为视频文件 # 检查是否为视频文件
video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v'] video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv', '.mpg', '.mpeg']
file_ext = osp.splitext(file_name)[1].lower() file_ext = osp.splitext(file_name)[1].lower()
if file_ext in video_extensions: if file_ext in video_extensions:
...@@ -902,56 +897,38 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -902,56 +897,38 @@ class DataCollectionPanel(QtWidgets.QWidget):
def _onDeleteFile(self, item): def _onDeleteFile(self, item):
"""删除文件""" """删除文件"""
print("\n" + "="*60)
print("[调试] _onDeleteFile 方法被调用")
print("="*60)
if not item: if not item:
print("[调试] item 为空,返回")
return return
# 获取文件路径 # 获取文件路径
file_path = item.data(Qt.UserRole) file_path = item.data(Qt.UserRole)
print(f"[调试] 文件路径: {file_path}")
if not file_path or not osp.exists(file_path): if not file_path or not osp.exists(file_path):
print("[调试] 文件不存在,显示警告")
self._showWarning("警告", "文件不存在") self._showWarning("警告", "文件不存在")
return return
file_name = osp.basename(file_path) file_name = osp.basename(file_path)
print(f"[调试] 文件名: {file_name}")
# 确认删除 - 使用警告图标的统一对话框 # 确认删除
print("[调试] 显示确认删除对话框(使用 _showQuestionWarning)")
if self._showQuestionWarning( if self._showQuestionWarning(
"确认删除", "确认删除",
f"确定要删除文件 '{file_name}' 吗?\n\n" f"确定要删除文件 '{file_name}' 吗?\n\n文件将被移动到回收站"
f"文件将被移动到回收站"
): ):
print("[调试] 用户确认删除")
try: try:
# 使用Windows回收站删除 # 使用Windows回收站删除
if delete_file_to_recycle_bin: if delete_file_to_recycle_bin:
delete_file_to_recycle_bin(file_path) delete_file_to_recycle_bin(file_path)
print(f"[调试] 文件已移动到回收站: {file_path}")
else:
raise ImportError("回收站工具未导入")
# 刷新内容列表 # 刷新内容列表
if self._current_folder: if self._current_folder:
self._loadFolderContent(self._current_folder) self._loadFolderContent(self._current_folder)
print(" [调试] 已刷新文件夹内容")
print(" [调试] 显示成功提示(使用 _showInformation)")
self._showInformation("成功", f"文件已删除\n{file_name}")
except Exception as e: except Exception as e:
print(f"[调试] 删除文件失败: {e}")
print("[调试] 显示错误提示(使用 _showCritical)")
self._showCritical("错误", f"删除文件失败:\n{str(e)}") self._showCritical("错误", f"删除文件失败:\n{str(e)}")
else: else:
print("[调试] 用户取消删除") pass
def _onAddFolder(self): def _onAddFolder(self):
"""新增文件夹""" """新增文件夹"""
...@@ -1020,8 +997,6 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -1020,8 +997,6 @@ class DataCollectionPanel(QtWidgets.QWidget):
# 发射信号 # 发射信号
self.folderAdded.emit(folder_path) self.folderAdded.emit(folder_path)
except Exception as e: except Exception as e:
self._showCritical("错误", f"创建文件夹失败: {e}") self._showCritical("错误", f"创建文件夹失败: {e}")
...@@ -1050,7 +1025,7 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -1050,7 +1025,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
elif ext in ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']: elif ext in ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']:
image_count += 1 image_count += 1
except Exception as e: except Exception as e:
print(f"[WARNING] 统计文件夹内容失败: {e}") pass
# 构建文件信息提示 # 构建文件信息提示
file_info = [] file_info = []
...@@ -1065,7 +1040,7 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -1065,7 +1040,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
else: else:
message = f"确定要删除文件夹 '{folder_name}' 吗?\n\n文件夹为空\n\n将被移动到回收站" message = f"确定要删除文件夹 '{folder_name}' 吗?\n\n文件夹为空\n\n将被移动到回收站"
# 确认删除 - 使用警告图标的统一对话框 # 确认删除
if self._showQuestionWarning("确认删除", message): if self._showQuestionWarning("确认删除", message):
try: try:
# 使用Windows回收站删除 # 使用Windows回收站删除
...@@ -1087,8 +1062,6 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -1087,8 +1062,6 @@ class DataCollectionPanel(QtWidgets.QWidget):
# 发射信号 # 发射信号
self.folderDeleted.emit(folder_path) self.folderDeleted.emit(folder_path)
except Exception as e: except Exception as e:
self._showCritical("错误", f"删除文件夹失败: {e}") self._showCritical("错误", f"删除文件夹失败: {e}")
...@@ -1346,7 +1319,6 @@ def _loadRTSPConfig(self): ...@@ -1346,7 +1319,6 @@ def _loadRTSPConfig(self):
config_path = os.path.join(project_root, 'database', 'config', 'default_config.yaml') config_path = os.path.join(project_root, 'database', 'config', 'default_config.yaml')
if not os.path.exists(config_path): if not os.path.exists(config_path):
print(f"[WARNING] 配置文件不存在: {config_path}")
return None return None
# 读取 YAML 配置文件 # 读取 YAML 配置文件
...@@ -1373,11 +1345,9 @@ def _loadRTSPConfig(self): ...@@ -1373,11 +1345,9 @@ def _loadRTSPConfig(self):
} if channels else None } if channels else None
except Exception as e: except Exception as e:
print(f"[WARNING] 无法获取项目根目录或读取配置: {e}")
return None return None
except Exception as e: except Exception as e:
print(f"[ERROR] 加载RTSP配置失败: {e}")
return None return None
# 获取选择的通道方法 # 获取选择的通道方法
......
...@@ -596,7 +596,7 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -596,7 +596,7 @@ class DataPreprocessPanel(QtWidgets.QWidget):
if saved_format: if saved_format:
self.crop_format_combo.setCurrentText(saved_format) self.crop_format_combo.setCurrentText(saved_format)
except Exception as e: except Exception as e:
print(f"加载裁剪配置失败: {e}") pass
def _saveCropConfig(self): def _saveCropConfig(self):
"""保存裁剪配置""" """保存裁剪配置"""
...@@ -607,7 +607,7 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -607,7 +607,7 @@ class DataPreprocessPanel(QtWidgets.QWidget):
settings.setValue("prefix", self.crop_prefix_edit.text()) settings.setValue("prefix", self.crop_prefix_edit.text())
settings.setValue("format", self.crop_format_combo.currentText()) settings.setValue("format", self.crop_format_combo.currentText())
except Exception as e: except Exception as e:
print(f"保存裁剪配置失败: {e}") pass
def getCropConfig(self): def getCropConfig(self):
"""获取裁剪配置""" """获取裁剪配置"""
...@@ -718,7 +718,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -718,7 +718,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
self.folder_list.clear() self.folder_list.clear()
if not osp.exists(self._root_path): if not osp.exists(self._root_path):
print(f" 根目录不存在: {self._root_path}")
return return
# 获取所有子文件夹 # 获取所有子文件夹
...@@ -747,26 +746,19 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -747,26 +746,19 @@ class DataPreprocessPanel(QtWidgets.QWidget):
def _loadVideos(self, folder_name): def _loadVideos(self, folder_name):
"""加载视频网格""" """加载视频网格"""
print("\n" + "=" * 50)
print(f" 开始加载视频: {folder_name}")
self.video_grid.clear() self.video_grid.clear()
folder_path = osp.join(self._root_path, folder_name) folder_path = osp.join(self._root_path, folder_name)
print(f" 完整路径: {folder_path}")
if not osp.exists(folder_path): if not osp.exists(folder_path):
print(f" 文件夹不存在: {folder_path}")
return return
try: try:
# 支持的视频格式 # 支持的视频格式
video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv', '.mpg', '.mpeg'] video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv', '.mpg', '.mpeg']
print(f" 支持的格式: {', '.join(video_extensions)}")
# 获取所有文件 # 获取所有文件
all_files = os.listdir(folder_path) all_files = os.listdir(folder_path)
print(f" 文件夹中共有 {len(all_files)} 个项目")
# 获取所有视频文件 # 获取所有视频文件
files = [f for f in all_files files = [f for f in all_files
...@@ -774,10 +766,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -774,10 +766,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
osp.splitext(f)[1].lower() in video_extensions] osp.splitext(f)[1].lower() in video_extensions]
files.sort() files.sort()
print(f" 找到 {len(files)} 个视频文件:")
for f in files:
print(f" - {f}")
# 添加到网格 # 添加到网格
for file in files: for file in files:
item = QtWidgets.QListWidgetItem(self.video_grid) item = QtWidgets.QListWidgetItem(self.video_grid)
...@@ -797,12 +785,10 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -797,12 +785,10 @@ class DataPreprocessPanel(QtWidgets.QWidget):
thumbnail = self._generateVideoThumbnail(file_path) thumbnail = self._generateVideoThumbnail(file_path)
if thumbnail: if thumbnail:
item.setIcon(QtGui.QIcon(thumbnail)) item.setIcon(QtGui.QIcon(thumbnail))
print(f" 生成缩略图: {file}")
else: else:
# 如果缩略图生成失败,使用系统标准图标 # 如果缩略图生成失败,使用系统标准图标
icon = self.style().standardIcon(QtWidgets.QStyle.SP_MediaPlay) icon = self.style().standardIcon(QtWidgets.QStyle.SP_MediaPlay)
item.setIcon(icon) item.setIcon(icon)
print(f" 使用默认图标: {file}")
# 设置文本居中对齐 # 设置文本居中对齐
item.setTextAlignment(Qt.AlignCenter) item.setTextAlignment(Qt.AlignCenter)
...@@ -811,17 +797,10 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -811,17 +797,10 @@ class DataPreprocessPanel(QtWidgets.QWidget):
self.lbl_video_stats.setText(f"视频数: {len(files)}") self.lbl_video_stats.setText(f"视频数: {len(files)}")
if len(files) == 0: if len(files) == 0:
print(" 该文件夹中没有视频文件!")
print(" 提示:请确保文件夹中有视频文件,并且格式正确")
else:
pass pass
print("=" * 50 + "\n")
except Exception as e: except Exception as e:
pass pass
import traceback
traceback.print_exc()
def _generateVideoThumbnail(self, video_path): def _generateVideoThumbnail(self, video_path):
"""生成视频缩略图(提取第一帧)""" """生成视频缩略图(提取第一帧)"""
...@@ -832,7 +811,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -832,7 +811,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
cap = cv2.VideoCapture(video_path) cap = cv2.VideoCapture(video_path)
if not cap.isOpened(): if not cap.isOpened():
print(f"[DataPreprocess] 无法打开视频: {video_path}")
return None return None
# 读取第一帧 # 读取第一帧
...@@ -840,7 +818,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -840,7 +818,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
cap.release() cap.release()
if not ret or frame is None: if not ret or frame is None:
print(f"[DataPreprocess] 无法读取视频帧: {video_path}")
return None return None
# 转换颜色空间 BGR -> RGB # 转换颜色空间 BGR -> RGB
...@@ -862,7 +839,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -862,7 +839,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
return scaled_pixmap return scaled_pixmap
except Exception as e: except Exception as e:
print(f"[DataPreprocess] 生成视频缩略图失败: {e}")
return None return None
# ========== 槽函数 ========== # ========== 槽函数 ==========
...@@ -887,8 +863,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -887,8 +863,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
folder_path = osp.join(self._root_path, folder_name) folder_path = osp.join(self._root_path, folder_name)
self.folderSelected.emit(folder_path) self.folderSelected.emit(folder_path)
print(f" 选中文件夹: {folder_name}")
def _onFolderDoubleClicked(self, item): def _onFolderDoubleClicked(self, item):
"""文件夹被双击""" """文件夹被双击"""
folder_name = item.data(Qt.UserRole) folder_name = item.data(Qt.UserRole)
...@@ -901,79 +875,53 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -901,79 +875,53 @@ class DataPreprocessPanel(QtWidgets.QWidget):
elif os.name == 'posix': # macOS, Linux elif os.name == 'posix': # macOS, Linux
import subprocess import subprocess
subprocess.Popen(['open', folder_path]) subprocess.Popen(['open', folder_path])
print(f" 打开文件夹: {folder_path}")
except Exception as e: except Exception as e:
pass pass
def _onAddFolder(self): def _onAddFolder(self):
"""新增文件夹""" """新增文件夹"""
print("\n" + "="*60)
print("[调试] _onAddFolder 方法被调用")
print("="*60)
# 创建自定义对话框(完全控制按钮和窗口标志) # 创建自定义对话框(完全控制按钮和窗口标志)
dialog = QtWidgets.QDialog(self) dialog = QtWidgets.QDialog(self)
print(f"[调试] QDialog 对象已创建: {dialog}")
dialog.setWindowTitle("新增文件夹") dialog.setWindowTitle("新增文件夹")
print(f"[调试] 窗口标题已设置: 新增文件夹")
# 移除帮助按钮(问号按钮) # 移除帮助按钮(问号按钮)
old_flags = dialog.windowFlags() old_flags = dialog.windowFlags()
print(f"[调试] 原始窗口标志: {old_flags}")
print(f"[调试] WindowContextHelpButtonHint 值: {QtCore.Qt.WindowContextHelpButtonHint}")
new_flags = old_flags & ~QtCore.Qt.WindowContextHelpButtonHint new_flags = old_flags & ~QtCore.Qt.WindowContextHelpButtonHint
dialog.setWindowFlags(new_flags) dialog.setWindowFlags(new_flags)
print(f"[调试] 新窗口标志已设置: {new_flags}")
print(f"[调试] 标志是否改变: {old_flags != new_flags}")
# 创建布局 # 创建布局
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
print(f"[调试] QVBoxLayout 已创建")
# 添加标签 # 添加标签
label = QtWidgets.QLabel("请输入文件夹名称:") label = QtWidgets.QLabel("请输入文件夹名称:")
layout.addWidget(label) layout.addWidget(label)
print(f"[调试] 标签已添加")
# 添加输入框 # 添加输入框
input_edit = QtWidgets.QLineEdit() input_edit = QtWidgets.QLineEdit()
layout.addWidget(input_edit) layout.addWidget(input_edit)
print(f"[调试] 输入框已添加")
# 创建按钮布局 # 创建按钮布局
button_layout = QtWidgets.QHBoxLayout() button_layout = QtWidgets.QHBoxLayout()
ok_btn = QtWidgets.QPushButton("确定") ok_btn = QtWidgets.QPushButton("确定")
cancel_btn = QtWidgets.QPushButton("取消") cancel_btn = QtWidgets.QPushButton("取消")
print(f"[调试] 按钮已创建 - 确定: {ok_btn.text()}, 取消: {cancel_btn.text()}")
button_layout.addStretch() button_layout.addStretch()
button_layout.addWidget(ok_btn) button_layout.addWidget(ok_btn)
button_layout.addWidget(cancel_btn) button_layout.addWidget(cancel_btn)
layout.addLayout(button_layout) layout.addLayout(button_layout)
print(f"[调试] 按钮布局已添加")
dialog.setLayout(layout) dialog.setLayout(layout)
print(f"[调试] 主布局已设置到对话框")
# 连接按钮信号 # 连接按钮信号
ok_btn.clicked.connect(dialog.accept) ok_btn.clicked.connect(dialog.accept)
cancel_btn.clicked.connect(dialog.reject) cancel_btn.clicked.connect(dialog.reject)
print(f"[调试] 按钮信号已连接")
# 设置输入框焦点 # 设置输入框焦点
input_edit.setFocus() input_edit.setFocus()
print(f"[调试] 输入框焦点已设置")
# 显示对话框 # 显示对话框
print(f"[调试] 即将显示对话框...")
ok = dialog.exec_() ok = dialog.exec_()
print(f"[调试] 对话框已关闭,返回值: {ok} (1=Accepted, 0=Rejected)")
text = input_edit.text() text = input_edit.text()
print(f"[调试] 输入框文本: '{text}'")
if ok and text: if ok and text:
folder_path = osp.join(self._root_path, text) folder_path = osp.join(self._root_path, text)
...@@ -1029,7 +977,7 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1029,7 +977,7 @@ class DataPreprocessPanel(QtWidgets.QWidget):
elif ext in ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']: elif ext in ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']:
image_count += 1 image_count += 1
except Exception as e: except Exception as e:
print(f"[WARNING] 统计文件夹内容失败: {e}") pass
# 构建文件信息提示 # 构建文件信息提示
file_info = [] file_info = []
...@@ -1050,7 +998,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1050,7 +998,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
# 使用Windows回收站删除 # 使用Windows回收站删除
if delete_folder_to_recycle_bin: if delete_folder_to_recycle_bin:
delete_folder_to_recycle_bin(folder_path) delete_folder_to_recycle_bin(folder_path)
print(f"[OK] 文件夹已移动到回收站: {folder_path}")
else: else:
raise ImportError("回收站工具未导入") raise ImportError("回收站工具未导入")
...@@ -1074,7 +1021,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1074,7 +1021,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
except Exception as e: except Exception as e:
self._showCritical("错误", f"删除文件夹失败: {e}") self._showCritical("错误", f"删除文件夹失败: {e}")
print(f"[ERROR] 删除文件夹失败: {e}")
def _onFolderListContextMenu(self, position): def _onFolderListContextMenu(self, position):
"""显示文件夹列表的右键菜单""" """显示文件夹列表的右键菜单"""
...@@ -1130,26 +1076,21 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1130,26 +1076,21 @@ class DataPreprocessPanel(QtWidgets.QWidget):
def _onVideoClicked(self, item): def _onVideoClicked(self, item):
"""视频被点击""" """视频被点击"""
print("=" * 50)
print(" _onVideoClicked 被调用")
video_path = item.data(Qt.UserRole) video_path = item.data(Qt.UserRole)
print(f" 视频路径: {video_path}")
# 先停止之前的播放 # 先停止之前的播放
self._onStopVideo() self._onStopVideo()
# 保存当前视频路径
self._current_video = video_path self._current_video = video_path
# 更新显示 # 更新当前视频显示
video_name = osp.basename(video_path) video_name = osp.basename(video_path)
self.lbl_current_video.setText(f"当前视频: {video_name}") self.lbl_current_video.setText(f"当前视频: {video_name}")
# 启用裁剪按钮和播放按钮 # 启用裁剪按钮和播放按钮
print(f" 启用裁剪按钮...")
self.btn_crop.setEnabled(True) self.btn_crop.setEnabled(True)
self.btn_play.setEnabled(True) self.btn_play.setEnabled(True)
print(f" 按钮状态: {'启用' if self.btn_crop.isEnabled() else '禁用'}")
# 加载视频的第一帧作为预览 # 加载视频的第一帧作为预览
self._loadVideoFirstFrame(video_path) self._loadVideoFirstFrame(video_path)
...@@ -1157,9 +1098,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1157,9 +1098,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
# 发射信号 # 发射信号
self.videoSelected.emit(video_path) self.videoSelected.emit(video_path)
print(f"[OK] 选中视频: {video_name}")
print("=" * 50)
def _onVideoDoubleClicked(self, item): def _onVideoDoubleClicked(self, item):
"""视频被双击 - 使用系统默认播放器打开""" """视频被双击 - 使用系统默认播放器打开"""
video_path = item.data(Qt.UserRole) video_path = item.data(Qt.UserRole)
...@@ -1170,18 +1108,14 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1170,18 +1108,14 @@ class DataPreprocessPanel(QtWidgets.QWidget):
elif os.name == 'posix': # macOS, Linux elif os.name == 'posix': # macOS, Linux
import subprocess import subprocess
subprocess.Popen(['open', video_path]) subprocess.Popen(['open', video_path])
print(f"▶ 播放视频: {video_path}")
except Exception as e: except Exception as e:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, "错误", f"无法打开视频: {e}" self, "错误", f"无法打开视频: {e}"
) )
print(f"[ERROR] 打开视频失败: {e}")
def _onRefreshVideos(self): def _onRefreshVideos(self):
"""刷新视频列表""" """刷新视频列表"""
if self._current_folder: if self._current_folder:
print(f"[刷新] 正在刷新文件夹: {self._current_folder}")
self._loadVideos(self._current_folder) self._loadVideos(self._current_folder)
# 刷新后,通知handler更新视频网格样式(恢复绿色标识) # 刷新后,通知handler更新视频网格样式(恢复绿色标识)
...@@ -1190,7 +1124,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1190,7 +1124,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
# 使用QTimer延迟执行,确保视频列表已完全加载 # 使用QTimer延迟执行,确保视频列表已完全加载
from qtpy.QtCore import QTimer from qtpy.QtCore import QTimer
QTimer.singleShot(100, self._handler.updateVideoGridStyles) QTimer.singleShot(100, self._handler.updateVideoGridStyles)
print(f"[刷新] 已安排更新视频网格样式")
# 隐藏刷新完成提示弹窗 # 隐藏刷新完成提示弹窗
# self._showInformation("刷新完成", f"已刷新文件夹 '{self._current_folder}' 中的视频列表") # self._showInformation("刷新完成", f"已刷新文件夹 '{self._current_folder}' 中的视频列表")
...@@ -1255,7 +1188,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1255,7 +1188,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
if hasattr(self, '_handler') and self._handler: if hasattr(self, '_handler') and self._handler:
if hasattr(self._handler, 'releaseVideoCapture'): if hasattr(self._handler, 'releaseVideoCapture'):
self._handler.releaseVideoCapture() self._handler.releaseVideoCapture()
print(f"[DataPreprocess] 已释放视频文件句柄")
# 获取当前文件名(不含扩展名)和扩展名 # 获取当前文件名(不含扩展名)和扩展名
video_dir = osp.dirname(video_path) video_dir = osp.dirname(video_path)
...@@ -1307,14 +1239,11 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1307,14 +1239,11 @@ class DataPreprocessPanel(QtWidgets.QWidget):
f"视频已重命名为: {new_video_name}" f"视频已重命名为: {new_video_name}"
) )
print(f"[OK] 重命名视频: {video_name} -> {new_video_name}")
except Exception as e: except Exception as e:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, "错误", self, "错误",
f"重命名视频失败:\n{str(e)}" f"重命名视频失败:\n{str(e)}"
) )
print(f"[ERROR] 重命名视频失败: {e}")
def _onDeleteVideo(self, item): def _onDeleteVideo(self, item):
"""删除视频""" """删除视频"""
...@@ -1356,12 +1285,8 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1356,12 +1285,8 @@ class DataPreprocessPanel(QtWidgets.QWidget):
if self._current_folder: if self._current_folder:
self._loadVideos(self._current_folder) self._loadVideos(self._current_folder)
print(f"[OK] 删除视频: {video_name}")
except Exception as e: except Exception as e:
self._showCritical("错误", f"删除视频失败:\n{str(e)}") self._showCritical("错误", f"删除视频失败:\n{str(e)}")
print(f"[ERROR] 删除视频失败: {e}")
def _onBrowseCropPath(self): def _onBrowseCropPath(self):
"""浏览裁剪保存路径""" """浏览裁剪保存路径"""
...@@ -1408,17 +1333,10 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1408,17 +1333,10 @@ class DataPreprocessPanel(QtWidgets.QWidget):
# 发射信号 # 发射信号
self.cropStarted.emit(config) self.cropStarted.emit(config)
print(f"[CROP] 裁剪配置:")
print(f" 视频: {osp.basename(self._current_video)}")
print(f" 保存路径: {config['save_liquid_data_path']}")
print(f" 裁剪频率: 每 {config['crop_frequency']} 帧")
print(f" 提示: 使用 DataPreprocessHandler 可以启用可视化画框功能")
except Exception as e: except Exception as e:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, "错误", f"打开配置对话框失败:\n{e}" self, "错误", f"打开配置对话框失败:\n{e}"
) )
print(f"[ERROR] 打开配置对话框失败: {e}")
def _loadVideoFirstFrame(self, video_path): def _loadVideoFirstFrame(self, video_path):
"""加载视频的第一帧作为预览""" """加载视频的第一帧作为预览"""
...@@ -1429,7 +1347,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1429,7 +1347,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
cap = cv2.VideoCapture(video_path) cap = cv2.VideoCapture(video_path)
if not cap.isOpened(): if not cap.isOpened():
print(f" 无法打开视频: {video_path}")
self.video_preview.setText("无法打开视频") self.video_preview.setText("无法打开视频")
return return
...@@ -1456,17 +1373,13 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1456,17 +1373,13 @@ class DataPreprocessPanel(QtWidgets.QWidget):
# 显示 # 显示
self.video_preview.setPixmap(scaled_pixmap) self.video_preview.setPixmap(scaled_pixmap)
print(f"[OK] 加载视频第一帧")
else: else:
self.video_preview.setText("无法读取视频帧") self.video_preview.setText("无法读取视频帧")
print(f" 无法读取视频帧")
except ImportError: except ImportError:
self.video_preview.setText("缺少 OpenCV 库\npip install opencv-python") self.video_preview.setText("缺少 OpenCV 库\npip install opencv-python")
print(f"[ERROR] 缺少 OpenCV 库")
except Exception as e: except Exception as e:
self.video_preview.setText(f"加载失败\n{str(e)}") self.video_preview.setText(f"加载失败\n{str(e)}")
print(f"[ERROR] 加载视频第一帧失败: {e}")
def _onPlayVideo(self): def _onPlayVideo(self):
"""播放视频""" """播放视频"""
...@@ -1503,8 +1416,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1503,8 +1416,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
self._video_timer.timeout.connect(self._updateVideoFrame) self._video_timer.timeout.connect(self._updateVideoFrame)
self._video_timer.start(int(1000 / fps)) # 根据fps设置间隔 self._video_timer.start(int(1000 / fps)) # 根据fps设置间隔
print(f"▶ 开始播放视频 (FPS: {fps})")
except ImportError: except ImportError:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, "错误", "缺少 OpenCV 库\n\n请安装: pip install opencv-python" self, "错误", "缺少 OpenCV 库\n\n请安装: pip install opencv-python"
...@@ -1513,7 +1424,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1513,7 +1424,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, "错误", f"播放视频失败: {e}" self, "错误", f"播放视频失败: {e}"
) )
print(f"[ERROR] 播放视频失败: {e}")
def _onPauseVideo(self): def _onPauseVideo(self):
"""暂停视频""" """暂停视频"""
...@@ -1524,8 +1434,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1524,8 +1434,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
self.btn_play.setEnabled(True) self.btn_play.setEnabled(True)
self.btn_pause.setEnabled(False) self.btn_pause.setEnabled(False)
print(f"⏸ 暂停视频")
def _onStopVideo(self): def _onStopVideo(self):
"""停止视频""" """停止视频"""
# 停止定时器 # 停止定时器
...@@ -1548,8 +1456,6 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1548,8 +1456,6 @@ class DataPreprocessPanel(QtWidgets.QWidget):
if self._current_video: if self._current_video:
self._loadVideoFirstFrame(self._current_video) self._loadVideoFirstFrame(self._current_video)
print(f"⏹ 停止视频")
def _updateVideoFrame(self): def _updateVideoFrame(self):
"""更新视频画面""" """更新视频画面"""
if not self._video_capture or not self._video_playing: if not self._video_capture or not self._video_playing:
...@@ -1585,7 +1491,7 @@ class DataPreprocessPanel(QtWidgets.QWidget): ...@@ -1585,7 +1491,7 @@ class DataPreprocessPanel(QtWidgets.QWidget):
self._video_capture.set(cv2.CAP_PROP_POS_FRAMES, 0) self._video_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)
except Exception as e: except Exception as e:
print(f"[ERROR] 更新视频画面失败: {e}") pass
def _onBrowseCropPath(self): def _onBrowseCropPath(self):
"""浏览裁剪保存路径""" """浏览裁剪保存路径"""
...@@ -1687,20 +1593,16 @@ if __name__ == "__main__": ...@@ -1687,20 +1593,16 @@ if __name__ == "__main__":
window.setWindowTitle("数据预处理面板测试") window.setWindowTitle("数据预处理面板测试")
window.resize(1200, 700) window.resize(1200, 700)
# 创建数据预处理面板(使用测试目录,与数据采集共用根目录)
test_root = osp.join(osp.expanduser("~"), "data_collection_test") test_root = osp.join(osp.expanduser("~"), "data_collection_test")
panel = DataPreprocessPanel(root_path=test_root) panel = DataPreprocessPanel(root_path=test_root)
window.setCentralWidget(panel) window.setCentralWidget(panel)
# 创建测试文件夹和文件(如果不存在)
def setup_test_data(): def setup_test_data():
"""创建测试数据""" """创建测试数据"""
test_folder = osp.join(test_root, "测试视频文件夹") test_folder = osp.join(test_root, "测试视频文件夹")
if not osp.exists(test_folder): if not osp.exists(test_folder):
os.makedirs(test_folder, exist_ok=True) os.makedirs(test_folder, exist_ok=True)
print(f" 创建测试文件夹: {test_folder}")
# 创建一些空的测试视频文件(仅用于测试界面)
test_files = [ test_files = [
"test_video_1.mp4", "test_video_1.mp4",
"test_video_2.avi", "test_video_2.avi",
...@@ -1711,33 +1613,24 @@ if __name__ == "__main__": ...@@ -1711,33 +1613,24 @@ if __name__ == "__main__":
if not osp.exists(fpath): if not osp.exists(fpath):
with open(fpath, 'w') as f: with open(fpath, 'w') as f:
f.write("# 这是一个测试文件,仅用于界面测试") f.write("# 这是一个测试文件,仅用于界面测试")
print(f" 创建测试文件: {fname}")
print("\n[OK] 测试数据准备完成!")
print(f" 测试目录: {test_root}")
print(f" 请点击左侧的'测试视频文件夹'查看视频网格\n")
# 延迟创建测试数据(等待UI初始化)
QtCore.QTimer.singleShot(100, setup_test_data) QtCore.QTimer.singleShot(100, setup_test_data)
QtCore.QTimer.singleShot(200, panel.refreshFolders) QtCore.QTimer.singleShot(200, panel.refreshFolders)
# 连接信号测试
def on_folder_selected(folder_path): def on_folder_selected(folder_path):
print(f" 文件夹选中信号: {folder_path}") pass
def on_folder_added(folder_path): def on_folder_added(folder_path):
print(f" 文件夹添加信号: {folder_path}") pass
def on_folder_deleted(folder_path): def on_folder_deleted(folder_path):
print(f" 文件夹删除信号: {folder_path}") pass
def on_video_selected(video_path): def on_video_selected(video_path):
print(f" 视频选中信号: {video_path}") pass
def on_crop_started(crop_config): def on_crop_started(crop_config):
print(f" 裁剪开始信号:") pass
for key, value in crop_config.items():
print(f" {key}: {value}")
panel.folderSelected.connect(on_folder_selected) panel.folderSelected.connect(on_folder_selected)
panel.folderAdded.connect(on_folder_added) panel.folderAdded.connect(on_folder_added)
...@@ -1745,44 +1638,6 @@ if __name__ == "__main__": ...@@ -1745,44 +1638,6 @@ if __name__ == "__main__":
panel.videoSelected.connect(on_video_selected) panel.videoSelected.connect(on_video_selected)
panel.cropStarted.connect(on_crop_started) panel.cropStarted.connect(on_crop_started)
# 打印测试说明
print("\n" + "="*70)
print(" 数据预处理面板测试程序")
print("="*70)
print("[OK] 界面布局(两栏):")
print("\n 左侧面板 - 目录管理:")
print(" - 显示根目录下的所有子文件夹")
print(" - 点击文件夹:选中并加载视频列表")
print(" - 双击文件夹:在系统文件管理器中打开")
print(" - 新增文件夹按钮:创建新的数据处理文件夹")
print(" - 删除文件夹按钮:删除选中的文件夹(含内容)")
print(" - 底部显示文件夹总数统计")
print("\n 右侧面板 - 视频网格显示和裁剪:")
print(" - 顶部区域裁剪按钮:打开裁剪配置对话框")
print(" - 视频网格显示:以图标模式显示文件夹中的所有视频")
print(" - 点击视频:选中视频,启用裁剪按钮")
print(" - 双击视频:使用系统默认播放器打开")
print(" - 底部显示视频统计和当前选中的视频")
print("\n 区域裁剪对话框:")
print(" - 帧范围设置:起始帧、结束帧、采样间隔")
print(" - 裁剪区域设置:X、Y坐标、宽度、高度")
print(" - 保存设置:保存目录、文件名前缀、图片格式")
print(" - 完整帧选项:可选择使用完整帧不裁剪")
print("\n 功能特点:")
print(" - 使用 QSplitter 实现可调整宽度的两栏布局")
print(" - 自动创建根目录(默认: ~/data_preprocess)")
print(" - 自动识别视频文件格式(mp4, avi, mov, mkv等)")
print(" - 完整的信号机制用于外部集成")
print(" - 友好的错误提示和确认对话框")
print("\n 测试操作:")
print(" 1. 点击'新增文件夹'创建数据处理目录")
print(" 2. 点击文件夹,右侧显示视频网格")
print(" 3. 点击视频进行选中")
print(" 4. 点击'区域裁剪'按钮打开裁剪配置对话框")
print(" 5. 在对话框中设置帧数、裁剪区域和保存路径")
print(" 6. 点击'开始裁剪'执行裁剪任务")
print("="*70 + "\n")
window.show() window.show()
sys.exit(app.exec_()) sys.exit(app.exec_())
...@@ -68,20 +68,14 @@ class IntegratedDatasetPage(QtWidgets.QWidget): ...@@ -68,20 +68,14 @@ class IntegratedDatasetPage(QtWidgets.QWidget):
def _initHandlers(self): def _initHandlers(self):
"""初始化处理器""" """初始化处理器"""
print("\n[IntegratedDatasetPage] 初始化处理器...")
# 数据预处理处理器 # 数据预处理处理器
self.preprocess_handler = DataPreprocessHandler(self.preprocess_panel) self.preprocess_handler = DataPreprocessHandler(self.preprocess_panel)
print(" ✓ 数据预处理处理器已创建")
# 裁剪预览处理器 # 裁剪预览处理器
self.preview_handler = CropPreviewHandler(self.preview_panel) self.preview_handler = CropPreviewHandler(self.preview_panel)
print(" ✓ 裁剪预览处理器已创建")
def _connectSignals(self): def _connectSignals(self):
"""连接信号""" """连接信号"""
print("\n[IntegratedDatasetPage] 连接信号...")
# === 预处理面板信号 === # === 预处理面板信号 ===
# 文件夹被选中 # 文件夹被选中
...@@ -120,30 +114,21 @@ class IntegratedDatasetPage(QtWidgets.QWidget): ...@@ -120,30 +114,21 @@ class IntegratedDatasetPage(QtWidgets.QWidget):
# 切换区域 # 切换区域
self.preview_panel.regionChanged.connect(self._onRegionChanged) self.preview_panel.regionChanged.connect(self._onRegionChanged)
print(" ✓ 信号连接完成")
# ========== 数据预处理面板槽函数 ========== # ========== 数据预处理面板槽函数 ==========
def _onFolderSelected(self, folder_path): def _onFolderSelected(self, folder_path):
"""文件夹被选中""" """文件夹被选中"""
print(f"\n[Folder] 选中: {osp.basename(folder_path)}") pass
def _onVideoSelected(self, video_path): def _onVideoSelected(self, video_path):
"""视频被选中""" """视频被选中"""
print(f"\n[Video] 选中: {osp.basename(video_path)}") pass
# ========== 数据预处理处理器槽函数 ========== # ========== 数据预处理处理器槽函数 ==========
def _onCropStarted(self, config): def _onCropStarted(self, config):
"""裁剪任务开始""" """裁剪任务开始"""
save_liquid_data_path = config.get('save_liquid_data_path', '') save_liquid_data_path = config.get('save_liquid_data_path', '')
crop_frequency = config.get('crop_frequency', 1)
print(f"\n{'='*60}")
print(f"[Crop] 裁剪任务开始")
print(f" 保存路径: {save_liquid_data_path}")
print(f" 裁剪频率: 每 {crop_frequency} 帧")
print(f"{'='*60}")
# 启动预览监控 # 启动预览监控
self.preview_handler.startMonitoring(save_liquid_data_path) self.preview_handler.startMonitoring(save_liquid_data_path)
...@@ -153,16 +138,10 @@ class IntegratedDatasetPage(QtWidgets.QWidget): ...@@ -153,16 +138,10 @@ class IntegratedDatasetPage(QtWidgets.QWidget):
def _onCropProgress(self, progress): def _onCropProgress(self, progress):
"""裁剪进度更新""" """裁剪进度更新"""
if progress % 10 == 0: # 每10%打印一次 pass
print(f"[Crop] 进度: {progress}%")
def _onCropFinished(self, save_liquid_data_path): def _onCropFinished(self, save_liquid_data_path):
"""裁剪任务完成""" """裁剪任务完成"""
print(f"\n{'='*60}")
print(f"[Crop] 裁剪任务完成!")
print(f" 保存路径: {save_liquid_data_path}")
print(f"{'='*60}\n")
# 刷新预览显示 # 刷新预览显示
self.preview_handler.refreshPanel() self.preview_handler.refreshPanel()
...@@ -175,8 +154,6 @@ class IntegratedDatasetPage(QtWidgets.QWidget): ...@@ -175,8 +154,6 @@ class IntegratedDatasetPage(QtWidgets.QWidget):
def _onCropError(self, error_msg): def _onCropError(self, error_msg):
"""裁剪错误""" """裁剪错误"""
print(f"\n[ERROR] 裁剪失败: {error_msg}")
# 显示错误提示 # 显示错误提示
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, "裁剪失败", self, "裁剪失败",
...@@ -187,21 +164,21 @@ class IntegratedDatasetPage(QtWidgets.QWidget): ...@@ -187,21 +164,21 @@ class IntegratedDatasetPage(QtWidgets.QWidget):
def _onNewImageDetected(self, region_index, image_path): def _onNewImageDetected(self, region_index, image_path):
"""检测到新图片""" """检测到新图片"""
print(f"[Preview] 新图片: 区域{region_index+1} - {osp.basename(image_path)}") pass
def _onFolderChanged(self, folder_path): def _onFolderChanged(self, folder_path):
"""监控文件夹变化""" """监控文件夹变化"""
print(f"[Preview] 文件夹变化: {folder_path}") pass
# ========== 预览面板槽函数 ========== # ========== 预览面板槽函数 ==========
def _onImageSelected(self, image_path): def _onImageSelected(self, image_path):
"""图片被选中""" """图片被选中"""
print(f"[Preview] 图片选中: {osp.basename(image_path)}") pass
def _onRegionChanged(self, region_index): def _onRegionChanged(self, region_index):
"""切换区域""" """切换区域"""
print(f"[Preview] 切换到区域{region_index+1}") pass
def main(): def main():
...@@ -226,41 +203,6 @@ def main(): ...@@ -226,41 +203,6 @@ def main():
except: except:
pass pass
# 打印使用说明
print("\n" + "="*70)
print(" 裁剪图片预览集成测试程序")
print("="*70)
print("\n布局说明:")
print(" 左侧面板 - 数据预处理")
print(" • 目录管理:查看和管理视频文件夹")
print(" • 视频预览:预览选中的视频")
print(" • 区域裁剪:配置裁剪参数并执行裁剪")
print("\n 右侧面板 - 裁剪预览")
print(" • 实时监控:自动检测新生成的裁剪图片")
print(" • 多区域显示:支持最多3个裁剪区域")
print(" • 图片预览:网格显示缩略图,双击查看大图")
print("\n使用流程:")
print(" 1. 在左侧选择包含视频的文件夹")
print(" 2. 点击视频文件进行预览")
print(" 3. 点击'区域裁剪'按钮配置裁剪参数")
print(" 4. 在视频预览区域画框选择裁剪区域(最多3个)")
print(" 5. 按 C 键确认裁剪配置")
print(" 6. 在弹出的对话框中设置保存路径和参数")
print(" 7. 点击'开始裁剪'执行任务")
print(" 8. 右侧预览面板会实时显示裁剪生成的图片")
print("\n快捷键:")
print(" • 画框模式:鼠标拖动绘制裁剪区域")
print(" • C 键:确认当前裁剪配置")
print(" • R 键:重置所有裁剪框")
print("\n功能特性:")
print(" ✓ 实时监控文件夹变化")
print(" ✓ 自动更新图片显示")
print(" ✓ 支持多区域独立显示")
print(" ✓ 双击图片查看原始大小")
print(" ✓ 显示详细统计信息")
print("="*70 + "\n")
# 显示窗口
window.show() window.show()
# 运行应用 # 运行应用
......
...@@ -24,10 +24,6 @@ from annotationtool import AnnotationTool ...@@ -24,10 +24,6 @@ from annotationtool import AnnotationTool
def test_labelme_integration(): def test_labelme_integration():
"""测试labelme集成""" """测试labelme集成"""
print("\n" + "="*70)
print(" Labelme集成测试")
print("="*70)
# 创建应用 # 创建应用
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
...@@ -37,22 +33,10 @@ def test_labelme_integration(): ...@@ -37,22 +33,10 @@ def test_labelme_integration():
window.resize(1600, 900) window.resize(1600, 900)
# 创建标注工具 # 创建标注工具
print("\n[1/4] 创建AnnotationTool实例...")
annotation_tool = AnnotationTool() annotation_tool = AnnotationTool()
window.setCentralWidget(annotation_tool) window.setCentralWidget(annotation_tool)
# 检查labelme是否成功初始化
print("\n[2/4] 检查Labelme初始化状态...")
if annotation_tool.labelme_widget is not None:
print(" Labelme已成功嵌入")
print(f" - Labelme实例类型: {type(annotation_tool.labelme_widget).__name__}")
print(f" - Labelme容器: {type(annotation_tool.labelme_container).__name__}")
else:
print(" Labelme未能初始化")
print(" 请检查labelme是否已安装: pip install labelme")
# 添加测试数据 # 添加测试数据
print("\n[3/4] 添加测试数据到列表...")
test_images = [ test_images = [
{ {
"name": "sample_001.jpg", "name": "sample_001.jpg",
...@@ -81,8 +65,6 @@ def test_labelme_integration(): ...@@ -81,8 +65,6 @@ def test_labelme_integration():
item.setText(f" {img_data['name']}\n{img_data['resolution']}") item.setText(f" {img_data['name']}\n{img_data['resolution']}")
item.setData(Qt.UserRole, img_data) item.setData(Qt.UserRole, img_data)
print(f" 已添加 {len(test_images)} 个测试图片")
# 更新统计 # 更新统计
annotation_tool.lbl_total_stats.setText(f"总数: {len(test_images)}") annotation_tool.lbl_total_stats.setText(f"总数: {len(test_images)}")
annotation_tool.lbl_annotated_stats.setText("已标注: 0") annotation_tool.lbl_annotated_stats.setText("已标注: 0")
...@@ -90,7 +72,6 @@ def test_labelme_integration(): ...@@ -90,7 +72,6 @@ def test_labelme_integration():
# 连接列表点击事件(演示如何加载图片) # 连接列表点击事件(演示如何加载图片)
def on_item_clicked(item): def on_item_clicked(item):
data = item.data(Qt.UserRole) data = item.data(Qt.UserRole)
print(f"\n 点击了图片: {data['name']}")
# 更新详细信息 # 更新详细信息
annotation_tool.lbl_image_name.setText(data["name"]) annotation_tool.lbl_image_name.setText(data["name"])
...@@ -102,36 +83,10 @@ def test_labelme_integration(): ...@@ -102,36 +83,10 @@ def test_labelme_integration():
# 如果图片存在,加载到labelme # 如果图片存在,加载到labelme
if osp.exists(data["path"]): if osp.exists(data["path"]):
print(f" 加载图片到labelme: {data['path']}")
annotation_tool.loadImageForAnnotation(data["path"]) annotation_tool.loadImageForAnnotation(data["path"])
else:
print(f" ️ 图片不存在: {data['path']}")
print(" (这是测试数据,实际使用时需要提供真实图片路径)")
annotation_tool.annotation_list.itemClicked.connect(on_item_clicked) annotation_tool.annotation_list.itemClicked.connect(on_item_clicked)
# 显示使用说明
print("\n[4/4] 启动测试窗口...")
print("\n" + "-"*70)
print(" 使用说明")
print("-"*70)
print("\n 界面布局:")
print(" 左侧: 标注数据列表")
print(" 右侧: Labelme标注工具")
print("\n 测试步骤:")
print(" 1. 查看右侧是否显示labelme界面")
print(" 2. 点击左侧列表中的图片项")
print(" 3. 观察详细信息是否更新")
print(" 4. 测试工具栏按钮(放大、缩小、适应窗口)")
print(" 5. 如果有真实图片,可以在labelme中进行标注")
print("\n 加载自定义图片:")
print(" 在右侧labelme中点击 '打开' 或 '打开目录' 加载图片")
print("\n 快捷键:")
print(" - Ctrl+O: 打开图片")
print(" - Ctrl+S: 保存标注")
print(" - 更多快捷键请参考labelme工具栏")
print("-"*70)
# 显示窗口 # 显示窗口
window.show() window.show()
...@@ -157,9 +112,6 @@ def test_labelme_integration(): ...@@ -157,9 +112,6 @@ def test_labelme_integration():
"详细错误信息请查看控制台。" "详细错误信息请查看控制台。"
) )
print("\n 测试窗口已启动")
print("="*70 + "\n")
sys.exit(app.exec_()) sys.exit(app.exec_())
......
...@@ -560,16 +560,11 @@ if __name__ == "__main__": ...@@ -560,16 +560,11 @@ if __name__ == "__main__":
panel = TrainingPanel() panel = TrainingPanel()
window.setCentralWidget(panel) window.setCentralWidget(panel)
# 连接信号测试
def on_start_training(params): def on_start_training(params):
print(f"开始训练:")
for key, value in params.items():
print(f" {key}: {value}")
panel.append_training_log("训练已开始...\n") panel.append_training_log("训练已开始...\n")
panel.set_training_active(True) panel.set_training_active(True)
def on_stop_training(): def on_stop_training():
print("停止训练")
panel.append_training_log("训练已停止\n") panel.append_training_log("训练已停止\n")
panel.set_training_active(False) panel.set_training_active(False)
......
...@@ -270,7 +270,6 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -270,7 +270,6 @@ class VideoBrowser(QtWidgets.QWidget):
path: 根目录路径 path: 根目录路径
""" """
if not osp.exists(path): if not osp.exists(path):
print(f" 路径不存在: {path}")
return False return False
self._root_path = path self._root_path = path
...@@ -283,7 +282,6 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -283,7 +282,6 @@ class VideoBrowser(QtWidgets.QWidget):
# 展开根节点 # 展开根节点
self.tree_view.expand(root_index) self.tree_view.expand(root_index)
print(f" 设置根目录: {path}")
return True return True
def getRootPath(self): def getRootPath(self):
...@@ -316,7 +314,7 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -316,7 +314,7 @@ class VideoBrowser(QtWidgets.QWidget):
if ext in self._video_extensions: if ext in self._video_extensions:
videos.append(file_path) videos.append(file_path)
except Exception as e: except Exception as e:
print(f" 获取视频列表失败: {e}") return []
return videos return videos
...@@ -362,13 +360,10 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -362,13 +360,10 @@ class VideoBrowser(QtWidgets.QWidget):
# 发送信号 # 发送信号
self.videoSelected.emit(video_files[0]) self.videoSelected.emit(video_files[0])
print(f" 加载视频文件: {video_count} 个,当前: {osp.basename(video_files[0])}")
else: else:
print(f" 文件夹中没有视频文件")
self.preview_label.setText("该文件夹中没有视频文件") self.preview_label.setText("该文件夹中没有视频文件")
except Exception as e: except Exception as e:
print(f" 加载视频失败: {e}")
self.stats_label.setText("加载失败") self.stats_label.setText("加载失败")
def _clearVideoInfo(self): def _clearVideoInfo(self):
...@@ -413,8 +408,6 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -413,8 +408,6 @@ class VideoBrowser(QtWidgets.QWidget):
self.btn_play.setEnabled(True) self.btn_play.setEnabled(True)
self.btn_open_folder.setEnabled(True) self.btn_open_folder.setEnabled(True)
print(f" 更新视频信息: {file_name}")
# ========== 槽函数 ========== # ========== 槽函数 ==========
def _onFolderClicked(self, index): def _onFolderClicked(self, index):
...@@ -423,7 +416,6 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -423,7 +416,6 @@ class VideoBrowser(QtWidgets.QWidget):
return return
folder_path = self.file_model.filePath(index) folder_path = self.file_model.filePath(index)
print(f" 点击文件夹: {folder_path}")
# 加载该文件夹中的视频 # 加载该文件夹中的视频
self._loadVideosFromFolder(folder_path) self._loadVideosFromFolder(folder_path)
...@@ -447,7 +439,6 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -447,7 +439,6 @@ class VideoBrowser(QtWidgets.QWidget):
current_folder = self.getCurrentFolder() current_folder = self.getCurrentFolder()
if current_folder: if current_folder:
self._loadVideosFromFolder(current_folder) self._loadVideosFromFolder(current_folder)
print(" 刷新文件夹")
def _onSelectRoot(self): def _onSelectRoot(self):
"""选择根目录""" """选择根目录"""
...@@ -475,10 +466,7 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -475,10 +466,7 @@ class VideoBrowser(QtWidgets.QWidget):
elif os.name == 'posix': # macOS 或 Linux elif os.name == 'posix': # macOS 或 Linux
import subprocess import subprocess
subprocess.Popen(['xdg-open', self._current_video_path]) subprocess.Popen(['xdg-open', self._current_video_path])
print(f"▶ 播放视频: {osp.basename(self._current_video_path)}")
except Exception as e: except Exception as e:
print(f" 播放视频失败: {e}")
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self,
"播放失败", "播放失败",
...@@ -499,10 +487,8 @@ class VideoBrowser(QtWidgets.QWidget): ...@@ -499,10 +487,8 @@ class VideoBrowser(QtWidgets.QWidget):
elif os.name == 'posix': # macOS 或 Linux elif os.name == 'posix': # macOS 或 Linux
import subprocess import subprocess
subprocess.Popen(['xdg-open', folder_path]) subprocess.Popen(['xdg-open', folder_path])
print(f" 打开文件夹: {folder_path}")
except Exception as e: except Exception as e:
print(f" 打开文件夹失败: {e}") pass
if __name__ == "__main__": if __name__ == "__main__":
...@@ -520,52 +506,19 @@ if __name__ == "__main__": ...@@ -520,52 +506,19 @@ if __name__ == "__main__":
video_browser = VideoBrowser() video_browser = VideoBrowser()
window.setCentralWidget(video_browser) window.setCentralWidget(video_browser)
# 连接信号测试
def on_folder_selected(folder_path): def on_folder_selected(folder_path):
print(f" 选中文件夹: {folder_path}") pass
def on_video_selected(video_path): def on_video_selected(video_path):
print(f" 选中视频: {video_path}") pass
def on_video_played(video_path): def on_video_played(video_path):
print(f"▶ 播放视频: {video_path}") pass
video_browser.folderSelected.connect(on_folder_selected) video_browser.folderSelected.connect(on_folder_selected)
video_browser.videoSelected.connect(on_video_selected) video_browser.videoSelected.connect(on_video_selected)
video_browser.videoPlayed.connect(on_video_played) video_browser.videoPlayed.connect(on_video_played)
# 打印测试说明
print("\n" + "="*70)
print(" VideoBrowser 视频浏览器测试程序")
print("="*70)
print(" 组件功能:")
print("\n 左侧面板 - 文件夹浏览:")
print(" - 显示目录树结构")
print(" - 点击文件夹自动加载第一个视频")
print(" - 双击文件夹展开/折叠")
print(" - 点击'选择根目录'切换根路径")
print(" - 点击'刷新'重新加载")
print(" - 显示统计信息(文件夹数、视频数)")
print("\n 右侧面板 - 视频预览:")
print(" - 视频预览区域(黑色背景)")
print(" - 自动显示第一个视频的信息")
print(" - 支持格式: .mp4, .avi, .mkv, .mov, .wmv, .flv, .webm, .m4v")
print(" - 点击'播放'按钮使用系统播放器打开")
print(" - 点击'打开文件夹'在资源管理器中查看")
print("\n 视频信息:")
print(" - 文件名")
print(" - 文件大小(MB/GB)")
print(" - 完整路径")
print("\n 信号:")
print(" - folderSelected: 文件夹被选中")
print(" - videoSelected: 视频被自动加载")
print(" - videoPlayed: 视频开始播放")
print("\n 提示:")
print(" - 可以通过代码设置自定义根目录")
print(" - 支持拖拽分割器调整左右面板大小")
print(" - 点击文件夹自动加载该文件夹中的第一个视频")
print("="*70 + "\n")
window.show() window.show()
sys.exit(app.exec_()) sys.exit(app.exec_())
...@@ -340,7 +340,6 @@ if __name__ == "__main__": ...@@ -340,7 +340,6 @@ if __name__ == "__main__":
video_clipper = VideoClipper() video_clipper = VideoClipper()
window.setCentralWidget(video_clipper) window.setCentralWidget(video_clipper)
# 添加测试数据到照片目录
test_folders = [ test_folders = [
("项目A", 25), ("项目A", 25),
("项目B", 18), ("项目B", 18),
...@@ -370,39 +369,8 @@ if __name__ == "__main__": ...@@ -370,39 +369,8 @@ if __name__ == "__main__":
video_clipper.photo_tree.setColumnWidth(0, 150) video_clipper.photo_tree.setColumnWidth(0, 150)
video_clipper.photo_tree.setColumnWidth(1, 60) video_clipper.photo_tree.setColumnWidth(1, 60)
# 更新统计信息
video_clipper.lbl_photo_stats.setText(f"照片: {sum(c for _, c in test_folders)} | 文件夹: {len(test_folders)}") video_clipper.lbl_photo_stats.setText(f"照片: {sum(c for _, c in test_folders)} | 文件夹: {len(test_folders)}")
# 打印测试说明
print("\n" + "="*70)
print(" VideoClipper 视频裁剪器组件测试程序")
print("="*70)
print(" 界面布局(三栏):")
print("\n 左侧面板 - 照片目录:")
print(" - 树形结构显示文件夹")
print(" - 显示每个文件夹的照片数量")
print(" - 刷新按钮")
print(" - 底部统计信息")
print("\n 中间面板 - 裁剪图片展示:")
print(" - 滚动区域显示裁剪的图片")
print(" - 清空和保存按钮")
print(" - 底部统计裁剪数量")
print("\n 右侧面板 - 视频预览:")
print(" - 视频预览显示区(黑色背景)")
print(" - 视频信息卡片(文件名、大小、时长、分辨率)")
print(" - 控制按钮(选择视频、播放/暂停、裁剪当前帧)")
print(" - 进度条")
print(" - 时间显示(当前时间 / 总时长)")
print("\n 布局特点:")
print(" - 使用 QSplitter 实现可调整宽度的三栏布局")
print(" - 默认比例: 左:中:右 = 1:2:2")
print(" - 可以拖拽分割线调整各面板宽度")
print("\n 说明:")
print(" - 当前为纯UI界面,不包含功能实现")
print(" - 所有按钮和控件已预留,可后续添加功能")
print(" - 界面风格统一,适配现有系统")
print("="*70 + "\n")
window.show() window.show()
sys.exit(app.exec_()) sys.exit(app.exec_())
...@@ -203,7 +203,6 @@ if __name__ == "__main__": ...@@ -203,7 +203,6 @@ if __name__ == "__main__":
menubar = MenuBar(main_window) menubar = MenuBar(main_window)
main_window.setMenuBar(menubar) main_window.setMenuBar(menubar)
# 添加测试菜单项(带图标)
menubar.addFileAction( menubar.addFileAction(
"open", "打开", "open", "打开",
lambda: print("打开文件"), lambda: print("打开文件"),
......
...@@ -104,9 +104,11 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -104,9 +104,11 @@ class ModelSetPage(QtWidgets.QWidget):
self._connectSignals() self._connectSignals()
self._setupShortcuts() self._setupShortcuts()
# 使用延迟加载确保 UI 完全初始化后再加载模型 # 移除自动加载,改为手动加载模式
# 这样可以避免 handler 未初始化的问题 # 用户可以通过以下方式加载模型:
QtCore.QTimer.singleShot(100, self.loadModelsFromConfig) # 1. 按 F5 刷新
# 2. 右键点击空白区域刷新
# 3. 点击刷新按钮(如果有)
def _initUI(self): def _initUI(self):
"""初始化UI - 简约labelme风格(三栏充实布局版)""" """初始化UI - 简约labelme风格(三栏充实布局版)"""
...@@ -331,7 +333,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -331,7 +333,6 @@ class ModelSetPage(QtWidgets.QWidget):
item = self.model_set_list.itemAt(pos) item = self.model_set_list.itemAt(pos)
if item is None: if item is None:
# 右键点击了空白区域,触发刷新 # 右键点击了空白区域,触发刷新
print("[ModelSetPage] 检测到空白区域右键点击,刷新模型列表")
self.loadModelsFromConfig() self.loadModelsFromConfig()
return True return True
return super(ModelSetPage, self).eventFilter(obj, event) return super(ModelSetPage, self).eventFilter(obj, event)
...@@ -467,11 +468,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -467,11 +468,6 @@ class ModelSetPage(QtWidgets.QWidget):
- classes: 类别文件路径(可选) - classes: 类别文件路径(可选)
- description: 模型描述(可选) - description: 模型描述(可选)
""" """
print("="*70)
print(" [ModelSetPage] 接收到新模型创建信号")
print(f" 模型信息: {model_info}")
print("="*70)
try: try:
# 1. 验证模型信息 # 1. 验证模型信息
model_name = model_info.get('name', '').strip() model_name = model_info.get('name', '').strip()
...@@ -556,7 +552,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -556,7 +552,6 @@ class ModelSetPage(QtWidgets.QWidget):
# 6. 添加到模型参数字典 # 6. 添加到模型参数字典
self._model_params[model_name] = model_params self._model_params[model_name] = model_params
print(f" [ModelSetPage] 已添加模型参数: {model_name}")
# 7. 添加到列表显示 # 7. 添加到列表显示
# 先检查是否已存在于列表中 # 先检查是否已存在于列表中
...@@ -568,7 +563,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -568,7 +563,6 @@ class ModelSetPage(QtWidgets.QWidget):
if model_name not in existing_items: if model_name not in existing_items:
self.addModelToList(model_name) self.addModelToList(model_name)
print(f" [ModelSetPage] 已添加到列表: {model_name}")
else: else:
# 更新现有项 # 更新现有项
for i in range(self.model_set_list.count()): for i in range(self.model_set_list.count()):
...@@ -578,7 +572,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -578,7 +572,6 @@ class ModelSetPage(QtWidgets.QWidget):
# 保留(默认)标记 # 保留(默认)标记
if "(默认)" in item_text: if "(默认)" in item_text:
self.model_set_list.item(i).setText(f"{model_name}(默认)") self.model_set_list.item(i).setText(f"{model_name}(默认)")
print(f" [ModelSetPage] 已更新列表项: {model_name}")
break break
# 8. 选中新创建的模型 # 8. 选中新创建的模型
...@@ -599,11 +592,7 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -599,11 +592,7 @@ class ModelSetPage(QtWidgets.QWidget):
f"模型已添加到模型列表中。" f"模型已添加到模型列表中。"
) )
print(f"✅ [ModelSetPage] 新模型 '{model_name}' 创建成功!")
print("="*70)
except Exception as e: except Exception as e:
print(f" [ERROR] 创建新模型失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
showCritical( showCritical(
...@@ -619,7 +608,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -619,7 +608,6 @@ class ModelSetPage(QtWidgets.QWidget):
# 发射信号通知外部模型已被选中 # 发射信号通知外部模型已被选中
self.modelSetClicked.emit(display_name) self.modelSetClicked.emit(display_name)
print(f"✅ [ModelSetPage] 模型已选中: {model_name}")
def _onModelSetDoubleClicked(self, item): def _onModelSetDoubleClicked(self, item):
"""模型集列表项被双击""" """模型集列表项被双击"""
...@@ -772,30 +760,23 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -772,30 +760,23 @@ class ModelSetPage(QtWidgets.QWidget):
def refreshModelList(self): def refreshModelList(self):
"""刷新模型列表显示""" """刷新模型列表显示"""
try: try:
print(f"🔄 [UI刷新] 开始刷新模型列表,当前模型参数数量: {len(self._model_params)}")
# 清空现有列表 # 清空现有列表
self.model_set_list.clear() self.model_set_list.clear()
# 重新添加所有模型 # 重新添加所有模型
for model_name in self._model_params.keys(): for model_name in self._model_params.keys():
print(f"🔄 [UI刷新] 添加模型到列表: {model_name}")
self.model_set_list.addItem(model_name) self.model_set_list.addItem(model_name)
# 如果是默认模型,添加标记 # 如果是默认模型,添加标记
if model_name == self._current_default_model: if model_name == self._current_default_model:
item = self.model_set_list.item(self.model_set_list.count() - 1) item = self.model_set_list.item(self.model_set_list.count() - 1)
item.setText(f"{model_name} [默认]") item.setText(f"{model_name} [默认]")
print(f"✅ [UI刷新] 标记默认模型: {model_name}")
# 更新统计信息 # 更新统计信息
self._updateStats() self._updateStats()
self._updateModelOrder() self._updateModelOrder()
print(f"✅ [UI刷新] 模型列表刷新完成,显示 {self.model_set_list.count()} 个模型")
except Exception as e: except Exception as e:
print(f"❌ [UI刷新] 刷新模型列表时发生异常: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -1112,11 +1093,9 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1112,11 +1093,9 @@ class ModelSetPage(QtWidgets.QWidget):
try: try:
# 优先委托给 handler 处理 # 优先委托给 handler 处理
if self._parent and hasattr(self._parent, 'model_set_handler'): if self._parent and hasattr(self._parent, 'model_set_handler'):
print("[OK] 使用 handler 加载模型")
self._parent.model_set_handler.loadModelsFromConfig() self._parent.model_set_handler.loadModelsFromConfig()
else: else:
# 备用方案:如果 handler 未初始化,使用本地方法加载 # 备用方案:如果 handler 未初始化,使用本地方法加载
print("[警告] handler 未初始化,使用本地方法加载模型")
self._loadModelsLocally() self._loadModelsLocally()
except Exception as e: except Exception as e:
...@@ -1131,7 +1110,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1131,7 +1110,6 @@ class ModelSetPage(QtWidgets.QWidget):
# 1. 加载配置文件 # 1. 加载配置文件
config = self._loadConfigFile() config = self._loadConfigFile()
if not config: if not config:
print("[警告] 无法加载配置文件")
return return
# 2. 从配置文件提取通道模型 # 2. 从配置文件提取通道模型
...@@ -1161,11 +1139,9 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1161,11 +1139,9 @@ class ModelSetPage(QtWidgets.QWidget):
if len(all_models) > 0: if len(all_models) > 0:
self.model_set_list.setCurrentRow(0) self.model_set_list.setCurrentRow(0)
print(f"[OK] 本地加载完成,共加载 {len(all_models)} 个模型")
self._updateModelOrder() self._updateModelOrder()
except Exception as e: except Exception as e:
print(f"[错误] 本地加载模型失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -1176,17 +1152,13 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1176,17 +1152,13 @@ class ModelSetPage(QtWidgets.QWidget):
config_path = current_dir / "database" / "config" / "default_config.yaml" config_path = current_dir / "database" / "config" / "default_config.yaml"
if not config_path.exists(): if not config_path.exists():
print(f"[警告] 配置文件不存在: {config_path}")
return None return None
print(f"[信息] 正在加载配置文件: {config_path}")
with open(config_path, 'r', encoding='utf-8') as f: with open(config_path, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f) config = yaml.safe_load(f)
print(f"[信息] 配置文件加载成功")
return config return config
except Exception as e: except Exception as e:
print(f"[错误] 加载配置文件失败: {e}")
return None return None
def _extractChannelModels(self, config): def _extractChannelModels(self, config):
...@@ -1224,9 +1196,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1224,9 +1196,6 @@ class ModelSetPage(QtWidgets.QWidget):
'source': 'config', 'source': 'config',
'is_default': i == 1 # channel1 作为默认 'is_default': i == 1 # channel1 作为默认
}) })
print(f" [信息] 找到通道{i}模型: {model_path}")
elif model_path:
print(f" [警告] 通道{i}模型路径不存在: {model_path}")
return models return models
...@@ -1247,11 +1216,8 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1247,11 +1216,8 @@ class ModelSetPage(QtWidgets.QWidget):
for model_dir, dir_type in model_dirs: for model_dir, dir_type in model_dirs:
if not model_dir.exists(): if not model_dir.exists():
print(f"[信息] {dir_type}目录不存在: {model_dir}")
continue continue
print(f"[信息] 正在扫描{dir_type}目录: {model_dir}")
# 遍历所有子目录,并按目录名排序(确保模型1最先) # 遍历所有子目录,并按目录名排序(确保模型1最先)
sorted_subdirs = sorted(model_dir.iterdir(), key=lambda x: x.name if x.is_dir() else '') sorted_subdirs = sorted(model_dir.iterdir(), key=lambda x: x.name if x.is_dir() else '')
...@@ -1267,7 +1233,6 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1267,7 +1233,6 @@ class ModelSetPage(QtWidgets.QWidget):
'format': 'dat', 'format': 'dat',
'model_type': dir_type 'model_type': dir_type
}) })
print(f"[信息] 找到{dir_type}: {model_file}")
# 然后查找 .pt 文件 # 然后查找 .pt 文件
for model_file in sorted(subdir.glob("*.pt")): for model_file in sorted(subdir.glob("*.pt")):
...@@ -1279,12 +1244,8 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1279,12 +1244,8 @@ class ModelSetPage(QtWidgets.QWidget):
'format': 'pt', 'format': 'pt',
'model_type': dir_type 'model_type': dir_type
}) })
print(f"[信息] 找到{dir_type}: {model_file}")
print(f"[信息] 模型扫描完成,共找到 {len(models)} 个模型")
except Exception as e: except Exception as e:
print(f"[错误] 扫描模型目录失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -1451,16 +1412,13 @@ class ModelSetPage(QtWidgets.QWidget): ...@@ -1451,16 +1412,13 @@ class ModelSetPage(QtWidgets.QWidget):
if config_path.exists(): if config_path.exists():
import shutil import shutil
shutil.copy2(config_path, backup_path) shutil.copy2(config_path, backup_path)
print(f" [信息] 已备份配置文件: {backup_path}")
# 保存新配置 # 保存新配置
with open(config_path, 'w', encoding='utf-8') as f: with open(config_path, 'w', encoding='utf-8') as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True, indent=2) yaml.dump(config, f, default_flow_style=False, allow_unicode=True, indent=2)
print(f" [信息] 配置文件已保存: {config_path}")
return True return True
except Exception as e: except Exception as e:
print(f" [错误] 保存配置文件失败: {e}")
return False return False
...@@ -1470,7 +1428,6 @@ if __name__ == "__main__": ...@@ -1470,7 +1428,6 @@ if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
# 测试模型参数数据
test_model_params = { test_model_params = {
"预训练模型1": { "预训练模型1": {
"name": "预训练模型1(默认)", "name": "预训练模型1(默认)",
...@@ -1536,11 +1493,6 @@ if __name__ == "__main__": ...@@ -1536,11 +1493,6 @@ if __name__ == "__main__":
page.addModelToList("预训练模型2") page.addModelToList("预训练模型2")
page.addModelToList("预训练模型3") page.addModelToList("预训练模型3")
# 连接信号
page.modelSetClicked.connect(lambda name: print(f" 点击模型: {name}"))
page.addSetClicked.connect(lambda: print(" 添加模型集"))
page.modelSettingsClicked.connect(lambda: print(" 模型设置"))
window.show() window.show()
sys.exit(app.exec_()) sys.exit(app.exec_())
...@@ -104,14 +104,12 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -104,14 +104,12 @@ class TrainingPage(QtWidgets.QWidget):
if self._log_font_size < 14: # 最大字体大小限制 if self._log_font_size < 14: # 最大字体大小限制
self._log_font_size += 1 self._log_font_size += 1
self._updateLogFontSize() self._updateLogFontSize()
print(f"[日志字体] 字体大小增加到: {self._log_font_size}pt")
def _decreaseFontSize(self): def _decreaseFontSize(self):
"""减少日志字体大小""" """减少日志字体大小"""
if self._log_font_size > 6: # 最小字体大小限制 if self._log_font_size > 6: # 最小字体大小限制
self._log_font_size -= 1 self._log_font_size -= 1
self._updateLogFontSize() self._updateLogFontSize()
print(f"[日志字体] 字体大小减少到: {self._log_font_size}pt")
def _updateLogFontSize(self): def _updateLogFontSize(self):
"""更新日志字体大小""" """更新日志字体大小"""
...@@ -132,7 +130,6 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -132,7 +130,6 @@ class TrainingPage(QtWidgets.QWidget):
"""清空日志内容""" """清空日志内容"""
self.train_log_text.clear() self.train_log_text.clear()
self.train_log_text.setPlainText("日志已清空...\n系统已就绪,请配置参数后点击\"开始升级\"按钮。") self.train_log_text.setPlainText("日志已清空...\n系统已就绪,请配置参数后点击\"开始升级\"按钮。")
print("[日志] 日志内容已清空")
def _initUI(self): def _initUI(self):
"""初始化UI""" """初始化UI"""
...@@ -158,7 +155,7 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -158,7 +155,7 @@ class TrainingPage(QtWidgets.QWidget):
ResponsiveLayout.apply_to_widget(params_group, min_height=380, max_height=420) ResponsiveLayout.apply_to_widget(params_group, min_height=380, max_height=420)
left_layout.addWidget(params_group, 0) # 不设置伸缩因子,保持固定尺寸 left_layout.addWidget(params_group, 0) # 不设置伸缩因子,保持固定尺寸
# === 模型测试区域 === # 模型测试区域
test_group = QtWidgets.QWidget() test_group = QtWidgets.QWidget()
test_group.setStyleSheet(""" test_group.setStyleSheet("""
...@@ -254,12 +251,9 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -254,12 +251,9 @@ class TrainingPage(QtWidgets.QWidget):
# 将视频面板添加到显示布局中 # 将视频面板添加到显示布局中
display_layout.addWidget(self.video_panel) display_layout.addWidget(self.video_panel)
print(f"[视频面板] 已创建并添加到显示布局")
# 🔥 设置整体窗口的最小尺寸 - 使用响应式布局 # 🔥 设置整体窗口的最小尺寸 - 使用响应式布局
min_w, min_h = scale_w(1000), scale_h(700) min_w, min_h = scale_w(1000), scale_h(700)
self.setMinimumSize(min_w, min_h) self.setMinimumSize(min_w, min_h)
print(f"[窗口] 最小尺寸设置: {min_w}x{min_h} (响应式)")
# 将左侧显示面板添加到 splitter # 将左侧显示面板添加到 splitter
test_group_splitter.addWidget(left_display_widget) test_group_splitter.addWidget(left_display_widget)
...@@ -279,7 +273,6 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -279,7 +273,6 @@ class TrainingPage(QtWidgets.QWidget):
right_control_layout = QtWidgets.QVBoxLayout(right_control_widget) right_control_layout = QtWidgets.QVBoxLayout(right_control_widget)
ResponsiveLayout.apply_to_layout(right_control_layout, base_spacing=12, base_margins=12) ResponsiveLayout.apply_to_layout(right_control_layout, base_spacing=12, base_margins=12)
# 测试模型选择
test_model_layout = QtWidgets.QVBoxLayout() test_model_layout = QtWidgets.QVBoxLayout()
from ..responsive_layout import scale_spacing from ..responsive_layout import scale_spacing
test_model_layout.setSpacing(scale_spacing(5)) test_model_layout.setSpacing(scale_spacing(5))
...@@ -309,7 +302,6 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -309,7 +302,6 @@ class TrainingPage(QtWidgets.QWidget):
test_model_layout.addWidget(self.test_model_combo) test_model_layout.addWidget(self.test_model_combo)
right_control_layout.addLayout(test_model_layout) right_control_layout.addLayout(test_model_layout)
# 测试文件选择
test_file_layout = QtWidgets.QVBoxLayout() test_file_layout = QtWidgets.QVBoxLayout()
from ..responsive_layout import scale_spacing from ..responsive_layout import scale_spacing
test_file_layout.setSpacing(scale_spacing(5)) test_file_layout.setSpacing(scale_spacing(5))
...@@ -342,16 +334,13 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -342,16 +334,13 @@ class TrainingPage(QtWidgets.QWidget):
# 添加垂直间距 # 添加垂直间距
right_control_layout.addSpacing(20) right_control_layout.addSpacing(20)
# 测试按钮区域(水平布局,与"开始升级"按钮保持一致)
test_button_layout = QtWidgets.QHBoxLayout() test_button_layout = QtWidgets.QHBoxLayout()
ResponsiveLayout.apply_to_layout(test_button_layout, base_spacing=10, base_margins=0) ResponsiveLayout.apply_to_layout(test_button_layout, base_spacing=10, base_margins=0)
# 开始标注按钮(使用系统默认样式 + 响应式布局)
self.start_annotation_btn = QtWidgets.QPushButton("开始标注") self.start_annotation_btn = QtWidgets.QPushButton("开始标注")
self.start_annotation_btn.setMinimumWidth(scale_w(80)) self.start_annotation_btn.setMinimumWidth(scale_w(80))
test_button_layout.addWidget(self.start_annotation_btn) test_button_layout.addWidget(self.start_annotation_btn)
# 开始测试按钮(使用系统默认样式 + 响应式布局)
self.start_test_btn = QtWidgets.QPushButton("开始测试") self.start_test_btn = QtWidgets.QPushButton("开始测试")
self.start_test_btn.setMinimumWidth(scale_w(80)) self.start_test_btn.setMinimumWidth(scale_w(80))
test_button_layout.addWidget(self.start_test_btn) test_button_layout.addWidget(self.start_test_btn)
...@@ -362,7 +351,6 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -362,7 +351,6 @@ class TrainingPage(QtWidgets.QWidget):
# 底部弹性空间 # 底部弹性空间
right_control_layout.addStretch() right_control_layout.addStretch()
# 初始化测试状态标志
self._is_testing = False self._is_testing = False
# 将右侧控件添加到 splitter # 将右侧控件添加到 splitter
...@@ -374,8 +362,7 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -374,8 +362,7 @@ class TrainingPage(QtWidgets.QWidget):
test_group_splitter.setStretchFactor(0, 6) # 左侧伸缩因子(6:1 比例) test_group_splitter.setStretchFactor(0, 6) # 左侧伸缩因子(6:1 比例)
test_group_splitter.setStretchFactor(1, 1) # 右侧伸缩因子 test_group_splitter.setStretchFactor(1, 1) # 右侧伸缩因子
# 将测试组添加到左侧布局,设置伸缩因子为1,让它占据剩余空间 left_layout.addWidget(test_group, 1)
left_layout.addWidget(test_group, 1) # 🔥 设置伸缩因子为1,让测试组占据剩余空间
# === 右侧:日志输出区 === # === 右侧:日志输出区 ===
right_widget = QtWidgets.QWidget() right_widget = QtWidgets.QWidget()
...@@ -467,12 +454,10 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -467,12 +454,10 @@ class TrainingPage(QtWidgets.QWidget):
right_min_w = scale_w(500) right_min_w = scale_w(500)
left_widget.setMinimumWidth(left_min_w) # 左侧最小宽度,保证参数文字可读 left_widget.setMinimumWidth(left_min_w) # 左侧最小宽度,保证参数文字可读
right_widget.setMinimumWidth(right_min_w) # 增加右侧最小宽度,确保训练指标在同一行显示 right_widget.setMinimumWidth(right_min_w) # 增加右侧最小宽度,确保训练指标在同一行显示
print(f"[分栏器] 最小尺寸: 左侧={left_min_w}px, 右侧={right_min_w}px (响应式)")
# 🔥 调整分栏器比例 - 给训练日志更多空间 (左:右 = 2:3) # 🔥 调整分栏器比例 - 给训练日志更多空间 (左:右 = 2:3)
content_splitter.setStretchFactor(0, 2) # 左侧测试区域 content_splitter.setStretchFactor(0, 2) # 左侧测试区域
content_splitter.setStretchFactor(1, 3) # 右侧日志区域获得更多空间 content_splitter.setStretchFactor(1, 3) # 右侧日志区域获得更多空间
print(f"[分栏器] 比例设置: 左侧(测试)=40%, 右侧(日志)=60%")
main_layout.addWidget(content_splitter) main_layout.addWidget(content_splitter)
...@@ -480,8 +465,7 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -480,8 +465,7 @@ class TrainingPage(QtWidgets.QWidget):
self.start_train_btn.clicked.connect(self.startTrainingClicked.emit) self.start_train_btn.clicked.connect(self.startTrainingClicked.emit)
self.stop_train_btn.clicked.connect(self._onStopOrContinueClicked) self.stop_train_btn.clicked.connect(self._onStopOrContinueClicked)
# 初始化日志字体大小 pass
print(f"[日志字体] 初始化字体大小: {self._log_font_size}pt")
def _createParametersGroup(self): def _createParametersGroup(self):
"""创建参数配置组""" """创建参数配置组"""
...@@ -712,8 +696,6 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -712,8 +696,6 @@ class TrainingPage(QtWidgets.QWidget):
# 应用到整个group(包括标签) # 应用到整个group(包括标签)
FontManager.applyToWidgetRecursive(group) FontManager.applyToWidgetRecursive(group)
print(f"✅ [升级参数配置] 已应用全局字体管理器到所有文本框和控件")
return group return group
def _browseModel(self): def _browseModel(self):
...@@ -901,9 +883,6 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -901,9 +883,6 @@ class TrainingPage(QtWidgets.QWidget):
self.stop_train_btn.update() self.stop_train_btn.update()
self.start_train_btn.update() self.start_train_btn.update()
print(f"[DEBUG] switchToContinueMode 完成,按钮文本已改为: {self.stop_train_btn.text()}")
print(f"[DEBUG] stop_train_btn.isEnabled()={self.stop_train_btn.isEnabled()}, start_train_btn.isEnabled()={self.start_train_btn.isEnabled()}")
def switchToStopMode(self): def switchToStopMode(self):
"""切换到停止升级模式(使用系统默认样式)""" """切换到停止升级模式(使用系统默认样式)"""
self._is_training_stopped = False self._is_training_stopped = False
...@@ -1059,10 +1038,9 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -1059,10 +1038,9 @@ class TrainingPage(QtWidgets.QWidget):
'source': 'train_model', 'source': 'train_model',
'format': 'pt' 'format': 'pt'
}) })
print(f"[TrainingPage] 扫描到 .pt 模型: {model_file.name}")
except Exception as e: except Exception as e:
print(f"[TrainingPage] 扫描模型目录失败: {e}") pass
return models return models
...@@ -1169,7 +1147,6 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -1169,7 +1147,6 @@ class TrainingPage(QtWidgets.QWidget):
return remembered return remembered
except Exception as e: except Exception as e:
print(f"[TrainingPage] 读取测试模型记忆失败: {e}")
return None return None
def _saveTestModelMemory(self, model_path): def _saveTestModelMemory(self, model_path):
...@@ -1189,10 +1166,8 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -1189,10 +1166,8 @@ class TrainingPage(QtWidgets.QWidget):
with open(config_path, 'w', encoding='utf-8') as f: with open(config_path, 'w', encoding='utf-8') as f:
yaml.dump(config, f, allow_unicode=True, default_flow_style=False) yaml.dump(config, f, allow_unicode=True, default_flow_style=False)
print(f"[TrainingPage] 已保存测试模型记忆: {model_path}")
except Exception as e: except Exception as e:
print(f"[TrainingPage] 保存测试模型记忆失败: {e}") pass
def getSelectedTestModel(self): def getSelectedTestModel(self):
"""获取选中的测试模型路径""" """获取选中的测试模型路径"""
...@@ -1209,6 +1184,10 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -1209,6 +1184,10 @@ class TrainingPage(QtWidgets.QWidget):
# 🔥 改为从QComboBox获取数据 # 🔥 改为从QComboBox获取数据
return self.test_file_input.currentData() or "" return self.test_file_input.currentData() or ""
def isTestingInProgress(self):
"""检查是否正在测试中"""
return self._is_testing
def setTestButtonState(self, is_testing): def setTestButtonState(self, is_testing):
"""设置测试按钮状态(开始测试 <-> 停止测试)""" """设置测试按钮状态(开始测试 <-> 停止测试)"""
self._is_testing = is_testing self._is_testing = is_testing
...@@ -1230,25 +1209,16 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -1230,25 +1209,16 @@ class TrainingPage(QtWidgets.QWidget):
QPushButton:hover { QPushButton:hover {
background-color: #c82333; background-color: #c82333;
} }
QPushButton:pressed {
background-color: #bd2130;
}
""") """)
print("[TrainingPage] 按钮状态已切换: 停止测试")
else: else:
# 切换为"开始测试"状态 # 切换为"开始测试"状态
self.start_test_btn.setText("开始测试") self.start_test_btn.setText("开始测试")
self.start_test_btn.setStyleSheet("") # 清除样式,恢复系统默认 # 恢复默认样式
print("[TrainingPage] 按钮状态已切换: 开始测试") self.start_test_btn.setStyleSheet("")
def isTestingInProgress(self):
"""检查是否正在测试中"""
return self._is_testing
def _onTemplateChecked(self, button): def _onTemplateChecked(self, button):
"""处理模板复选框选中事件""" """处理模板复选框选中事件"""
template_num = self.template_button_group.id(button) template_num = self.template_button_group.id(button)
print(f"[模板] 用户选择了模板{template_num}")
# 加载并应用模板配置 # 加载并应用模板配置
self._loadTemplateConfig(template_num) self._loadTemplateConfig(template_num)
...@@ -1266,18 +1236,15 @@ class TrainingPage(QtWidgets.QWidget): ...@@ -1266,18 +1236,15 @@ class TrainingPage(QtWidgets.QWidget):
config_path = project_root / "database" / "config" / "train_configs" / f"template_{template_num}.yaml" config_path = project_root / "database" / "config" / "train_configs" / f"template_{template_num}.yaml"
if not config_path.exists(): if not config_path.exists():
print(f"[模板] ⚠️ 配置文件不存在: {config_path}")
return return
try: try:
with open(config_path, 'r', encoding='utf-8') as f: with open(config_path, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f) config = yaml.safe_load(f)
print(f"[模板] ✅ 成功加载模板{template_num}配置")
self._applyTemplateConfig(config, template_num) self._applyTemplateConfig(config, template_num)
except Exception as e: except Exception as e:
print(f"[模板] ❌ 加载配置失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
......
...@@ -964,12 +964,10 @@ if __name__ == '__main__': ...@@ -964,12 +964,10 @@ if __name__ == '__main__':
# 应用全局字体 # 应用全局字体
FontManager.applyToApplication(app) FontManager.applyToApplication(app)
# 创建测试窗口
window = QtWidgets.QWidget() window = QtWidgets.QWidget()
window.setWindowTitle("统一样式管理器测试") window.setWindowTitle("统一样式管理器测试")
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
# 测试字体管理器
label1 = QtWidgets.QLabel("默认字体 - Microsoft YaHei 12pt Normal") label1 = QtWidgets.QLabel("默认字体 - Microsoft YaHei 12pt Normal")
applyDefaultFont(label1) applyDefaultFont(label1)
layout.addWidget(label1) layout.addWidget(label1)
...@@ -978,14 +976,12 @@ if __name__ == '__main__': ...@@ -978,14 +976,12 @@ if __name__ == '__main__':
applyTitleFont(label2) applyTitleFont(label2)
layout.addWidget(label2) layout.addWidget(label2)
# 测试按钮样式管理器
button1 = createTextButton("确认", parent=window) button1 = createTextButton("确认", parent=window)
layout.addWidget(button1) layout.addWidget(button1)
button2 = createTextButton("这是一个很长的按钮文本", parent=window) button2 = createTextButton("这是一个很长的按钮文本", parent=window)
layout.addWidget(button2) layout.addWidget(button2)
# 测试标题文本框样式管理器
title_group, title_text = createTitleTextBox( title_group, title_text = createTitleTextBox(
window, window,
"模型描述", "模型描述",
...@@ -994,7 +990,6 @@ if __name__ == '__main__': ...@@ -994,7 +990,6 @@ if __name__ == '__main__':
) )
layout.addWidget(title_group) layout.addWidget(title_group)
# 测试对话框管理器
def test_dialog(): def test_dialog():
result = show_question(window, "确认", "确定要执行此操作吗?") result = show_question(window, "确认", "确定要执行此操作吗?")
if result: if result:
......
...@@ -443,12 +443,9 @@ class ChannelPanel(QtWidgets.QWidget): ...@@ -443,12 +443,9 @@ class ChannelPanel(QtWidgets.QWidget):
# 只显示文件夹名称 # 只显示文件夹名称
text = task_folder_name.strip() text = task_folder_name.strip()
self.taskLabel.setText(text) self.taskLabel.setText(text)
# 有任务时启用面板
self._setDisabled(False) self._setDisabled(False)
else: else:
# 没有任务信息时显示未分配任务
self.taskLabel.setText("未分配任务") self.taskLabel.setText("未分配任务")
# 无任务时禁用面板
self._setDisabled(True) self._setDisabled(True)
self.taskLabel.adjustSize() self.taskLabel.adjustSize()
...@@ -458,7 +455,6 @@ class ChannelPanel(QtWidgets.QWidget): ...@@ -458,7 +455,6 @@ class ChannelPanel(QtWidgets.QWidget):
def clearTaskInfo(self): def clearTaskInfo(self):
"""清空任务信息显示""" """清空任务信息显示"""
self.taskLabel.setText("未分配任务") self.taskLabel.setText("未分配任务")
# 清空任务时禁用面板
self._setDisabled(True) self._setDisabled(True)
self.taskLabel.adjustSize() self.taskLabel.adjustSize()
self._positionTaskLabel() self._positionTaskLabel()
...@@ -560,27 +556,15 @@ class ChannelPanel(QtWidgets.QWidget): ...@@ -560,27 +556,15 @@ class ChannelPanel(QtWidgets.QWidget):
current_mission: 当前任务路径或名称 current_mission: 当前任务路径或名称
""" """
if self._debug_mode and hasattr(self, 'debugLabel'): if self._debug_mode and hasattr(self, 'debugLabel'):
# 🔥 添加调试信息
# print(f"[DEBUG] setCurrentMission 被调用: current_mission = {current_mission}")
if current_mission: if current_mission:
mission_str = str(current_mission).strip() mission_str = str(current_mission).strip()
# print(f"[DEBUG] mission_str = '{mission_str}'")
# 检查是否是 "None" 字符串或空字符串
if mission_str.lower() == 'none' or not mission_str: if mission_str.lower() == 'none' or not mission_str:
# print(f"[DEBUG] 设置为未分配任务(mission_str为空或'none')")
self.debugLabel.setText("未分配任务") self.debugLabel.setText("未分配任务")
else: else:
# 🔥 修改:显示完整的 current_mission 值
# 统一路径分隔符为 /
normalized_path = mission_str.replace('\\', '/') normalized_path = mission_str.replace('\\', '/')
# print(f"[DEBUG] 设置debug标签为: {normalized_path}")
# 直接显示完整路径
self.debugLabel.setText(normalized_path) self.debugLabel.setText(normalized_path)
else: else:
# print(f"[DEBUG] current_mission 为 None,设置debug标签为'未分配任务'")
self.debugLabel.setText("未分配任务") self.debugLabel.setText("未分配任务")
self.debugLabel.adjustSize() self.debugLabel.adjustSize()
...@@ -752,13 +736,10 @@ if __name__ == "__main__": ...@@ -752,13 +736,10 @@ if __name__ == "__main__":
# 创建通道面板(现在是QWidget,可以直接作为中央部件) # 创建通道面板(现在是QWidget,可以直接作为中央部件)
channel_panel = ChannelPanel("通道1", main_window) channel_panel = ChannelPanel("通道1", main_window)
# 连接信号用于测试
def on_channel_connected(cam_id): def on_channel_connected(cam_id):
# 模拟连接成功后切换状态
channel_panel.setConnected(True) channel_panel.setConnected(True)
def on_channel_disconnected(cam_id): def on_channel_disconnected(cam_id):
# 模拟断开成功后切换状态
channel_panel.setConnected(False) channel_panel.setConnected(False)
def on_curve_clicked(): def on_curve_clicked():
...@@ -775,8 +756,6 @@ if __name__ == "__main__": ...@@ -775,8 +756,6 @@ if __name__ == "__main__":
channel_panel.curveClicked.connect(on_curve_clicked) channel_panel.curveClicked.connect(on_curve_clicked)
channel_panel.amplifyClicked.connect(on_amplify_clicked) channel_panel.amplifyClicked.connect(on_amplify_clicked)
channel_panel.channelEdited.connect(on_edit_clicked) channel_panel.channelEdited.connect(on_edit_clicked)
# 添加测试数据
test_channels = [ test_channels = [
{ {
'id': str(uuid.uuid4()), 'id': str(uuid.uuid4()),
......
...@@ -784,8 +784,6 @@ class CurvePanel(QtWidgets.QWidget): ...@@ -784,8 +784,6 @@ class CurvePanel(QtWidgets.QWidget):
if self.chk_auto_follow.isChecked(): if self.chk_auto_follow.isChecked():
min_time = max_time - view_width min_time = max_time - view_width
self.plot_widget.setXRange(min_time, max_time, padding=0) self.plot_widget.setXRange(min_time, max_time, padding=0)
# 调试:打印X轴范围
# print(f"X轴范围: {datetime.datetime.fromtimestamp(min_time).strftime('%H:%M:%S')} ~ {datetime.datetime.fromtimestamp(max_time).strftime('%H:%M:%S')}")
def setYRangeAuto(self, max_value): def setYRangeAuto(self, max_value):
""" """
...@@ -930,7 +928,6 @@ if __name__ == "__main__": ...@@ -930,7 +928,6 @@ if __name__ == "__main__":
curve_panel = CurvePanel() curve_panel = CurvePanel()
window.setCentralWidget(curve_panel) window.setCentralWidget(curve_panel)
# 添加测试通道(通道名_检测窗口名)
curve_panel.addChannel("channel1", "通道1", "1", "#1f77b4") curve_panel.addChannel("channel1", "通道1", "1", "#1f77b4")
curve_panel.addChannel("channel2", "通道2", "2", "#ff7f0e") curve_panel.addChannel("channel2", "通道2", "2", "#ff7f0e")
curve_panel.addChannel("channel3", "通道3", "3", "#2ca02c") curve_panel.addChannel("channel3", "通道3", "3", "#2ca02c")
...@@ -945,7 +942,6 @@ if __name__ == "__main__": ...@@ -945,7 +942,6 @@ if __name__ == "__main__":
# 计算经过的秒数(用于生成波形) # 计算经过的秒数(用于生成波形)
elapsed = (current_time - start_time).total_seconds() elapsed = (current_time - start_time).total_seconds()
# 为每个通道生成不同的测试数据(整数值,范围在0-23之间)
value1 = int(16 + 3 * np.sin(elapsed * 0.1) + np.random.randn() * 1.5) value1 = int(16 + 3 * np.sin(elapsed * 0.1) + np.random.randn() * 1.5)
value2 = int(15 + 2 * np.cos(elapsed * 0.15) + np.random.randn() * 1.2) value2 = int(15 + 2 * np.cos(elapsed * 0.15) + np.random.randn() * 1.2)
value3 = int(14 + 3 * np.sin(elapsed * 0.08 + 1) + np.random.randn() * 1.0) value3 = int(14 + 3 * np.sin(elapsed * 0.08 + 1) + np.random.randn() * 1.0)
...@@ -965,51 +961,19 @@ if __name__ == "__main__": ...@@ -965,51 +961,19 @@ if __name__ == "__main__":
timer.timeout.connect(update_test_data) timer.timeout.connect(update_test_data)
timer.start(100) # 100ms更新一次,10Hz刷新率 timer.start(100) # 100ms更新一次,10Hz刷新率
# 连接信号测试
def on_curve_updated(channel_id, t, v): def on_curve_updated(channel_id, t, v):
pass # 静默处理,避免打印过多 pass # 静默处理,避免打印过多
def on_channel_switched(channel_id): def on_channel_switched(channel_id):
print(f" 切换到通道: {channel_id}") pass
def on_data_exported(channel_id, file_path): def on_data_exported(channel_id, file_path):
print(f" 数据已导出: {channel_id} -> {file_path}") pass
curve_panel.curveDataUpdated.connect(on_curve_updated) curve_panel.curveDataUpdated.connect(on_curve_updated)
curve_panel.channelSwitched.connect(on_channel_switched) curve_panel.channelSwitched.connect(on_channel_switched)
curve_panel.dataExported.connect(on_data_exported) curve_panel.dataExported.connect(on_data_exported)
print("\n" + "="*70)
print(" CurvePanel 高性能曲线面板测试程序")
print("="*70)
print(" 已添加3个测试通道(通道1_1、通道2_2、通道3_3)")
print(" 正在模拟实时数据更新 (10Hz)")
print("\n 数据格式:")
print(" - CSV格式:时间戳 数值")
print(" - 时间格式:2025-09-28-17:37:39.220")
print(" - 文件名:通道名_检测窗口名称_时间戳.csv")
print(" - 图例显示:通道名_检测窗口名")
print("\n 可以尝试以下操作:")
print(" 通道管理:")
print(" - 下拉框切换不同通道")
print(" - 点击'添加通道'动态添加新通道")
print(" - 点击'清空数据'清除当前通道数据")
print("\n 视图控制:")
print(" - 鼠标左键拖动:左右平移(X轴)或上下平移(Y轴)")
print(" - 鼠标滚轮:放大/缩小时间轴或数值轴")
print(" - 点击'查看全部':显示所有历史数据(自动调整XY轴)")
print(" - 点击'重置视图':显示最新10秒数据(Y:0-23)")
print(" - '自动跟随'开关:启用后自动滚动显示最新时间数据")
print(" - '自动Y轴'开关:启用后自动扩展Y轴以适应数据")
print("\n 数据操作:")
print(" - 点击'导出数据':保存为CSV文件")
print(" - 点击'保存图片':导出为PNG图片")
print(" - '自动保存'开关:定时自动保存数据(每2分钟)")
print("\n 坐标轴:")
print(" - X轴(横坐标):时间戳,显示实际时间(HH:MM:SS),支持左右拖动和缩放")
print(" - Y轴(纵坐标):数值,范围0-23,支持上下拖动和缩放")
print(" - Y轴限制:最小值不能小于0(只显示非负值)")
print("="*70 + "\n")
window.show() window.show()
sys.exit(app.exec_()) sys.exit(app.exec_())
......
...@@ -742,8 +742,7 @@ class GeneralSetPanel(QtWidgets.QWidget): ...@@ -742,8 +742,7 @@ class GeneralSetPanel(QtWidgets.QWidget):
self.model_setting_widget.readModelDescriptionRequested.emit(absolute_path) self.model_setting_widget.readModelDescriptionRequested.emit(absolute_path)
except Exception as e: except Exception as e:
import traceback pass
traceback.print_exc()
def _autoSaveModelPath(self, model_path): def _autoSaveModelPath(self, model_path):
""" """
...@@ -1846,7 +1845,7 @@ class AnnotationWidget(QtWidgets.QWidget): ...@@ -1846,7 +1845,7 @@ class AnnotationWidget(QtWidgets.QWidget):
elif self.annotation_engine.step == 1: elif self.annotation_engine.step == 1:
# 标注底部点模式:删除最后一个检测框(回退到画框模式) # 标注底部点模式:删除最后一个检测框(回退到画框模式)
if len(self.annotation_engine.boxes) > 0: if len(self.annotation_engine.boxes) > 0:
removed_box = self.annotation_engine.boxes.pop() self.annotation_engine.boxes.pop()
# 同时删除对应的区域名称和高度 # 同时删除对应的区域名称和高度
if len(self.area_names) > 0: if len(self.area_names) > 0:
...@@ -1863,7 +1862,7 @@ class AnnotationWidget(QtWidgets.QWidget): ...@@ -1863,7 +1862,7 @@ class AnnotationWidget(QtWidgets.QWidget):
elif self.annotation_engine.step == 2: elif self.annotation_engine.step == 2:
# 标注顶部点模式:删除最后一个底部点(回退到标注底部点模式) # 标注顶部点模式:删除最后一个底部点(回退到标注底部点模式)
if len(self.annotation_engine.bottom_points) > 0: if len(self.annotation_engine.bottom_points) > 0:
removed_point = self.annotation_engine.bottom_points.pop() self.annotation_engine.bottom_points.pop()
# 回到标注底部点模式 # 回到标注底部点模式
self.annotation_engine.step = 1 self.annotation_engine.step = 1
...@@ -1882,7 +1881,7 @@ class AnnotationWidget(QtWidgets.QWidget): ...@@ -1882,7 +1881,7 @@ class AnnotationWidget(QtWidgets.QWidget):
# 发送标注数据请求信号给handler # 发送标注数据请求信号给handler
self.annotationDataRequested.emit() self.annotationDataRequested.emit()
else: else:
pass return
def keyPressEvent(self, event): def keyPressEvent(self, event):
"""键盘事件处理 - 增强版快捷键绑定""" """键盘事件处理 - 增强版快捷键绑定"""
...@@ -1955,27 +1954,27 @@ class AnnotationWidget(QtWidgets.QWidget): ...@@ -1955,27 +1954,27 @@ class AnnotationWidget(QtWidgets.QWidget):
return return
# 删除检测框 # 删除检测框
removed_box = self.annotation_engine.boxes.pop(area_index) self.annotation_engine.boxes.pop(area_index)
# 删除对应的底部点 # 删除对应的底部点
if area_index < len(self.annotation_engine.bottom_points): if area_index < len(self.annotation_engine.bottom_points):
removed_bottom = self.annotation_engine.bottom_points.pop(area_index) self.annotation_engine.bottom_points.pop(area_index)
# 删除对应的顶部点 # 删除对应的顶部点
if area_index < len(self.annotation_engine.top_points): if area_index < len(self.annotation_engine.top_points):
removed_top = self.annotation_engine.top_points.pop(area_index) self.annotation_engine.top_points.pop(area_index)
# 删除对应的区域名称 # 删除对应的区域名称
if area_index < len(self.area_names): if area_index < len(self.area_names):
removed_name = self.area_names.pop(area_index) self.area_names.pop(area_index)
# 删除对应的区域高度 # 删除对应的区域高度
if area_index < len(self.area_heights): if area_index < len(self.area_heights):
removed_height = self.area_heights.pop(area_index) self.area_heights.pop(area_index)
# 删除对应的区域状态 # 删除对应的区域状态
if area_index < len(self.area_states): if area_index < len(self.area_states):
removed_state = self.area_states.pop(area_index) self.area_states.pop(area_index)
# 更新显示 # 更新显示
self._updateDisplay() self._updateDisplay()
...@@ -1996,8 +1995,6 @@ class AnnotationWidget(QtWidgets.QWidget): ...@@ -1996,8 +1995,6 @@ class AnnotationWidget(QtWidgets.QWidget):
self._help_visible = not self._help_visible self._help_visible = not self._help_visible
pass
# 更新显示 # 更新显示
self._updateDisplay() self._updateDisplay()
...@@ -2010,7 +2007,6 @@ class AnnotationWidget(QtWidgets.QWidget): ...@@ -2010,7 +2007,6 @@ class AnnotationWidget(QtWidgets.QWidget):
self._ensureAreaConfig(area_index) self._ensureAreaConfig(area_index)
# 设置高度 # 设置高度
old_height = self.area_heights[area_index]
self.area_heights[area_index] = height_value self.area_heights[area_index] = height_value
# 更新显示 # 更新显示
...@@ -2047,4 +2043,4 @@ class AnnotationWidget(QtWidgets.QWidget): ...@@ -2047,4 +2043,4 @@ class AnnotationWidget(QtWidgets.QWidget):
def showAnnotationError(self, message): def showAnnotationError(self, message):
"""显示标注错误(由handler调用)""" """显示标注错误(由handler调用)"""
pass return
...@@ -134,7 +134,7 @@ class HistoryVideoPanel(QtWidgets.QWidget): ...@@ -134,7 +134,7 @@ class HistoryVideoPanel(QtWidgets.QWidget):
self.nameLabel.setText("") self.nameLabel.setText("")
self.nameLabel.hide() # 隐藏标签 self.nameLabel.hide() # 隐藏标签
# 创建debug模式静态文本控件(叠加在视频区域顶部中间,仅在debug模式下显示) # 创建调试模式静态文本控件(叠加在视频区域顶部中间,仅在调试模式下显示)
self.debugLabel = QtWidgets.QLabel(self.videoLabel) self.debugLabel = QtWidgets.QLabel(self.videoLabel)
self.debugLabel.setText("") # 初始为空,等待设置current_mission self.debugLabel.setText("") # 初始为空,等待设置current_mission
self.debugLabel.setStyleSheet(""" self.debugLabel.setStyleSheet("""
...@@ -150,7 +150,7 @@ class HistoryVideoPanel(QtWidgets.QWidget): ...@@ -150,7 +150,7 @@ class HistoryVideoPanel(QtWidgets.QWidget):
self.debugLabel.adjustSize() self.debugLabel.adjustSize()
# 定位到顶部中间 # 定位到顶部中间
self._positionDebugLabel() self._positionDebugLabel()
# 根据debug_mode控制显示/隐藏 # 根据调试模式控制显示/隐藏
self.debugLabel.setVisible(self._debug_mode) self.debugLabel.setVisible(self._debug_mode)
# 🔥 历史视频面板不显示任务信息标签 # 🔥 历史视频面板不显示任务信息标签
...@@ -780,7 +780,7 @@ if __name__ == "__main__": ...@@ -780,7 +780,7 @@ if __name__ == "__main__":
# 连接信号用于测试 # 连接信号用于测试
def on_channel_name_changed(channel_id, new_name): def on_channel_name_changed(channel_id, new_name):
print(f"📝 通道名称改变: {channel_id} -> {new_name}") pass
history_panel.channelNameChanged.connect(on_channel_name_changed) history_panel.channelNameChanged.connect(on_channel_name_changed)
......
...@@ -116,7 +116,6 @@ if __name__ == "__main__": ...@@ -116,7 +116,6 @@ if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
# 测试逻辑配置数据
test_config = { test_config = {
'detection_mode': 'continuous', 'detection_mode': 'continuous',
'high_threshold': 80.0, 'high_threshold': 80.0,
...@@ -134,9 +133,6 @@ if __name__ == "__main__": ...@@ -134,9 +133,6 @@ if __name__ == "__main__":
dialog = LogicSettingDialog(logic_config=test_config, channel_id='channel1') dialog = LogicSettingDialog(logic_config=test_config, channel_id='channel1')
if dialog.exec_() == QtWidgets.QDialog.Accepted: if dialog.exec_() == QtWidgets.QDialog.Accepted:
config = dialog.getLogicConfig() config = dialog.getLogicConfig()
print("=== 获取的逻辑配置 ===")
for key, value in config.items():
print(f"{key}: {value}")
sys.exit(0) sys.exit(0)
...@@ -95,9 +95,6 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -95,9 +95,6 @@ class MissionPanel(QtWidgets.QWidget):
self._initUI() self._initUI()
self._connectSignals() self._connectSignals()
# 🔥 暂时禁用全局字体管理器,测试是否解决重复显示问题
# FontManager.applyToWidgetRecursive(self)
# 自动应用默认配置 # 自动应用默认配置
self._applyDefaultConfig() self._applyDefaultConfig()
...@@ -757,7 +754,8 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -757,7 +754,8 @@ class MissionPanel(QtWidgets.QWidget):
def _testFontException(self): def _testFontException(self):
""" """
测试字体例外机制是否正常工作 测试字体例外机制是否正常工作
""" """
pass
def updateRow(self, row_index, row_data): def updateRow(self, row_index, row_data):
...@@ -1421,8 +1419,6 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -1421,8 +1419,6 @@ class MissionPanel(QtWidgets.QWidget):
if not addr.startswith('rtsp://'): if not addr.startswith('rtsp://'):
addr = 'rtsp://' + addr addr = 'rtsp://' + addr
print(f"🔧 [MissionPanel] 请求测试通道{channel_id}连接: {addr}")
# 发送调试信号给handler处理 # 发送调试信号给handler处理
self.channelDebugRequested.emit(channel_id, addr) self.channelDebugRequested.emit(channel_id, addr)
...@@ -1529,35 +1525,26 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -1529,35 +1525,26 @@ class MissionPanel(QtWidgets.QWidget):
'' # 曲线列(按钮会自动添加) '' # 曲线列(按钮会自动添加)
] ]
self.addRow(row_data, task_info) self.addRow(row_data, task_info)
print(f" 任务已添加到表格: {task_info['task_name']}")
def removeTaskRow(self, row_index): def removeTaskRow(self, row_index):
"""删除任务行(由handler调用)""" """删除任务行(由handler调用)"""
if self.removeRow(row_index): self.removeRow(row_index)
print(f" 已删除任务行: {row_index}")
def _showWarningDialog(self, title, message): def _showWarningDialog(self, title, message):
"""显示警告对话框(内部使用)""" """显示警告对话框(内部使用)"""
print(f"\n[对话框调试] 创建警告对话框: {title}")
msg_box = QtWidgets.QMessageBox(self) msg_box = QtWidgets.QMessageBox(self)
msg_box.setWindowTitle(title) msg_box.setWindowTitle(title)
msg_box.setText(message) msg_box.setText(message)
msg_box.setIcon(QtWidgets.QMessageBox.NoIcon) # 不显示内容区域图标 msg_box.setIcon(QtWidgets.QMessageBox.NoIcon) # 不显示内容区域图标
print(f" - 设置内容区域图标: NoIcon")
# 设置左上角图标为系统警告图标 # 设置左上角图标为系统警告图标
warning_icon = msg_box.style().standardIcon(QtWidgets.QStyle.SP_MessageBoxWarning) warning_icon = msg_box.style().standardIcon(QtWidgets.QStyle.SP_MessageBoxWarning)
msg_box.setWindowIcon(warning_icon) msg_box.setWindowIcon(warning_icon)
print(f" - 设置窗口图标: SP_MessageBoxWarning")
print(f" - 窗口图标是否为空: {warning_icon.isNull()}")
# 移除帮助按钮 # 移除帮助按钮
original_flags = msg_box.windowFlags()
msg_box.setWindowFlags( msg_box.setWindowFlags(
msg_box.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint msg_box.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint
) )
print(f" - 原始窗口标志: {original_flags}")
print(f" - 最终窗口标志: {msg_box.windowFlags()}")
# 设置文字水平和垂直居中 # 设置文字水平和垂直居中
msg_box.setStyleSheet(""" msg_box.setStyleSheet("""
...@@ -1569,9 +1556,7 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -1569,9 +1556,7 @@ class MissionPanel(QtWidgets.QWidget):
qproperty-alignment: 'AlignCenter'; qproperty-alignment: 'AlignCenter';
} }
""") """)
print(f" - 已设置样式表")
print(f" - 显示对话框...")
msg_box.exec_() msg_box.exec_()
def showConfirmDialog(self, title, message): def showConfirmDialog(self, title, message):
...@@ -1679,17 +1664,15 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -1679,17 +1664,15 @@ class MissionPanel(QtWidgets.QWidget):
def _onFirstPage(self): def _onFirstPage(self):
"""跳转到首页""" """跳转到首页"""
if self._current_page != 1: if self._current_page > 1:
self._current_page = 1 self._current_page = 1
self._updatePagination() self._updatePagination()
print(f" 跳转到首页")
def _onPrevPage(self): def _onPrevPage(self):
"""上一页""" """上一页"""
if self._current_page > 1: if self._current_page > 1:
self._current_page -= 1 self._current_page -= 1
self._updatePagination() self._updatePagination()
print(f" 上一页 -> 第 {self._current_page} 页")
def _onNextPage(self): def _onNextPage(self):
"""下一页""" """下一页"""
...@@ -1697,7 +1680,6 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -1697,7 +1680,6 @@ class MissionPanel(QtWidgets.QWidget):
if self._current_page < total_pages: if self._current_page < total_pages:
self._current_page += 1 self._current_page += 1
self._updatePagination() self._updatePagination()
print(f" 下一页 -> 第 {self._current_page} 页")
def _onLastPage(self): def _onLastPage(self):
"""跳转到末页""" """跳转到末页"""
...@@ -1705,7 +1687,6 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -1705,7 +1687,6 @@ class MissionPanel(QtWidgets.QWidget):
if self._current_page != total_pages: if self._current_page != total_pages:
self._current_page = total_pages self._current_page = total_pages
self._updatePagination() self._updatePagination()
print(f" 跳转到末页")
def _onGoToPage(self): def _onGoToPage(self):
"""跳转到指定页""" """跳转到指定页"""
...@@ -1716,7 +1697,6 @@ class MissionPanel(QtWidgets.QWidget): ...@@ -1716,7 +1697,6 @@ class MissionPanel(QtWidgets.QWidget):
if 1 <= page_num <= total_pages: if 1 <= page_num <= total_pages:
self._current_page = page_num self._current_page = page_num
self._updatePagination() self._updatePagination()
print(f" 跳转到第 {page_num} 页")
self.page_input.clear() self.page_input.clear()
else: else:
self._showWarningDialog( self._showWarningDialog(
...@@ -1754,7 +1734,7 @@ if __name__ == "__main__": ...@@ -1754,7 +1734,7 @@ if __name__ == "__main__":
# 曲线按钮点击处理 # 曲线按钮点击处理
def on_curve_button_clicked(row, col): def on_curve_button_clicked(row, col):
row_data = table.getRowData(row) row_data = table.getRowData(row)
print(f" 点击曲线按钮: 行 {row}, 数据: {row_data}") pass
# 添加数据(按钮会自动添加) # 添加数据(按钮会自动添加)
for row_data, user_data in test_data: for row_data, user_data in test_data:
...@@ -1762,7 +1742,7 @@ if __name__ == "__main__": ...@@ -1762,7 +1742,7 @@ if __name__ == "__main__":
# 连接按钮点击信号 # 连接按钮点击信号
def on_button_signal(row, col): def on_button_signal(row, col):
print(f" 按钮点击信号: 行 {row}, 列 {col}") pass
table.buttonClicked.connect(on_button_signal) table.buttonClicked.connect(on_button_signal)
...@@ -1770,15 +1750,14 @@ if __name__ == "__main__": ...@@ -1770,15 +1750,14 @@ if __name__ == "__main__":
def on_item_selected(row_index): def on_item_selected(row_index):
row_data = table.getRowData(row_index) row_data = table.getRowData(row_index)
user_data = table.getUserData(row_index) user_data = table.getUserData(row_index)
print(f" 选中行 {row_index}: {row_data}") pass
print(f" 用户数据: {user_data}")
def on_item_double_clicked(row_index): def on_item_double_clicked(row_index):
row_data = table.getRowData(row_index) row_data = table.getRowData(row_index)
print(f" 双击行 {row_index}: {row_data}") pass
def on_item_changed(row, col, new_value): def on_item_changed(row, col, new_value):
print(f" 单元格改变 ({row}, {col}): {new_value}") pass
table.itemSelected.connect(on_item_selected) table.itemSelected.connect(on_item_selected)
table.itemDoubleClicked.connect(on_item_double_clicked) table.itemDoubleClicked.connect(on_item_double_clicked)
......
...@@ -282,8 +282,6 @@ class ModelSettingDialog(QtWidgets.QDialog): ...@@ -282,8 +282,6 @@ class ModelSettingDialog(QtWidgets.QDialog):
if model_path: if model_path:
self.readModelDescriptionRequested.emit(model_path) self.readModelDescriptionRequested.emit(model_path)
print(f"[对话框] 用户双击选择模型: {model_path}")
def _updateCurrentModelInfo(self, model_path): def _updateCurrentModelInfo(self, model_path):
""" """
更新当前模型信息显示 更新当前模型信息显示
...@@ -312,7 +310,6 @@ class ModelSettingDialog(QtWidgets.QDialog): ...@@ -312,7 +310,6 @@ class ModelSettingDialog(QtWidgets.QDialog):
# 选中当前模型项 # 选中当前模型项
self.modelListWidget.setCurrentItem(item) self.modelListWidget.setCurrentItem(item)
item.setSelected(True) item.setSelected(True)
print(f"[模型设置对话框] 已在列表中高亮当前模型: {model_path}")
break break
def _readModelDescription(self, model_path): def _readModelDescription(self, model_path):
...@@ -395,7 +392,6 @@ if __name__ == "__main__": ...@@ -395,7 +392,6 @@ if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
# 测试模型配置数据
test_config = { test_config = {
'model_path': '', 'model_path': '',
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment