工控上位机控制系统通用UI框架
This commit is contained in:
223
wndMain/pageAutoPage/sub_uiAutoPage.py
Normal file
223
wndMain/pageAutoPage/sub_uiAutoPage.py
Normal file
@ -0,0 +1,223 @@
|
||||
# 自动作业内嵌页面子类
|
||||
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()
|
||||
Reference in New Issue
Block a user