Files

223 lines
7.8 KiB
Python
Raw Permalink Normal View History

# 自动作业内嵌页面子类
from PySide6.QtCore import Slot, Qt, QTimer
from PySide6.QtWidgets import QWidget, QMessageBox, QLabel
from PySide6.QtGui import QImage, QPixmap
from wndCtrl.stateCtrl.clsSysState_autoproc import CStateAutoProc
from .uiSub_AutoPage import Ui_pageAutoProc
from msg_dict import g_uiCtrlScript, g_uiGeometrySize, g_errMsgText
from ..camera_img_get import Camera
import cv2 # 确保导入OpenCV
class CSubPageAutoProc(QWidget):
# public:
def __init__(self, widgetSize: tuple[int, int], parent=None):
super().__init__(parent)
# 挂载UI界面将当前业务类实例传入setupUiUI组件成为实例属性
self.ui = Ui_pageAutoProc()
self.ui.setupUi(self)
# 按需声明对应的成员变量
self.szStack = widgetSize
# 摄像头相关变量
self.cam0 = None # 第一个摄像头
self.cam1 = None # 第二个摄像头
self.timer = None # 定时器
self.camera_label = None # 专门用于显示摄像头的Label避免重复创建
pass
# 界面初始化
def uiInit(self) -> None:
self._editCtrlTitle()
self._screenAdapter() # 界面自适应
# 添加其他和界面或控件初始化相关的操作
self._changeWndStyle() # 设置成无框架边框
self._centerWidget() # 居中显示
# ---------------------------------------------------------------
self._setupSignalSlotMapping()
# 添加摄像头实时图片
self._camera_show()
pass
# -----------------------------------------
# private:
# 初始化修改页面控件文字
def _editCtrlTitle(self) -> None:
# 修改tab页面文字
self.ui.tabProc.setTabText(0, g_uiCtrlScript['PAGE_AUTOPROC_TAB_0'])
self.ui.tabProc.setTabText(1, g_uiCtrlScript['PAGE_AUTOPROC_TAB_1'])
# 界面自适应
def _screenAdapter(self) -> None:
self.resize(self.szStack[0], self.szStack[1])
self.ui.tabProc.setGeometry(g_uiGeometrySize['WND_MARGIN_HORI'], g_uiGeometrySize['WND_MARGIN_VERT'],
self.szStack[0] - g_uiGeometrySize['WND_MARGIN_HORI'] * 2,
self.szStack[1] - g_uiGeometrySize['WND_MARGIN_VERT'] * 2)
self._adjustTabCtrls() # 调整tab页内控件的位置及大小
pass
# 窗口居中显示
def _centerWidget(self) -> None:
pass
# 修改窗体属性
def _changeWndStyle(self) -> None:
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
pass
# 调整tab页面控件
def _adjustTabCtrls(self):
rctTemp = self.ui.grpCamera0.geometry()
nSize = (rctTemp.width(), rctTemp.height())
self.ui.grpCamera0.setGeometry(g_uiGeometrySize['WND_MARGIN_HORI'], 0, nSize[0], nSize[1])
# -------------------------------------------
# 建立信号槽连接
def _setupSignalSlotMapping(self) -> None:
# self.ui.btnProcStart.clicked.connect(self._onBtnProcStart)
self.ui.btnProcStop.clicked.connect(self._onBtnProcStop)
self.ui.btnReset.clicked.connect(self._onBtnReset)
pass
# ----------槽函数----------
# @Slot()
# def _onBtnProcStart(self):
# # 启动自动作业
# if g_warnState.checkSysWarning():
# QMessageBox.information(self, g_uiCtrlScript['MSG_TITLE_TIPS'], g_errMsgText['ERR_SYS_WARNING'])
# else:
#
# tProcJob = CProcThread()
# CStateAutoProc.setProcState(True)
# tProcJob.runProc()
# # 更新作业按钮的使能状态
# self.ui.btnProcStart.setEnabled(False)
# self.ui.btnProcStop.setEnabled(True)
# pass
@Slot()
def _onBtnProcStop(self):
# 停止自动作业
pass
@Slot()
def _onBtnReset(self):
pass
def _camera_show(self):
"""
初始化摄像头并启动实时显示
"""
try:
# 1. 初始化摄像头(保持打开状态)
self.cam0 = Camera()
if not self.cam0._open():
print("[Error] Failed to open camera")
QMessageBox.warning(self, "摄像头错误", "无法打开摄像头,请检查设备连接!")
return
# 2. 初始化显示用的Label
self._init_camera_label()
# 3. 创建定时器每50毫秒更新一次图像
self.timer = QTimer(self)
self.timer.timeout.connect(self._update_camera_image)
self.timer.start(10) # 50ms约20fps
print("[Info] Camera started successfully")
except Exception as e:
error_msg = f"摄像头初始化失败: {str(e)}"
print(f"[Error] {error_msg}")
QMessageBox.critical(self, "摄像头错误", error_msg)
def _init_camera_label(self):
"""
初始化摄像头显示用的Label只创建一次
"""
# 如果Label已存在直接返回
if self.camera_label is not None:
return
# 创建Label并设置属性
self.camera_label = QLabel(self.ui.fraCamera0)
# 设置Label充满父容器fraCamera0
self.camera_label.setGeometry(0, 0, self.ui.fraCamera0.width(), self.ui.fraCamera0.height())
# 设置图像自适应缩放
self.camera_label.setScaledContents(True)
# 设置对齐方式
self.camera_label.setAlignment(Qt.AlignCenter)
# 确保Label在最上层显示
self.camera_label.raise_()
def _update_camera_image(self):
"""
定时更新摄像头图像修复版
"""
try:
if self.cam0 is None or self.camera_label is None:
return
# 1. 获取摄像头图像
img = self.cam0.get_img()
if img is None or img.size == 0:
print("[Warning] 获取到空图像")
return
# 2. OpenCV图像是BGR格式需要转换为RGB
# 先检查图像通道数
if len(img.shape) == 3 and img.shape[2] == 3:
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
else:
# 灰度图像处理
img_rgb = img
# 3. 转换为QImage
h, w = img_rgb.shape[:2]
ch = 3 if len(img_rgb.shape) == 3 else 1
bytes_per_line = ch * w
if ch == 3:
q_img = QImage(img_rgb.data, w, h, bytes_per_line, QImage.Format_RGB888)
else:
q_img = QImage(img_rgb.data, w, h, bytes_per_line, QImage.Format_Grayscale8)
# 4. 转换为QPixmap并显示
pixmap = QPixmap.fromImage(q_img)
if not pixmap.isNull():
self.camera_label.setPixmap(pixmap)
except Exception as e:
print(f"[Error] 更新摄像头图像失败: {e}")
# 不中断程序,继续尝试
def resizeEvent(self, event):
"""
窗口大小变化时同步调整摄像头显示Label的大小
"""
super().resizeEvent(event)
if self.camera_label is not None and self.ui.fraCamera0 is not None:
self.camera_label.setGeometry(0, 0, self.ui.fraCamera0.width(), self.ui.fraCamera0.height())
def closeEvent(self, event):
"""
关闭窗口时释放摄像头资源增强版
"""
# 停止定时器
if self.timer is not None and self.timer.isActive():
self.timer.stop()
self.timer.deleteLater()
self.timer = None
# 释放摄像头资源
if self.cam0 is not None:
self.cam0._close()
self.cam0 = None
if self.cam1 is not None:
self.cam1._close()
self.cam1 = None
event.accept()