# 自动作业内嵌页面子类 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界面:将当前业务类实例传入setupUi,UI组件成为实例属性 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()