Commit 60a45704 by Yuhaibo

曲线面板

parent ed6080ac
...@@ -958,18 +958,20 @@ class MainWindow( ...@@ -958,18 +958,20 @@ class MainWindow(
self._updateCurveChannelDisplay([]) self._updateCurveChannelDisplay([])
return return
# 🔥 根据 curve_load_mode 决定显示逻辑 # 🔥 重新检查检测状态并切换布局
if hasattr(self, 'curvePanelHandler'): print(f"\n🔄 [任务切换] 任务已切换到: {mission_name},重新检查检测状态...")
curve_mode = self.curvePanelHandler.getCurveLoadMode() detection_running = False
else: if hasattr(self, '_switchCurveSubLayout') and hasattr(self, '_getCurrentDetectionState'):
curve_mode = 'realtime' detection_running = self._getCurrentDetectionState()
self._switchCurveSubLayout(detection_running)
if curve_mode == 'realtime':
# 🔥 实时模式:只显示任务配置中使用的通道 # 🔥 根据检测状态决定显示逻辑(而不是依赖 getCurveLoadMode)
if detection_running:
# 🔥 实时检测模式:只显示任务配置中使用的通道
selected_channels = self._getTaskChannels(mission_name) selected_channels = self._getTaskChannels(mission_name)
print(f"📊 [曲线布局-实时模式] 任务 {mission_name},显示任务使用的通道: {selected_channels}") print(f"📊 [曲线布局-实时模式] 任务 {mission_name},显示任务使用的通道: {selected_channels}")
else: else:
# 🔥 历史模式:显示所有通道容器 # 🔥 历史回放模式:显示所有通道容器
selected_channels = ['通道1', '通道2', '通道3', '通道4'] selected_channels = ['通道1', '通道2', '通道3', '通道4']
print(f"📊 [曲线布局-历史模式] 任务 {mission_name},显示所有通道容器") print(f"📊 [曲线布局-历史模式] 任务 {mission_name},显示所有通道容器")
...@@ -989,21 +991,15 @@ class MainWindow( ...@@ -989,21 +991,15 @@ class MainWindow(
import yaml import yaml
try: try:
# 构建任务文件夹路径 # 构建任务配置文件路径(在 database/config/mission/ 目录下)
try: try:
from database.config import get_project_root from database.config import get_project_root
project_root = get_project_root() project_root = get_project_root()
except ImportError: except ImportError:
project_root = os.getcwd() project_root = os.getcwd()
mission_path = os.path.join(project_root, 'database', 'mission_result', mission_name) # 任务配置文件在 database/config/mission/ 目录下
config_file = os.path.join(project_root, 'database', 'config', 'mission', f"{mission_name}.yaml")
if not os.path.exists(mission_path):
print(f"⚠️ [通道筛选] 任务文件夹不存在: {mission_path}")
return []
# 查找任务配置文件(.yaml文件,文件名与任务名相同)
config_file = os.path.join(mission_path, f"{mission_name}.yaml")
if not os.path.exists(config_file): if not os.path.exists(config_file):
print(f"⚠️ [通道筛选] 任务配置文件不存在: {config_file}") print(f"⚠️ [通道筛选] 任务配置文件不存在: {config_file}")
......
...@@ -5,29 +5,29 @@ channel1: ...@@ -5,29 +5,29 @@ channel1:
height: 20mm height: 20mm
name: 通道1_区域1 name: 通道1_区域1
boxes: boxes:
- - 617 - - 846
- 415 - 447
- 192 - 160
fixed_bottoms: fixed_bottoms:
- 482 - 474
fixed_tops: fixed_tops:
- 387 - 418
last_updated: '2025-11-27 15:55:10' last_updated: '2025-11-29 11:16:07'
channel2: channel2:
annotation_count: 1 annotation_count: 1
areas: areas:
area_1: area_1:
height: 20mm height: 20mm
name: 我去饿_区域1 name: 通道2_区域1
boxes: boxes:
- - 643 - - 75
- 558 - 1043
- 160 - 128
fixed_bottoms: fixed_bottoms:
- 616 - 1065
fixed_tops: fixed_tops:
- 534 - 1028
last_updated: '2025-11-26 20:09:26' last_updated: '2025-11-29 12:23:45'
channel3: channel3:
annotation_count: 1 annotation_count: 1
areas: areas:
......
This source diff could not be displayed because it is too large. You can view the blob instead.
然后我去佛i好的食品发酵食品的 这是综合模型,经过了多种场景的训练与测试,适应性强,准确率高。
然后我去佛i好的食品发酵食品的 这是综合模型,经过了多种场景的训练与测试,适应性强,准确率高。
\ No newline at end of file \ No newline at end of file
...@@ -799,6 +799,11 @@ class CurvePanelHandler: ...@@ -799,6 +799,11 @@ class CurvePanelHandler:
# 按文件夹名称排序 # 按文件夹名称排序
mission_folders.sort(key=lambda x: x['name']) mission_folders.sort(key=lambda x: x['name'])
print(f"📂 [任务扫描] 扫描目录: {mission_result_dir}")
print(f"📂 [任务扫描] 找到 {len(mission_folders)} 个任务文件夹")
for folder in mission_folders:
print(f" - {folder['name']}")
# 通知UI更新下拉框 # 通知UI更新下拉框
if self.curve_panel: if self.curve_panel:
self.curve_panel.updateMissionFolderList(mission_folders) self.curve_panel.updateMissionFolderList(mission_folders)
...@@ -1034,8 +1039,7 @@ class CurvePanelHandler: ...@@ -1034,8 +1039,7 @@ class CurvePanelHandler:
new_points: 新增的数据点列表 new_points: 新增的数据点列表
""" """
try: try:
# 🔥 调试:记录接收到的数据
print(f"📥 [曲线数据处理-主线程] 接收到数据: curve_id={curve_id}, area_idx={area_idx}, 数据点数={len(new_points)}")
# 🔥 检查是否在曲线模式(防止UI对象生命周期问题) # 🔥 检查是否在曲线模式(防止UI对象生命周期问题)
if hasattr(self, 'is_curve_mode_active'): if hasattr(self, 'is_curve_mode_active'):
......
...@@ -121,21 +121,104 @@ class ViewHandler: ...@@ -121,21 +121,104 @@ class ViewHandler:
def _getCurrentDetectionState(self): def _getCurrentDetectionState(self):
""" """
获取当前检测线程的运行状态 获取当前检测线程的运行状态(基于curvemission使用的通道)
Returns: Returns:
bool: True=有检测线程正在运行, False=没有检测线程运行 bool: True=curvemission使用的通道中有任意一个检测线程正在运行, False=全部停止
""" """
print(f"\n🔍 [检测状态判断] 开始检查...")
if not hasattr(self, 'thread_manager'): if not hasattr(self, 'thread_manager'):
print(f"❌ [检测状态判断] 没有thread_manager")
return False
# 获取当前curvemission选择的任务
if not hasattr(self, 'curvemission'):
print(f"❌ [检测状态判断] 没有curvemission")
return False
mission_name = self.curvemission.currentText()
print(f"📋 [检测状态判断] 当前任务: {mission_name}")
if not mission_name or mission_name == "请选择任务":
print(f"❌ [检测状态判断] 未选择有效任务")
return False
# 🔥 第一层判断:检查任务状态
mission_status = self._getMissionStatus(mission_name)
print(f"📊 [检测状态判断] 任务状态: '{mission_status}'")
if mission_status == "未启动":
print(f"⚠️ [检测状态判断] 任务状态为'未启动',跳过detection_flag检查,直接使用历史回放模式(索引1)")
return False
else:
print(f"✅ [检测状态判断] 任务状态为'{mission_status}',继续检查detection_flag")
# 获取该任务使用的通道列表
task_channels = self._getTaskChannels(mission_name)
print(f"📡 [检测状态判断] 任务使用的通道: {task_channels}")
if not task_channels:
print(f"❌ [检测状态判断] 任务没有配置通道")
return False return False
# 检查是否有任何检测线程正在运行 # 将通道名称转换为通道ID(通道1 -> channel1)
for context in self.thread_manager.contexts.values(): channel_ids = []
if context and context.detection_flag: for channel_name in task_channels:
return True if '通道' in channel_name:
# 提取数字部分
channel_num = channel_name.replace('通道', '')
channel_ids.append(f'channel{channel_num}')
print(f"🔑 [检测状态判断] 转换后的通道ID: {channel_ids}")
# 检查这些通道的detection_flag状态
# 只要有任意一个通道的detection_flag为True,就返回True
for channel_id in channel_ids:
context = self.thread_manager.get_channel_context(channel_id)
if context:
detection_flag = context.detection_flag
print(f" 🔸 {channel_id}: detection_flag={detection_flag}, type={type(detection_flag)}")
# 确保 detection_flag 是布尔值 True
if detection_flag is True or detection_flag == True:
print(f"✅ [检测状态判断] 发现运行中的检测线程: {channel_id}")
return True
else:
print(f" ⚠️ {channel_id}: 没有context")
# 所有通道的detection_flag都为False
print(f"❌ [检测状态判断] 所有通道的检测线程都已停止")
return False return False
def _getMissionStatus(self, mission_name):
"""
获取任务的实际运行状态(检查是否有通道正在使用该任务)
Args:
mission_name: 任务名称
Returns:
str: 任务状态,"已启动" 或 "未启动"
"""
try:
# 🔥 检查任务是否被任何通道使用
# MissionPanelHandler 是通过 Mixin 继承的,所以直接用 self._isTaskInUse
if hasattr(self, '_isTaskInUse'):
is_in_use = self._isTaskInUse(mission_name)
status = "已启动" if is_in_use else "未启动"
print(f" 🔍 [任务状态检查] 任务'{mission_name}' is_in_use={is_in_use} → 状态='{status}'")
return status
else:
# 如果没有 _isTaskInUse 方法,默认返回"未启动"
print(f" ⚠️ [任务状态检查] 没有_isTaskInUse方法,默认返回'未启动'")
return "未启动"
except Exception as e:
print(f"❌ [任务状态] 获取失败: {e}")
import traceback
traceback.print_exc()
return "未启动"
def _switchToCurveLayout(self): def _switchToCurveLayout(self):
"""切换到曲线模式:根据检测线程状态选择合适的子布局""" """切换到曲线模式:根据检测线程状态选择合适的子布局"""
# 🔥 检查检测线程状态,决定使用哪种子布局 # 🔥 检查检测线程状态,决定使用哪种子布局
...@@ -312,7 +395,10 @@ class ViewHandler: ...@@ -312,7 +395,10 @@ class ViewHandler:
Args: Args:
detection_running: bool, True=检测线程运行中, False=检测线程停止 detection_running: bool, True=检测线程运行中, False=检测线程停止
""" """
print(f"\n🔄 [布局切换] detection_running={detection_running}")
if not hasattr(self, 'curveLayoutStack'): if not hasattr(self, 'curveLayoutStack'):
print(f"❌ [布局切换] 没有curveLayoutStack")
return return
if detection_running: if detection_running:
...@@ -322,6 +408,7 @@ class ViewHandler: ...@@ -322,6 +408,7 @@ class ViewHandler:
mode_text = "实时检测" mode_text = "实时检测"
mode_style = "font-weight: bold; padding: 2px 8px;" mode_style = "font-weight: bold; padding: 2px 8px;"
curve_mode = 'realtime' curve_mode = 'realtime'
print(f"✅ [布局切换] 选择索引0 - 实时检测布局")
else: else:
# 切换到历史回放布局(索引1) # 切换到历史回放布局(索引1)
...@@ -330,6 +417,7 @@ class ViewHandler: ...@@ -330,6 +417,7 @@ class ViewHandler:
mode_text = "历史回放" mode_text = "历史回放"
mode_style = "font-weight: bold; padding: 2px 8px;" mode_style = "font-weight: bold; padding: 2px 8px;"
curve_mode = 'history' curve_mode = 'history'
print(f"✅ [布局切换] 选择索引1 - 历史回放布局")
# 🔥 同步切换曲线绘制模式 # 🔥 同步切换曲线绘制模式
...@@ -350,15 +438,15 @@ class ViewHandler: ...@@ -350,15 +438,15 @@ class ViewHandler:
pass pass
# 执行布局切换 # 执行布局切换
if self.curveLayoutStack.currentIndex() != target_index: current_index = self.curveLayoutStack.currentIndex()
print(f"📍 [布局切换] 当前索引: {current_index}, 目标索引: {target_index}")
if current_index != target_index:
self.curveLayoutStack.setCurrentIndex(target_index) self.curveLayoutStack.setCurrentIndex(target_index)
self._curve_sub_layout_mode = target_index self._curve_sub_layout_mode = target_index
print(f"✅ [布局切换] 已切换到索引 {target_index}")
# 🔥 切换模式后,重新应用通道筛选逻辑 else:
if hasattr(self, 'curvemission') and hasattr(self, '_onCurveMissionChanged'): print(f"ℹ️ [布局切换] 已经是目标索引 {target_index},无需切换")
current_mission = self.curvemission.currentText()
if current_mission and current_mission != "请选择任务":
self._onCurveMissionChanged(current_mission)
def _loadCurveDataOrStartThreads(self): def _loadCurveDataOrStartThreads(self):
......
...@@ -9,4 +9,6 @@ R - Renamed(已重命名):文件已被重命名 ...@@ -9,4 +9,6 @@ R - Renamed(已重命名):文件已被重命名
C - Copied(已复制):文件已被复制 C - Copied(已复制):文件已被复制
U - Unmerged(未合并):存在合并冲突 U - Unmerged(未合并):存在合并冲突
channeldetect=True channeldetect=True
curve_load_mode curve_load_mode
\ No newline at end of file 检测线程运行中 (detection_running=True) → 索引0(实时检测模式)
检测线程停止 (detection_running=False) → 索引1(历史回放模式)
\ No newline at end of file
1曲线模式索引0布局,只显示根据curvemission筛选使用的通道面板失效了
1曲线模式索引0布局,只显示根据curvemission筛选使用的通道面板失效了
2判断detection_falg前,若curvemission任务面板状态列的状态为未启动( mission_status变量),则直接使用索引1布局
选择任务
检查任务状态
任务状态 = "未启动"?
├─ 是 → 返回 False → 索引1(历史回放)
└─ 否 → 继续检查
检查通道 detection_flag
任意通道 detection_flag = True?
├─ 是 → 返回 True → 索引0(实时检测)
└─ 否 → 返回 False → 索引1(历史回放)
\ No newline at end of file
...@@ -386,7 +386,7 @@ class GeneralSetPanel(QtWidgets.QWidget): ...@@ -386,7 +386,7 @@ class GeneralSetPanel(QtWidgets.QWidget):
layout.addWidget(task_name_label, 0, 2) layout.addWidget(task_name_label, 0, 2)
layout.addWidget(self.task_name_edit, 0, 3) layout.addWidget(self.task_name_edit, 0, 3)
# 第二行:检测模型、数据推送地址 # 第二行:检测模型、地址
model_path_label = QtWidgets.QLabel("检测模型:") model_path_label = QtWidgets.QLabel("检测模型:")
self.model_path_display = QtWidgets.QLineEdit() self.model_path_display = QtWidgets.QLineEdit()
self.model_path_display.setReadOnly(True) self.model_path_display.setReadOnly(True)
...@@ -394,7 +394,11 @@ class GeneralSetPanel(QtWidgets.QWidget): ...@@ -394,7 +394,11 @@ class GeneralSetPanel(QtWidgets.QWidget):
self.model_path_display.setMinimumWidth(scale_w(140)) # 响应式宽度 self.model_path_display.setMinimumWidth(scale_w(140)) # 响应式宽度
push_label = QtWidgets.QLabel("数据推送地址:") push_label = QtWidgets.QLabel("数据推送地址:")
self.push_edit = QtWidgets.QLineEdit("192.168.1.234/put/push/height") self.push_edit = QtWidgets.QLineEdit()
self.push_edit.setReadOnly(True)
self.push_edit.setPlaceholderText("数据推送功能开发中,敬请期待。")
self.push_edit.setMinimumWidth(scale_w(140)) # 响应式宽度
layout.addWidget(model_path_label, 1, 0) layout.addWidget(model_path_label, 1, 0)
layout.addWidget(self.model_path_display, 1, 1) layout.addWidget(self.model_path_display, 1, 1)
......
...@@ -195,7 +195,7 @@ class HistoryVideoPanel(QtWidgets.QWidget): ...@@ -195,7 +195,7 @@ class HistoryVideoPanel(QtWidgets.QWidget):
nvr_layout.addWidget(nvr_label) nvr_layout.addWidget(nvr_label)
self.nvrAddressEdit = QtWidgets.QLineEdit() self.nvrAddressEdit = QtWidgets.QLineEdit()
self.nvrAddressEdit.setPlaceholderText("请输入NVR地址...") self.nvrAddressEdit.setPlaceholderText("NVR历史回放功能开发中,敬请期待。")
self.nvrAddressEdit.setFont(FontManager.getMediumFont()) self.nvrAddressEdit.setFont(FontManager.getMediumFont())
self.nvrAddressEdit.setStyleSheet(""" self.nvrAddressEdit.setStyleSheet("""
QLineEdit { QLineEdit {
......
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