Commit 4f8ebab8 by Yuhaibo

1

parent 21a67d1a
......@@ -1240,6 +1240,9 @@ class MainWindow(
# 默认显示第一个子页面(数据采集)
self.datasetStackWidget.setCurrentIndex(0)
# 连接切换信号,实现切换时刷新文件列表
self.datasetStackWidget.currentChanged.connect(self._onDatasetSubPageChanged)
page_layout.addWidget(self.datasetStackWidget)
return page
......@@ -1369,6 +1372,21 @@ class MainWindow(
self.datasetStackWidget.setCurrentIndex(2) # 切换到数据标注子页面
self.statusBar().showMessage(self.tr("当前页面: 数据集管理 - 数据标注"))
def _onDatasetSubPageChanged(self, index):
"""
数据集子页面切换时的回调
Args:
index: 当前子页面索引(0=数据采集, 1=数据预处理, 2=数据标注, 3=模型训练)
"""
# 刷新数据采集和数据预处理页面的左侧文件列表
if index == 0: # 数据采集
if hasattr(self, 'dataCollectionPanel') and self.dataCollectionPanel:
self.dataCollectionPanel.refreshFolders()
elif index == 1: # 数据预处理
if hasattr(self, 'dataPreprocessPanel') and self.dataPreprocessPanel:
self.dataPreprocessPanel.refreshFolders()
def _showModelSetsTab(self):
"""显示模型集管理选项卡"""
self.showModelPage() # 先切换到模型管理页面
......
......@@ -184,12 +184,12 @@ class DataCollectionChannelHandler:
if channel_config:
success = self._connectRealChannel(channel_config)
if not success:
error_detail = f"无法连接到配置的通道 {channel_source}\n请检查:\n1. 相机是否已开机并连接到网络\n2. IP地址和端口是否正确"
error_detail = f"无法连接到配置的通道 {channel_source}\n请检查:\n 相机是否已开机并连接到网络\n2. IP地址和端口是否正确"
else:
# 如果没有配置,尝试直接连接USB通道
success = self._connectUSBChannel(channel_source)
if not success:
error_detail = f"无法连接到USB通道 {channel_source}\n请检查:\n1. USB相机是否已连接\n2. 相机驱动是否已安装\n3. 相机是否被其他程序占用"
error_detail = f"无法连接到USB通道 {channel_source}\n请检查:\nUSB相机是否已连接\n2. 相机驱动是否已安装\n3. 相机是否被其他程序占用"
else:
# 如果是RTSP地址,直接连接
success = self._connectRTSPChannel(channel_source)
......@@ -853,6 +853,9 @@ class DataCollectionChannelHandler:
self._dc_video_writer.release()
self._dc_video_writer = None
# 等待文件系统完成写入(确保文件完全写入磁盘)
time.sleep(0.5)
return True
except Exception as e:
......
......@@ -116,14 +116,21 @@ class SettingsHandler:
def showAbout(self):
"""显示关于对话框"""
QtWidgets.QMessageBox.about(
self,
self.tr("关于"),
self.tr(
try:
from widgets.style_manager import DialogManager
except ImportError:
DialogManager = None
message = (
"<h2>帕特智能油液位检测</h2>"
"<p>版本: 1.0</p>"
)
)
if DialogManager:
DialogManager.show_about(self, "关于", message)
else:
# 降级方案:使用标准对话框
QtWidgets.QMessageBox.about(self, "关于", message)
def showDocumentation(self):
"""显示帮助文档 - 打开用户手册"""
......
......@@ -511,6 +511,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
folder_path = osp.join(self._root_path, folder_name)
if not osp.exists(folder_path):
print(f"[数据采集] 文件夹不存在: {folder_path}")
return
try:
......@@ -519,6 +520,8 @@ class DataCollectionPanel(QtWidgets.QWidget):
if osp.isfile(osp.join(folder_path, f))]
files.sort()
print(f"[数据采集] 在文件夹 {folder_name} 中找到 {len(files)} 个文件")
# 添加到列表
for file in files:
file_path = osp.join(folder_path, file)
......@@ -543,8 +546,9 @@ class DataCollectionPanel(QtWidgets.QWidget):
if thumbnail:
item.setIcon(QtGui.QIcon(thumbnail))
else:
# 缩略图生成失败,不显示图标(避免在录制过程中显示播放按钮)
item.setIcon(QtGui.QIcon()) # 空图标
# 缩略图生成失败,使用默认视频图标
icon = self.style().standardIcon(QtWidgets.QStyle.SP_MediaPlay)
item.setIcon(icon)
item.setText(f"\n{display_name}")
elif file_ext in ['.jpg', '.jpeg', '.png', '.bmp']:
# 图片文件 - 加载图片作为缩略图
......@@ -575,11 +579,19 @@ class DataCollectionPanel(QtWidgets.QWidget):
"""生成视频缩略图(提取第一帧)"""
try:
import cv2
import time
# 打开视频文件
# 尝试多次打开视频文件(刚录制完成的文件可能需要等待)
cap = None
for attempt in range(3):
cap = cv2.VideoCapture(video_path)
if cap.isOpened():
break
if cap:
cap.release()
time.sleep(0.1) # 等待100ms后重试
if not cap.isOpened():
if not cap or not cap.isOpened():
return None
# 读取第一帧
......@@ -589,6 +601,11 @@ class DataCollectionPanel(QtWidgets.QWidget):
if not ret or frame is None:
return None
# 检查 QGuiApplication 是否存在(避免应用关闭时出错)
from qtpy.QtWidgets import QApplication
if not QApplication.instance():
return None
# 转换颜色空间 BGR -> RGB
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
......@@ -613,6 +630,11 @@ class DataCollectionPanel(QtWidgets.QWidget):
def _generateImageThumbnail(self, image_path):
"""生成图片缩略图"""
try:
# 检查 QGuiApplication 是否存在(避免应用关闭时出错)
from qtpy.QtWidgets import QApplication
if not QApplication.instance():
return None
# 加载图片
pixmap = QtGui.QPixmap(image_path)
......@@ -635,11 +657,11 @@ class DataCollectionPanel(QtWidgets.QWidget):
"""检查文件是否正在被录制"""
try:
# 检查父窗口是否有录制状态信息
if not hasattr(self._parent, '_dc_save_flag'):
if not hasattr(self._parent, '_dc_video_recording'):
return False
# 如果没有在录制,返回False
if not getattr(self._parent, '_dc_save_flag', False):
if not getattr(self._parent, '_dc_video_recording', False):
return False
# 检查是否是当前录制的文件
......@@ -657,7 +679,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
except (IOError, OSError):
# 文件被占用,可能正在录制
# 但只有在确实在录制状态时才返回True
return getattr(self._parent, '_dc_save_flag', False)
return getattr(self._parent, '_dc_video_recording', False)
except Exception as e:
# 发生异常时,为安全起见不隐藏文件
......@@ -923,7 +945,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
if self._current_folder:
self._loadFolderContent(self._current_folder)
self._showInformation("成功", f"文件已删除\n{file_name}")
except Exception as e:
self._showCritical("错误", f"删除文件失败:\n{str(e)}")
......@@ -1152,9 +1174,12 @@ class DataCollectionPanel(QtWidgets.QWidget):
self.btn_record_video.clicked.connect(self._onRecordVideo)
if success:
print(f"[数据采集] 录制停止成功,准备刷新文件列表")
print(f"[数据采集] 当前文件夹: {self._current_folder}")
# 刷新内容列表(显示新录制的视频)
if self._current_folder:
self._loadFolderContent(self._current_folder)
print(f"[数据采集] 文件列表已刷新")
else:
self._showWarning("录制失败", "录制时间过短,未能保存任何视频帧\n请确保录制时间足够长")
else:
......
......@@ -6,8 +6,33 @@
包含三个主要管理器:
1. FontManager - 字体管理器
2. DialogMana 对话框管理器
2. DialogManager - 对话框管理器
3. ButtonStyleManager - 按钮样式管理器
对话框文本对齐方式使用示例:
-----------------------------
from widgets.style_manager import DialogManager
# 1. 左对齐(默认,适用于多行列表或详细说明)
DialogManager.show_warning(
self, "警告",
"请检查以下问题:\n1. 相机是否开机\n2. 网络是否连接\n3. IP地址是否正确"
# text_alignment=DialogManager.ALIGN_LEFT # 默认值,可省略
)
# 2. 居中对齐(适用于简短消息)
DialogManager.show_information(
self, "提示",
"操作成功完成",
text_alignment=DialogManager.ALIGN_CENTER
)
# 3. 右对齐(较少使用,特殊场景)
DialogManager.show_critical(
self, "错误",
"系统错误\n错误代码: 500",
text_alignment=DialogManager.ALIGN_RIGHT
)
"""
import os
......@@ -212,20 +237,30 @@ class DialogManager:
# 默认样式(使用Qt5默认按钮样式)
# 🔥 移除了font-size设置,改用FontManager统一管理字体
# 🔥 移除了固定高度限制,改为根据内容自适应
# 🔥 移除了固定对齐方式,改为通过参数动态设置
DEFAULT_STYLE = """
QMessageBox {
min-width: 400px;
min-height: 180px;
}
QLabel {
min-height: 60px;
qproperty-alignment: 'AlignCenter';
}
"""
# 文本对齐方式常量
ALIGN_LEFT = QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter
ALIGN_CENTER = QtCore.Qt.AlignCenter
ALIGN_RIGHT = QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter
@staticmethod
def _create_base_dialog(parent, title, message, icon_type):
"""创建基础对话框"""
def _create_base_dialog(parent, title, message, icon_type, text_alignment=None):
"""创建基础对话框
Args:
parent: 父窗口
title: 对话框标题
message: 消息文本
icon_type: 图标类型
text_alignment: 文本对齐方式(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT),默认为左对齐
"""
msg_box = QtWidgets.QMessageBox(parent)
msg_box.setWindowTitle(title)
msg_box.setText(message)
......@@ -248,9 +283,73 @@ class DialogManager:
# 🔥 应用全局字体管理器到对话框及其所有子控件
FontManager.applyToWidgetRecursive(msg_box)
# 🔥 设置文本对齐方式(默认左对齐)
if text_alignment is None:
text_alignment = DialogManager.ALIGN_LEFT
DialogManager._set_text_alignment(msg_box, text_alignment)
# 🔥 根据文本内容自动调整对话框大小
DialogManager._adjust_dialog_size(msg_box, message)
return msg_box
@staticmethod
def _set_text_alignment(msg_box, alignment):
"""设置对话框文本对齐方式
Args:
msg_box: QMessageBox对象
alignment: Qt对齐方式(Qt.AlignLeft, Qt.AlignCenter, Qt.AlignRight)
"""
try:
# 查找对话框中的QLabel(消息文本标签)
for label in msg_box.findChildren(QtWidgets.QLabel):
# 只设置消息文本标签的对齐方式,不影响其他标签
if label.text() and not label.pixmap():
label.setAlignment(alignment)
except Exception as e:
pass
@staticmethod
def _adjust_dialog_size(msg_box, message):
"""根据文本内容自动调整对话框大小
Args:
msg_box: QMessageBox对象
message: 消息文本
"""
try:
# 计算文本行数
lines = message.split('\n')
line_count = len(lines)
# 计算最长行的字符数(考虑HTML标签)
import re
max_chars = 0
for line in lines:
# 移除HTML标签来计算实际字符数
clean_line = re.sub(r'<[^>]+>', '', line)
max_chars = max(max_chars, len(clean_line))
# 根据行数和字符数动态计算宽度和高度
# 基础宽度400px,每个字符约12px
base_width = 400
char_width = 12
calculated_width = max(base_width, min(max_chars * char_width + 100, 800))
# 基础高度150px,每行约30px
base_height = 150
line_height = 30
calculated_height = base_height + (line_count * line_height)
# 设置最小尺寸(让对话框至少有这么大)
msg_box.setMinimumSize(calculated_width, calculated_height)
except Exception as e:
# 如果计算失败,使用默认尺寸
pass
@staticmethod
def _set_chinese_button_texts(msg_box, button_texts=None):
"""设置按钮为中文文本"""
# 默认中文按钮文本映射
......@@ -280,11 +379,19 @@ class DialogManager:
btn.setText(text)
@staticmethod
def show_warning(parent, title, message):
"""显示警告对话框"""
def show_warning(parent, title, message, text_alignment=None):
"""显示警告对话框
Args:
parent: 父窗口
title: 标题
message: 消息文本
text_alignment: 文本对齐方式(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT),默认左对齐
"""
msg_box = DialogManager._create_base_dialog(
parent, title, message,
QtWidgets.QStyle.SP_MessageBoxWarning
QtWidgets.QStyle.SP_MessageBoxWarning,
text_alignment
)
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
DialogManager._set_chinese_button_texts(msg_box)
......@@ -295,11 +402,19 @@ class DialogManager:
msg_box.exec_()
@staticmethod
def show_information(parent, title, message):
"""显示信息对话框"""
def show_information(parent, title, message, text_alignment=None):
"""显示信息对话框
Args:
parent: 父窗口
title: 标题
message: 消息文本
text_alignment: 文本对齐方式(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT),默认左对齐
"""
msg_box = DialogManager._create_base_dialog(
parent, title, message,
QtWidgets.QStyle.SP_MessageBoxInformation
QtWidgets.QStyle.SP_MessageBoxInformation,
text_alignment
)
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
DialogManager._set_chinese_button_texts(msg_box)
......@@ -310,11 +425,19 @@ class DialogManager:
msg_box.exec_()
@staticmethod
def show_critical(parent, title, message):
"""显示错误对话框"""
def show_critical(parent, title, message, text_alignment=None):
"""显示错误对话框
Args:
parent: 父窗口
title: 标题
message: 消息文本
text_alignment: 文本对齐方式(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT),默认左对齐
"""
msg_box = DialogManager._create_base_dialog(
parent, title, message,
QtWidgets.QStyle.SP_MessageBoxCritical
QtWidgets.QStyle.SP_MessageBoxCritical,
text_alignment
)
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
DialogManager._set_chinese_button_texts(msg_box)
......@@ -325,11 +448,21 @@ class DialogManager:
msg_box.exec_()
@staticmethod
def show_question(parent, title, message, yes_text="是", no_text="否"):
"""显示询问对话框"""
def show_question(parent, title, message, yes_text="是", no_text="否", text_alignment=None):
"""显示询问对话框
Args:
parent: 父窗口
title: 标题
message: 消息文本
yes_text: "是"按钮文本
no_text: "否"按钮文本
text_alignment: 文本对齐方式(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT),默认左对齐
"""
msg_box = DialogManager._create_base_dialog(
parent, title, message,
QtWidgets.QStyle.SP_MessageBoxQuestion
QtWidgets.QStyle.SP_MessageBoxQuestion,
text_alignment
)
# 设置按钮
......@@ -347,11 +480,21 @@ class DialogManager:
return result == QtWidgets.QMessageBox.Yes
@staticmethod
def show_question_warning(parent, title, message, yes_text="是", no_text="否"):
"""显示警告询问对话框(用于删除确认等危险操作)"""
def show_question_warning(parent, title, message, yes_text="是", no_text="否", text_alignment=None):
"""显示警告询问对话框(用于删除确认等危险操作)
Args:
parent: 父窗口
title: 标题
message: 消息文本
yes_text: "是"按钮文本
no_text: "否"按钮文本
text_alignment: 文本对齐方式(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT),默认左对齐
"""
msg_box = DialogManager._create_base_dialog(
parent, title, message,
QtWidgets.QStyle.SP_MessageBoxWarning
QtWidgets.QStyle.SP_MessageBoxWarning,
text_alignment
)
# 设置按钮
......@@ -369,9 +512,20 @@ class DialogManager:
return result == QtWidgets.QMessageBox.Yes
@staticmethod
def show_custom(parent, title, message, icon_type=None, buttons=None, button_texts=None, default_button=None):
"""显示自定义对话框"""
msg_box = DialogManager._create_base_dialog(parent, title, message, icon_type)
def show_custom(parent, title, message, icon_type=None, buttons=None, button_texts=None, default_button=None, text_alignment=None):
"""显示自定义对话框
Args:
parent: 父窗口
title: 标题
message: 消息文本
icon_type: 图标类型
buttons: 按钮组合
button_texts: 按钮文本字典
default_button: 默认按钮
text_alignment: 文本对齐方式(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT),默认左对齐
"""
msg_box = DialogManager._create_base_dialog(parent, title, message, icon_type, text_alignment)
# 设置按钮
if buttons:
......@@ -388,6 +542,33 @@ class DialogManager:
return msg_box.exec_()
@staticmethod
def show_about(parent, title, message, text_alignment=None):
"""显示关于对话框
Args:
parent: 父窗口
title: 对话框标题
message: 关于信息(支持HTML格式)
text_alignment: 文本对齐方式(ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT),默认左对齐
"""
msg_box = DialogManager._create_base_dialog(
parent, title, message,
QtWidgets.QStyle.SP_MessageBoxInformation,
text_alignment
)
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
DialogManager._set_chinese_button_texts(msg_box)
# 确保OK按钮文本为"确定"
ok_btn = msg_box.button(QtWidgets.QMessageBox.Ok)
if ok_btn:
ok_btn.setText("确定")
# 设置文本格式为富文本(支持HTML)
msg_box.setTextFormat(QtCore.Qt.RichText)
msg_box.exec_()
@staticmethod
def show_information_with_details(parent, title, message, detail_info="", custom_buttons=None):
"""显示带详细信息和自定义按钮的信息对话框
......@@ -512,6 +693,10 @@ def show_question_warning(parent, title, message, yes_text="是", no_text="否")
"""显示警告询问对话框(中文按钮)"""
return DialogManager.show_question_warning(parent, title, message, yes_text, no_text)
def show_about(parent, title, message):
"""显示关于对话框(中文按钮)"""
return DialogManager.show_about(parent, title, message)
# ============================================================================
# 按钮样式管理器 (Button Style Manager)
......
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