基于QtPy (PySide6) 的PLC-HMI工程项目(十一)框架的进一步完善:UI的自动周期更新以及下行数据的生成和处理

一、改进变量表

增加一个更新周期的列,在Excel的数据验证里定义一个序列:0.5\1\3\60\3600,其含义是该变量在上位机中的读取周期,也就是其对应的槽函数(比如UI更新)的刷新周期。

修改生成变量表的脚本:

python 复制代码
def write_vari_table_file(excel_file: str, vari_file: str):
    """
    把excel变量表写到python格式的变量表中并定义变量
    :param excel_file: excel变量表写
    :param vari_file: python格式的变量表
    :return:
    """
    df = pd.read_excel(excel_file)
    variables = "variables = ["
    with open(vari_file, "w", encoding="utf-8") as f:
        f.write("from .TCP_comm import UiVari\n")
        # 读取Excel文件的每一行
        for _, row in df.iterrows():
            name, typ, addr, period = row[0], row[1], row[2], row[3]  # 变量表的行,必须是4列:名称、类型、地址、周期
            if pd.isna(name) or name.strip() == "":  # 去除空行
                continue
            area, db_num, offset, bit = parse_address(addr)
            f.write(f"{name}=UiVari(\n    typ= '{typ}',\n"
                    f"    byte_count={type_bytes[typ]},\n"
                    f"    area= '{area}',\n"
                    f"    DBnum= {db_num},\n"
                    f"    offset={offset},\n"
                    f"    bit={bit}\n)\n")
            period = int(float(period) * 1000)
            variables += f"[{name}, {period}], "

        variables += ']'
        f.write(variables)

新生成的变量表,所有变量的列表中,每个变量都附加了周期信息:

二、下行报文组态

由于需要传递bool变量,与上行报文不同的是,下行报文多了一个位(bit)信息,以DB1.DBX0.1 = 1为例:

  • 如果传递的不是bool,位信息则固定为16#FFFF:

三、将上行报文定义为具有valueChanged信号的QObject,并增加上行报文解析线程。

四、初步可运行的上位机和运行效果

所有上位机代码见附件。

  • 目录结构:

build_varis.py:

python 复制代码
import pandas as pd
type_bytes = {'Byte': 1,'Bool': 1, 'Int': 2, 'Real': 4, 'Word':2,
              'DInt':4, 'DWord':4, 'LInt':4, 'LWord':4, 'LReal':8}


def parse_address(addr: str):
    """
    解析Excel变量表的变量地址,解析出区域、偏移、位
    :param addr:
    :return:
    """
    out = []
    s = ''
    addr = addr.replace('%', '')
    addr += '.'
    # 取出地址文字串中每个"."之前的连续的数字,;例如DB10.DBX100.0的结果:[10,100,0]
    for b in addr:
        if b.isdigit():
            s += b
        if b == '.' and s != '':
            out.append(int(s))
            s = ''
    bit = -1
    if addr.startswith('DB'):
        area = 'DB'
    elif addr.startswith('I'):
        area = 'I'
        out.insert(0, 0)
    elif addr.startswith('Q'):
        area = 'Q'
        out.insert(0, 0)
    elif addr.startswith('M'):
        area = 'M'
        out.insert(0, 0)
    else:
        raise ValueError(f"无法解析地址: {addr}")

    if len(out) == 3:
        db, offset, bit = out[0], out[1], out[2]
    elif len(out) == 2:
        db, offset = out[0], out[1]
    else:
        raise ValueError(f"无法解析地址: {addr}")

    return area, db, offset, bit

def write_vari_table_file(excel_file: str, vari_file: str):
    """
    把excel变量表写到python格式的变量表中并定义变量
    :param excel_file: excel变量表写
    :param vari_file: python格式的变量表
    :return:
    """
    df = pd.read_excel(excel_file)
    variables = "variables = ["
    with open(vari_file, "w", encoding="utf-8") as f:
        f.write("from .PLC import UiVari\n")
        # 读取Excel文件的每一行
        for _, row in df.iterrows():
            name, typ, addr, period = row[0], row[1], row[2], row[3]  # 变量表的行,必须是4列:名称、类型、地址、周期
            if pd.isna(name) or name.strip() == "":  # 去除空行
                continue
            area, db_num, offset, bit = parse_address(addr)
            f.write(f"{name}=UiVari(\n    typ= '{typ}',\n"
                    f"    byte_count={type_bytes[typ]},\n"
                    f"    area= '{area}',\n"
                    f"    DBnum= {db_num},\n"
                    f"    offset={offset},\n"
                    f"    bit={bit}\n)\n")
            period = int(float(period) * 1000)
            variables += f"[{name}, {period}], "

        variables += ']'
        f.write(variables)

if __name__ == "__main__":
    write_vari_table_file("PLC1Tags.xlsx", "变量表.py")

PLC.py:

python 复制代码
import socket
import struct
from typing import NamedTuple

import numpy as np
from PySide6.QtCore import QObject, Signal, QTimer, Slot, QMutex, QThread, QMutexLocker

from .settings import *

# 字节长度的字典
type_bytes = {'Byte': 1,'Bool': 1, 'Int': 2, 'Real': 4, 'Word':2,
              'DInt':4, 'DWord':4, 'LInt':4, 'LWord':4, 'LReal':8}

def set_bit(b: bytes,  bit_idx: int, value: int) -> bytes:
    """
    修改 bytes 变量的某一位
    :param b: 原始字节
    :param bit_idx: 要修改的位下标(0~7,0 是最低位)
    :param value: 目标值 0 或 1
    :return: 修改后的新 bytes
    """
    # 转成可变的 bytearray
    arr = bytearray(b)

    # 取出目标字节
    byte_val = arr[0]
    if value == 1:
        # 置 1:按位或 |
        # b = 1 << bit_idx
        # byte_val = byte_val | b
        byte_val |= 1 << bit_idx
    else:
        # 置 0:按位与 & 取反 ~
        byte_val &= ~(1 << bit_idx)
    # 写回
    arr[0] = byte_val
    # 转回 bytes
    return bytes(arr)

def get_bit(byte_val: bytes, bit_idx: int) -> int:
    """
    判断一个字节的某一位是 0 还是 1
    :param byte_val: 输入字节(只判断第一个字节)
    :param bit_idx: 位索引(0~7,0=最低位)
    :return: 0 或 1
    """
    return 1 if (byte_val[0] & (1 << bit_idx)) != 0 else 0

# 区域变量
class AreaVar(NamedTuple):
    area: str  # I、Q、M、DB
    DBnum: int  # DB号(I/Q/M=0)
    offset: int  # 字节偏移
    byte_count: int  # 字节数
    value_bytes: bytes= b''  # 数据的字节

    def __eq__(self, other):
        return self.value_bytes == other.value_bytes

# UI变量
class UiVari(QObject):
    valueChanged = Signal(object)
    def __init__(self, typ:str, byte_count:int, area:str, offset:int, DBnum=0, bit=0, value=None ):
        """
        UI变量,用来与UI部件交互和触发通信操作
        :param typ:
        :param typ: 类型
        :param byte_count: 字节数
        :param area: 区域
        :param offset: 地址偏移
        :param DBnum: DB编号
        :param bit: 位
        :param value: 值
        """
        super().__init__()
        self.typ = typ
        self.byte_count = byte_count
        self.area = area
        self.DBnum = DBnum
        self.offset = offset
        self.bit = bit
        self._value = value

    def __eq__(self, other):
        return self.value == other.value


    @property
    def value(self):
        """获取变量值"""
        return self._value

    @value.setter
    def value(self, new_val):
        """设置值,变化时自动发射信号"""
        if self._value != new_val:
            self._value = new_val
            self.valueChanged.emit(new_val)

    def set_value(self, val):
        """外部设置值接口(语义更清晰)"""
        self.value = val

# 上行报文变量
class UplinkMsg(QObject):
    valueChanged = Signal(object)
    def __init__(self):
        super().__init__()
        self._value = b''

    @property
    def value(self):
        """获取变量值"""
        return self._value

    @value.setter
    def value(self, new_val):
        """设置值,变化时自动发射信号"""
        if self._value != new_val:
            self._value = new_val
            self.valueChanged.emit(new_val)

    def set_value(self, val):
        """外部设置值接口(语义更清晰)"""
        self.value = val


# Numpy格式数据区存储(支持 I/Q/M/DB)
class DataStore:
    def __init__(self, max_db_number: int = 2048, area_size: int = 2048):
        """
        统一数据存储:I、Q、M、DB
        :param max_db_number: 最大 DB 块号
        :param area_size: 每个区域默认大小(字节)
        """
        self.area_size = area_size

        # I / Q / M 区:一维数组(DBnum=0)
        self.I_area = np.zeros(area_size, dtype=np.uint8)  # I区
        self.Q_area = np.zeros(area_size, dtype=np.uint8)  # Q区
        self.M_area = np.zeros(area_size, dtype=np.uint8)  # M区

        # DB区:二维数组 [DB号][偏移]
        self.DB_area = np.zeros((max_db_number + 1, area_size), dtype=np.uint8)

# 变量表管理器:按变量名直接读写
class VariManager:
    def __init__(self, store: DataStore):
        """
        变量表管理器:按变量名直接读写
        :param store: 变量存储区
        """
        self.store = store
        self.vari_lock = QMutex()
        self.store_lock = QMutex()

    # UiVari变量转为AreaVar变量
    def UiVari2AreaVar(self, ui_vari:UiVari):
    # def pack_value(self, ui_vari:UiVari, value):
        typ = ui_vari.typ  # 变量格式

        value_bytes = b''

        # 先构造一个AreaVar变量

        area_var = AreaVar(
            area=ui_vari.area,
            DBnum=ui_vari.DBnum,
            offset=ui_vari.offset,
            byte_count=ui_vari.byte_count
        )
        if ui_vari.value is not None:
            value = ui_vari.value
            # 打包成 bytes
            if typ == 'Bool':
                value_bytes = self.read_block(area_var)
                bit = ui_vari.bit
                value_bytes = set_bit(value_bytes, bit, value)
            elif typ == 'Byte':
                value_bytes = value
            elif typ == 'Int':
                value_bytes = struct.pack('>h', value)  # 大端 Int16
            elif typ == 'Real':
                value_bytes = struct.pack('>f', value)  # 大端 Float32
            elif typ == 'Word' or typ == 'DWord' or typ == 'LWord':
                value_bytes = value
            elif typ == 'LInt':
                value_bytes = struct.pack('>i', value)
            elif typ == 'LReal':
                value_bytes = struct.pack('>d', value)
            else:
                raise TypeError(f"不支持类型: {typ}")

        area_var = AreaVar(
            area=ui_vari.area,
            DBnum=ui_vari.DBnum,
            offset=ui_vari.offset,
            byte_count=ui_vari.byte_count,
            value_bytes=value_bytes
        )
        return area_var


    # ------------------- 按变量 写值 -------------------
    def write_vari(self, ui_vari:UiVari, value):
        ui_vari.set_value(value)
        with QMutexLocker(self.vari_lock):
            area_var = self.UiVari2AreaVar(ui_vari)
            self.write_block(area_var)

    # ------------------- 按变量 读值 -------------------
    def read_vari(self, ui_vari:UiVari):
        with QMutexLocker(self.vari_lock):
            typ = ui_vari.typ  # 变量格式
            # 先构造一个AreaVar变量
            area_var =self.UiVari2AreaVar(ui_vari)
            # 读取变量字节串
            data = self.read_block(area_var)
            # 解析值
            if typ == 'Bool':
                value = get_bit(data, ui_vari.bit)
            elif typ == 'Byte':
                value = data
            elif typ == 'Int':
                value = struct.unpack('>h', data)[0]
            elif typ == 'Real':
                value = struct.unpack('>f', data)[0]
            elif typ == 'Word' or typ == 'DWord' or typ == 'LWord':
                value = data
            elif typ == 'LInt':
                value = struct.unpack('>i', data)[0]
            elif typ == 'LReal':
                value = struct.unpack('>d', data)[0]
            else:
                raise TypeError(f"不支持类型: {typ}")

            # 将变量本身的value也修改
            ui_vari.set_value(value)
            # print(ui_vari)
            return value

    # ------------------- 按块 写值 -------------------
    def write_block(self, area_var: AreaVar):
        """统一写入接口:支持 I/Q/M/DB"""
        with QMutexLocker(self.store_lock):
            data = np.frombuffer(area_var.value_bytes, dtype=np.uint8)
            start = area_var.offset
            end = start + area_var.byte_count

            if area_var.area == 'I':
                self.store.I_area[start:end] = data
            elif area_var.area == 'Q':
                self.store.Q_area[start:end] = data
            elif area_var.area == 'M':
                self.store.M_area[start:end] = data
            elif area_var.area == 'DB':
                self.store.DB_area[area_var.DBnum, start:end] = data
            else:
                raise ValueError(f"不支持的区域: {area_var.area}")

    # ------------------- 按块 读值 -------------------
    def read_block(self, area_var: AreaVar) -> bytes:
        """统一读取接口:支持 I/Q/M/DB"""
        with QMutexLocker(self.store_lock):
            start = area_var.offset
            end = start + area_var.byte_count

            if area_var.area == 'I':
                arr = self.store.I_area[start:end]
            elif area_var.area == 'Q':
                arr = self.store.Q_area[start:end]
            elif area_var.area == 'M':
                arr = self.store.M_area[start:end]
            elif area_var.area == 'DB':
                arr = self.store.DB_area[area_var.DBnum, start:end]
            else:
                raise ValueError(f"不支持的区域: {area_var.area}")

            return arr.tobytes()

# 用于TCP通信的周期运行的子线程工作者
class ThreadWorker(QObject):
    _signal_start = Signal()  # 开始运行的信号
    _signal_stop = Signal()  # 停止信号
    _signal_run_now = Signal()  # 打破定时器周期立即运行一次

    def __init__(self, target, looping, loop_interval=0, *args, **kwargs):
        """
        :param target: 需要在子线程中运行的目标函数
        :param looping: 是周期运行还是一次性任务
        :param loop_interval: 周期运行的间隙时间
        :param args: 附带参数
        :param kwargs:
        """
        super().__init__()
        self._loop_timer = None  # 循环运行定时器
        self.looping = looping  # 是否循环运行
        self.loop_interval = loop_interval  # 循环运行间隔
        self.target = target  # 目标函数
        self.args = args
        self.kwargs = kwargs
        self.started = False  # 已经开始
        self._signal_start.connect(self._start)
        self._signal_stop.connect(self._stop)
        self._signal_run_now.connect(self._run_target)

    # 内部接口,在子线程内用槽函数操作定时器
    @Slot()
    def _start(self):
        self._run_target()
        if self.looping:
            if self._loop_timer is None:
                self._loop_timer = QTimer()
                self._loop_timer.setInterval(self.loop_interval)
                self._loop_timer.timeout.connect(self._run_target)
            self._loop_timer.start()

    # 内部接口,在子线程内用槽函数操作定时器
    @Slot()
    def _stop(self):
        if self._loop_timer is not None:
            self._loop_timer.stop()

    # 外部接口,在调用线程内发射信号
    def start(self):
        self.started = True
        self._signal_start.emit()

    # 外部接口,在调用线程内发射信号
    def stop(self):
        self.started = False
        self._signal_stop.emit()

    # 外部接口,在调用线程内发射信号
    def run_now(self):
        self._signal_run_now.emit()

    # 槽函数,运行目标函数
    @Slot()
    def _run_target(self):
        if self._loop_timer is not None:
            self._loop_timer.stop()  # 停止定时器,防止信号堆积

        if self.started:
            self.target(*self.args, **self.kwargs)
        if self._loop_timer is not None:
            self._loop_timer.start()  # 重启定时器

# TCP客户端
class TcpClient(QObject):
    def __init__(self, ip, port):
        super().__init__()

        self.ip = ip
        self.port = port
        self.socket = None

        self.is_connected = False
        self.send_bytes = b""  # 发送的字节
        self.rsv_msg = UplinkMsg() # 接收到的字节

        self.rsv_lock = QMutex()
        self.send_lock = QMutex()

        ############## 创建线程和worker ################
        # 连接服务器
        self.connect_thread = QThread()  # 线程
        self.connect_worker = ThreadWorker(target=self.connect_server,
                                           looping=True,
                                           loop_interval=RECONNECT_INTERVAL)  # worker
        self.connect_worker.moveToThread(self.connect_thread)  # 把worker移动到线程中
        self.connect_thread.start()  # 启动线程

        # 在子线程中周期发送数据
        self.send_thread = QThread()  # 线程
        self.send_worker = ThreadWorker(target=self.send_data,
                                        looping=True,
                                        loop_interval=HEARTBEAT_INTERVAL)  # worker
        self.send_worker.moveToThread(self.send_thread)  # 把worker移动到线程中
        self.send_thread.start()  # 启动线程

        # 在子线程中持续接收数据
        self.recv_thread = QThread()  # 线程
        self.recv_worker = ThreadWorker(target=self.recv_data,
                                        looping=True,
                                        loop_interval=0)  # worker
        self.recv_worker.moveToThread(self.recv_thread)  # 把worker移动到线程中
        self.recv_thread.start()  # 启动线程

    def connect_server(self):
        """建立 TCP 连接"""
        if self.is_connected:
            return
        try:
            # 停止发送工作者
            self.send_worker.stop()
            # 停止接收工作者
            self.recv_worker.stop()

            # 创建 TCP socket
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.settimeout(CONNECT_TIMEOUT)
            self.socket.connect((self.ip, self.port))  # 连接服务器
            self.is_connected = True
            self.connect_worker.stop()  # 连接完成,停止连接worker
            print(f"✅ 成功连接到服务器 {self.ip}:{self.port}")
            # 启动发送工作者
            self.send_worker.start()
            # 启动接收工作者
            self.recv_worker.start()

        except Exception as e:
            print(f"❌ 连接失败,{RECONNECT_INTERVAL}秒后重试... 错误:{e}")
            self.is_connected = False
            # self.connect_worker.stop()
            # self.send_worker.stop()
            # self.recv_worker.stop()

    def send_data(self):
        """发送数据"""
        if not self.is_connected:
            print("⚠️ 未连接,无法发送")
            return False

        try:
            with QMutexLocker(self.send_lock):
                # self.send_bytes =
                # 发送数据
                self.socket.send(self.send_bytes)
                # print(f"📤 已发送:{self.send_bytes}")
                self.send_bytes = DOWNLINK_FRAME_HEAD + DOWNLINK_FRAME_END  # 发送完成后清空发送区
                return True
        except Exception as e:
            print(f"❌ 发送失败:{e}")
            self.is_connected = False
            self.send_worker.stop()
            self.recv_worker.stop()
            self.connect_worker.start()
            return False

    # 打破周期立即发送一个数据
    def send_now(self):
        self.send_worker.run_now()

    def recv_data(self):
        """接收数据(处理半包/粘包)"""
        if not self.is_connected:
            print("⚠️ 未连接,无法接收")
            return False
        buffer = b''  # 清空接收缓存区

        try:
            data = self.socket.recv(1024)
            if not data:
                print("🔌 服务器断开连接")
                self.is_connected = False
                self.send_worker.stop()
                self.recv_worker.stop()
                self.connect_worker.start()
                return False
            buffer += data
            with QMutexLocker(self.rsv_lock):
                self.rsv_msg.set_value(buffer)
            print(f"📥 收到数据:{buffer}")
        except socket.timeout:
            return True
        except Exception as e:
            print(f"❌ 接收异常:{e}")
            self.is_connected = False
            self.send_worker.stop()
            self.recv_worker.stop()
            self.connect_worker.start()

    def start(self):
        """启动客户端"""
        print(f"🚀 启动 TCP 客户端,目标:{self.ip}:{self.port}")
        self.connect_worker.start()

    def quit(self):
        self.is_connected = False
        self.connect_worker.stop()
        self.send_worker.stop()
        self.recv_worker.stop()
        self.connect_thread.quit()
        self.recv_thread.quit()
        self.send_thread.quit()

# 把TcpClient和PlcPartner整合成一个,然后定义一个处理上行帧的函数,下行数据加进去CRC
# PLC通信伙伴
class PlcPartner(QObject):
    def __init__(self, plc_ip, plc_port, vari_table):
        super().__init__()
        self.all_vari_list = None
        self.vs = DataStore()  # 创建变量存储区
        self.vm = VariManager(self.vs)    # 创建变量管理器
        self.client = TcpClient(plc_ip, plc_port)  # 客户端
        self.vari_table = vari_table  # 变量表
        self.update_workers =[]  # 周期更新变量的工作者们
        self.parse_uplink_worker = None  # 解析上行报文的工作者


    # 写PLC变量
    def write_vari(self, ui_vari: UiVari, value):
        self.vm.write_vari(ui_vari, value)  # 先写入本地

        # 如果是写一个单bit,把位(Int格式)打包成字节
        if ui_vari.typ == 'Bool':
            bit = ui_vari.bit
            bit_bytes = struct.pack('>i', bit)
        else:
            bit_bytes = b'0xffff'  # 如果不是写单个的bit,位字节为 ffff

        # 将Ui变量转为区域变量
        area_var = self.vm.UiVari2AreaVar(ui_vari)
        # 拼接下行报文
        area_var_bytes = self.AreaVar2msg(area_var)  # 把区域变量的信息转成字节携带在下行报文中
        send_bytes = b"".join([DOWNLINK_FRAME_HEAD, area_var_bytes, bit_bytes, area_var.value_bytes, DOWNLINK_FRAME_END])
        #生成CRC
        crc_bytes = CRC16.new(send_bytes).crcValue.to_bytes(2, byteorder='big')
        # crc_bytes = struct.pack('>i', crc_result)
        print(crc_bytes)
        with QMutexLocker(self.client.send_lock):  #DOWNLINK_FRAME_HEAD + DOWNLINK_FRAME_END
            self.client.send_bytes = send_bytes + crc_bytes
        # 发送报文到PLC
        self.send_now()

    def read_vari(self, ui_vari):
        # print('2')
        # with QMutexLocker(self.lock):
        v = self.vm.read_vari(ui_vari)
        return v

    def write_block(self, area_var: AreaVar):
        # with QMutexLocker(self.lock):
        self.vm.write_block(area_var)

    def read_block(self, area_var: AreaVar) -> bytes:
        # with QMutexLocker(self.lock):
        v = self.vm.read_block(area_var)
        return v

    def start(self):
        self.client.start()  # 启动客户端
        self.start_updater()  # 启动变量自动更新

    def quit(self):
        self.client.quit()
        self.quit_updater()

    # 打破周期立即发送
    def send_now(self):
        self.client.send_now()

    def AreaVar2msg(self, area_vari: AreaVar):
        # 把area变量的信息转换成字节
        if area_vari.area == "I":
            area_bytes = b'\x81\x81'
        elif area_vari.area == "Q":
            area_bytes = b'\x82\x82'
        elif area_vari.area == "M":
            area_bytes = b'\x83\x83'
        elif area_vari.area == "DB":
            area_bytes = b'\x84\x84'
        else:
            raise ValueError("下行报文组态错误:未识别的分区")

        # 把DB号转换成字节
        db_num_bytes = struct.pack('>i', area_vari.DBnum)
        #  把offset转换成字节
        offset_bytes = struct.pack('>i', area_vari.offset)
        # 把byte_count转换成字节
        byte_count_bytes = struct.pack('>i', area_vari.byte_count)

        out_bytes = b''.join([area_bytes, db_num_bytes, offset_bytes, byte_count_bytes])
        print(out_bytes)
        return out_bytes

    def get_vari_update_table(self,varies: list):
        """
        从变量表的所有变量列表中获取到每个周期需要更新的变量内容
        :param varies:
        :return:
        """
        periods = set()
        for v in varies:
            periods.add(v[1])

        periods = sorted(list(periods))

        varis = []  # 最终的输出结果
        for p in periods:  # 所有周期
            # print(p)
            o = []
            for v in varies:
                if v[1] == p:
                    o.append(v[0])
            varis.append(o)
        # print(periods, varis)
        return periods, varis

    # 开始更新变量
    def start_updater(self):
        variables = self.vari_table.variables
        all_period, self.all_vari_list = self.get_vari_update_table(variables)
        for i, p in enumerate(all_period):
            worker = ThreadWorker(target=self.update_vari,
                                  looping=True,
                                  loop_interval=p
                                  )
            th = QThread()
            worker.moveToThread(th)
            worker.start()
            th.start()
            self.update_workers.append([worker,th])  # 新建的更新worker和thread
        # 解析上行报文的工作者
        self.parse_uplink_worker = ThreadWorker(target=self.parse_uplink_msg,
                              looping=False  # 非定时器周期运行,每次run_now()运行一次
                              )
        th = QThread()
        self.parse_uplink_worker.moveToThread(th)
        self.parse_uplink_worker.start()
        th.start()
        self.update_workers.append([self.parse_uplink_worker,th])
        # 当上行报文的内容发生变化就解析一次
        self.client.rsv_msg.valueChanged.connect(self.parse_uplink_worker.run_now)

    def quit_updater(self):
        for worker in self.update_workers:
            worker[0].stop()
            worker[1].quit()

    # 更新变量(通过读取变量表中的变量和周期定义)
    def update_vari(self):
        for vari_list in self.all_vari_list:
            for vari in vari_list:
                self.read_vari(vari)
                # if value != vari.value:
                #     self.vm.write_vari(vari, value)

    @Slot()
    def parse_uplink_msg(self):
        msg_bytes = self.client.rsv_msg.value
        # print(msg_bytes)
        if msg_bytes == b'':
            return

        if len(msg_bytes) < 21:
            raise BufferError(f"❌数据校验失败:数据长度不足")
        head = msg_bytes[0:2]  # 帧头
        tail = msg_bytes[-4:-2]  # 帧尾
        if head != UPLINK_FRAME_HEAD or tail != UPLINK_FRAME_END:
            raise BufferError(f"❌数据校验失败:帧头尾错误")
        # CRC
        crc_int = int.from_bytes(msg_bytes[-2:], byteorder='big')
        crc_result = CRC16.new(msg_bytes[:-2]).crcValue
        if crc_result != crc_int:
            raise BufferError(f"❌数据校验失败:CRC失败")
        # 截取上行数据的有效部分
        up_data = msg_bytes[2:-4]

        pos = 0  # 定义一个指针,用来遍历字节
        AreaVars = []  # 输出的变量列表

        # 解析数据
        while pos < len(up_data):
            try:
                area = AREA_DICT[up_data[pos]]
            except KeyError:
                raise BufferError(f"❌数据校验失败:数据中区域代码错误")
            pos += 2

            DBnum = int.from_bytes(up_data[pos:pos + 4], byteorder='big')
            pos += 4

            offset = int.from_bytes(up_data[pos:pos + 4], byteorder='big')
            pos += 4

            byte_count = int.from_bytes(up_data[pos:pos + 4], byteorder='big')
            pos += 4

            bytes_get = up_data[pos:pos + byte_count]
            pos += byte_count
            AreaVars.append(AreaVar(area, DBnum, offset, byte_count, bytes_get))
            print(AreaVars)

        if pos != len(up_data):
            raise BufferError(f"❌数据校验失败:数据长度错误,解析失败!")

        # with QMutexLocker(self.lock):
        for var in AreaVars:
            self.write_block(var)

    

PLC.settings.py:

python 复制代码
import crcmod

PLC_IP = "127.0.0.1"  # 下位机服务器(PLC)的IP地址
PLC_PORT = 2001  # 下位机(PLC)端口
RECONNECT_INTERVAL = 8000  # 断线重连间隔(毫秒)
CONNECT_TIMEOUT = 5000  # 断线重连间隔(毫秒)
HEARTBEAT_INTERVAL = 1000  # 心跳包间隔(毫秒)
UPLINK_FRAME_HEAD = b'AA'      # 上行帧头
UPLINK_FRAME_END = b'BB'      # 上行帧尾
DOWNLINK_FRAME_HEAD = b'XX'      # 下行帧头
DOWNLINK_FRAME_END = b'YY'      # 下行帧尾
CRC16 = crcmod.predefined.Crc('modbus')  # CRC16预定义
AREA_DICT = {    # 区域字典
    0x81: "I",
    0x82: "Q",
    0x83: "M",
    0x84: "DB"
}

变量表.py:

python 复制代码
from .PLC import UiVari
油泵1按钮起=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'I',
    DBnum= 0,
    offset=0,
    bit=0
)
油泵1按钮停=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'I',
    DBnum= 0,
    offset=0,
    bit=1
)
油泵1压力IW=UiVari(
    typ= 'Int',
    byte_count=2,
    area= 'I',
    DBnum= 0,
    offset=22,
    bit=-1
)
油泵1工作=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'Q',
    DBnum= 0,
    offset=0,
    bit=0
)
油泵1指示=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'Q',
    DBnum= 0,
    offset=0,
    bit=1
)
油泵1超压=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'Q',
    DBnum= 0,
    offset=0,
    bit=2
)
油泵2按钮起=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'I',
    DBnum= 0,
    offset=1,
    bit=0
)
油泵2按钮停=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'I',
    DBnum= 0,
    offset=1,
    bit=1
)
油泵2压力IW=UiVari(
    typ= 'Int',
    byte_count=2,
    area= 'I',
    DBnum= 0,
    offset=24,
    bit=-1
)
油泵2工作=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'Q',
    DBnum= 0,
    offset=1,
    bit=0
)
油泵2指示=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'Q',
    DBnum= 0,
    offset=1,
    bit=1
)
油泵2超压=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'Q',
    DBnum= 0,
    offset=1,
    bit=2
)
油泵1屏幕启动=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'DB',
    DBnum= 4,
    offset=0,
    bit=0
)
油泵1屏幕停止=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'DB',
    DBnum= 4,
    offset=0,
    bit=1
)
油泵1屏按选择=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'DB',
    DBnum= 4,
    offset=0,
    bit=2
)
油泵1压力设定=UiVari(
    typ= 'Real',
    byte_count=4,
    area= 'DB',
    DBnum= 4,
    offset=2,
    bit=-1
)
油泵1压力显示=UiVari(
    typ= 'Real',
    byte_count=4,
    area= 'DB',
    DBnum= 4,
    offset=6,
    bit=-1
)
油泵2屏幕启动=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'DB',
    DBnum= 5,
    offset=0,
    bit=0
)
油泵2屏幕停止=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'DB',
    DBnum= 5,
    offset=0,
    bit=1
)
油泵2屏按选择=UiVari(
    typ= 'Bool',
    byte_count=1,
    area= 'DB',
    DBnum= 5,
    offset=0,
    bit=2
)
油泵2压力设定=UiVari(
    typ= 'Real',
    byte_count=4,
    area= 'DB',
    DBnum= 5,
    offset=2,
    bit=-1
)
油泵2压力显示=UiVari(
    typ= 'Real',
    byte_count=4,
    area= 'DB',
    DBnum= 5,
    offset=6,
    bit=-1
)
variables = [[油泵1按钮起, 1000], [油泵1按钮停, 1000], [油泵1压力IW, 3000], [油泵1工作, 1000], [油泵1指示, 1000], [油泵1超压, 3000], [油泵2按钮起, 1000], [油泵2按钮停, 1000], [油泵2压力IW, 3000], [油泵2工作, 1000], [油泵2指示, 1000], [油泵2超压, 3000], [油泵1屏幕启动, 500], [油泵1屏幕停止, 500], [油泵1屏按选择, 1000], [油泵1压力设定, 1000], [油泵1压力显示, 3000], [油泵2屏幕启动, 1000], [油泵2屏幕停止, 1000], [油泵2屏按选择, 1000], [油泵2压力设定, 1000], [油泵2压力显示, 3000], ]

all_forms.py:

python 复制代码
import os

from PySide6.QtCore import QRegularExpression
from PySide6.QtGui import QRegularExpressionValidator
from PySide6.QtWidgets import QMainWindow

from . import *
from ..settings import *


# 点亮/熄灭按钮
def set_lighting(widget, value):
    if value == 0:
        value = False
    widget.setProperty("light_up",value)
    widget.style().unpolish(widget)
    widget.style().polish(widget)
    widget.update()


def set_validator(widget, value):
    """
    数字输入的正则函数
    light_up^ 表示匹配字符串的开始位置。
    light_up-? 表示匹配一个可选的负号(-)。
    light_up\d+ 表示匹配一个或多个数字字符(0-9)。
    light_up\.? 表示匹配一个可选的小数点(.)。在正则表达式中,. 是一个特殊字符,需要用 \ 进行转义,因此写作 \.。
    light_up\d+ 表示匹配一个或多个数字字符。
    light_up$ 表示匹配字符串的结束位置。
    light_up如果希望可以输入负数,则正则表达式为:"^-?\d+\.?\d+$"
    light_up如果希望输入非负数,则正则表达式为: "^\d+\.?\d+$"
    """
    reg = QRegularExpression(value)
    validator = QRegularExpressionValidator()
    validator.setRegularExpression(reg)
    widget.setValidator(validator)

#######################################################################主窗口
class master_window(QMainWindow, mainWindow_ui.Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)

main_window = master_window()
# 设定按钮特性(绿灯按钮)
main_window.btn_start_P_1.setStyleSheet(GREEN_PUSHBUTTON)
main_window.btn_start_P_2.setStyleSheet(GREEN_PUSHBUTTON)
set_lighting(main_window.btn_start_P_1, False)
set_lighting(main_window.btn_start_P_2, False)
# 设置油泵实时压力显示标签
main_window.real_pressure_P_1.setStyleSheet(RED_SHOWING_LABEL)
main_window.real_pressure_P_2.setStyleSheet(RED_SHOWING_LABEL)
set_lighting(main_window.real_pressure_P_1, False)
set_lighting(main_window.real_pressure_P_2, False)
# 设置压力设置linedit的正则公式
set_validator(main_window.lineEdit_setting_1, "^\d+\.?\d+$")
set_validator(main_window.lineEdit_setting_2, "^\d+\.?\d+$")
# 设置分页容器的起始页面编号
main_window.stackedWidget.setCurrentIndex(1)

mainWindow.ui:

python 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QGroupBox" name="groupBox_2">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="title">
       <string/>
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout">
       <property name="leftMargin">
        <number>20</number>
       </property>
       <property name="rightMargin">
        <number>30</number>
       </property>
       <item alignment="Qt::AlignLeft">
        <widget class="QLabel" name="label_top_left">
         <property name="text">
          <string>TextLabel</string>
         </property>
        </widget>
       </item>
       <item alignment="Qt::AlignHCenter">
        <widget class="QLabel" name="label_top_mid">
         <property name="font">
          <font>
           <pointsize>16</pointsize>
          </font>
         </property>
         <property name="text">
          <string>油泵控制系统</string>
         </property>
        </widget>
       </item>
       <item alignment="Qt::AlignRight">
        <widget class="QLabel" name="label_top_right">
         <property name="text">
          <string>TextLabel</string>
         </property>
        </widget>
       </item>
      </layout>
     </widget>
    </item>
    <item>
     <widget class="QGroupBox" name="groupBox_3">
      <property name="title">
       <string/>
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout_2">
       <item alignment="Qt::AlignLeft">
        <widget class="QGroupBox" name="groupBox">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="minimumSize">
          <size>
           <width>200</width>
           <height>0</height>
          </size>
         </property>
         <property name="maximumSize">
          <size>
           <width>200</width>
           <height>16777215</height>
          </size>
         </property>
         <property name="title">
          <string/>
         </property>
         <layout class="QVBoxLayout" name="verticalLayout_2">
          <property name="spacing">
           <number>34</number>
          </property>
          <item>
           <spacer name="verticalSpacer_6">
            <property name="orientation">
             <enum>Qt::Vertical</enum>
            </property>
            <property name="sizeType">
             <enum>QSizePolicy::Fixed</enum>
            </property>
            <property name="sizeHint" stdset="0">
             <size>
              <width>20</width>
              <height>10</height>
             </size>
            </property>
           </spacer>
          </item>
          <item>
           <widget class="QPushButton" name="btn_setting">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
              <horstretch>0</horstretch>
              <verstretch>0</verstretch>
             </sizepolicy>
            </property>
            <property name="minimumSize">
             <size>
              <width>180</width>
              <height>50</height>
             </size>
            </property>
            <property name="maximumSize">
             <size>
              <width>180</width>
              <height>50</height>
             </size>
            </property>
            <property name="font">
             <font>
              <pointsize>13</pointsize>
             </font>
            </property>
            <property name="text">
             <string>参数设定画面</string>
            </property>
           </widget>
          </item>
          <item alignment="Qt::AlignTop">
           <widget class="QPushButton" name="btn_control">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
              <horstretch>0</horstretch>
              <verstretch>0</verstretch>
             </sizepolicy>
            </property>
            <property name="minimumSize">
             <size>
              <width>180</width>
              <height>50</height>
             </size>
            </property>
            <property name="maximumSize">
             <size>
              <width>180</width>
              <height>50</height>
             </size>
            </property>
            <property name="font">
             <font>
              <pointsize>13</pointsize>
             </font>
            </property>
            <property name="text">
             <string>油泵操作画面</string>
            </property>
           </widget>
          </item>
          <item>
           <spacer name="verticalSpacer">
            <property name="orientation">
             <enum>Qt::Vertical</enum>
            </property>
            <property name="sizeHint" stdset="0">
             <size>
              <width>20</width>
              <height>40</height>
             </size>
            </property>
           </spacer>
          </item>
         </layout>
        </widget>
       </item>
       <item>
        <widget class="QStackedWidget" name="stackedWidget">
         <property name="cursor">
          <cursorShape>ArrowCursor</cursorShape>
         </property>
         <property name="frameShape">
          <enum>QFrame::StyledPanel</enum>
         </property>
         <property name="currentIndex">
          <number>1</number>
         </property>
         <widget class="QWidget" name="page_contorl">
          <layout class="QHBoxLayout" name="horizontalLayout_3">
           <item>
            <spacer name="verticalSpacer_9">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeType">
              <enum>QSizePolicy::Fixed</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>5</width>
               <height>10</height>
              </size>
             </property>
            </spacer>
           </item>
           <item alignment="Qt::AlignTop">
            <widget class="QGroupBox" name="groupBox_4">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="minimumSize">
              <size>
               <width>210</width>
               <height>240</height>
              </size>
             </property>
             <property name="maximumSize">
              <size>
               <width>210</width>
               <height>290</height>
              </size>
             </property>
             <property name="title">
              <string/>
             </property>
             <layout class="QGridLayout" name="gridLayout">
              <property name="rightMargin">
               <number>6</number>
              </property>
              <item row="1" column="0">
               <widget class="QLabel" name="label_4">
                <property name="font">
                 <font>
                  <pointsize>15</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>1#油泵</string>
                </property>
               </widget>
              </item>
              <item row="6" column="0" colspan="2">
               <widget class="QPushButton" name="btn_stop_P_1">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Maximum">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>停    止</string>
                </property>
               </widget>
              </item>
              <item row="3" column="0">
               <widget class="QLabel" name="real_pressure_P_1">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>150</width>
                  <height>40</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>150</width>
                  <height>40</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="frameShape">
                 <enum>QFrame::Box</enum>
                </property>
                <property name="frameShadow">
                 <enum>QFrame::Raised</enum>
                </property>
                <property name="text">
                 <string/>
                </property>
               </widget>
              </item>
              <item row="3" column="1">
               <widget class="QLabel" name="label_7">
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>MPa</string>
                </property>
               </widget>
              </item>
              <item row="5" column="0" colspan="2">
               <widget class="QPushButton" name="btn_start_P_1">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>启    动</string>
                </property>
               </widget>
              </item>
              <item row="4" column="0">
               <spacer name="verticalSpacer_2">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>30</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="2" column="0">
               <spacer name="verticalSpacer_3">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeType">
                 <enum>QSizePolicy::Fixed</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>5</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="0" column="0">
               <spacer name="verticalSpacer_7">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>40</height>
                 </size>
                </property>
               </spacer>
              </item>
             </layout>
            </widget>
           </item>
           <item alignment="Qt::AlignTop">
            <widget class="QGroupBox" name="groupBox_5">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="minimumSize">
              <size>
               <width>210</width>
               <height>240</height>
              </size>
             </property>
             <property name="maximumSize">
              <size>
               <width>210</width>
               <height>290</height>
              </size>
             </property>
             <property name="title">
              <string/>
             </property>
             <layout class="QGridLayout" name="gridLayout_2">
              <property name="rightMargin">
               <number>6</number>
              </property>
              <item row="4" column="0">
               <spacer name="verticalSpacer_4">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>30</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="5" column="0" colspan="2">
               <widget class="QPushButton" name="btn_start_P_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>启    动</string>
                </property>
               </widget>
              </item>
              <item row="1" column="0">
               <widget class="QLabel" name="label_6">
                <property name="font">
                 <font>
                  <pointsize>15</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>2#油泵</string>
                </property>
               </widget>
              </item>
              <item row="3" column="0">
               <widget class="QLabel" name="real_pressure_P_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>150</width>
                  <height>40</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>150</width>
                  <height>40</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="frameShape">
                 <enum>QFrame::Box</enum>
                </property>
                <property name="frameShadow">
                 <enum>QFrame::Raised</enum>
                </property>
                <property name="text">
                 <string/>
                </property>
               </widget>
              </item>
              <item row="6" column="0" colspan="2">
               <widget class="QPushButton" name="btn_stop_P_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Maximum">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>停    止</string>
                </property>
               </widget>
              </item>
              <item row="2" column="0">
               <spacer name="verticalSpacer_5">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeType">
                 <enum>QSizePolicy::Fixed</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>5</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="3" column="1">
               <widget class="QLabel" name="label_8">
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>MPa</string>
                </property>
               </widget>
              </item>
              <item row="0" column="0">
               <spacer name="verticalSpacer_8">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>40</height>
                 </size>
                </property>
               </spacer>
              </item>
             </layout>
            </widget>
           </item>
          </layout>
         </widget>
         <widget class="QWidget" name="page_setting">
          <layout class="QHBoxLayout" name="horizontalLayout_4">
           <item>
            <spacer name="verticalSpacer_13">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeType">
              <enum>QSizePolicy::Fixed</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>5</width>
               <height>10</height>
              </size>
             </property>
            </spacer>
           </item>
           <item alignment="Qt::AlignTop">
            <widget class="QGroupBox" name="groupBox_7">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="minimumSize">
              <size>
               <width>210</width>
               <height>240</height>
              </size>
             </property>
             <property name="maximumSize">
              <size>
               <width>210</width>
               <height>290</height>
              </size>
             </property>
             <property name="title">
              <string/>
             </property>
             <layout class="QGridLayout" name="gridLayout_4">
              <item row="0" column="0">
               <spacer name="verticalSpacer_16">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>40</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="1" column="0">
               <widget class="QLabel" name="label_5">
                <property name="font">
                 <font>
                  <pointsize>15</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>1#油泵</string>
                </property>
               </widget>
              </item>
              <item row="2" column="0">
               <spacer name="verticalSpacer_15">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeType">
                 <enum>QSizePolicy::Fixed</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>5</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="3" column="0">
               <widget class="QLineEdit" name="lineEdit_setting_1">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>150</width>
                  <height>40</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>150</width>
                  <height>40</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <family>黑体</family>
                  <pointsize>11</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string/>
                </property>
               </widget>
              </item>
              <item row="3" column="1">
               <widget class="QLabel" name="label_11">
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>MPa</string>
                </property>
               </widget>
              </item>
              <item row="4" column="0">
               <spacer name="verticalSpacer_14">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>30</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="5" column="0" colspan="2">
               <widget class="QPushButton" name="btn_setting_ok_1">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>确   定</string>
                </property>
               </widget>
              </item>
              <item row="6" column="0" colspan="2">
               <widget class="QPushButton" name="btn_setting_cancel_1">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Maximum">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>取   消</string>
                </property>
               </widget>
              </item>
             </layout>
            </widget>
           </item>
           <item alignment="Qt::AlignTop">
            <widget class="QGroupBox" name="groupBox_6">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="minimumSize">
              <size>
               <width>210</width>
               <height>240</height>
              </size>
             </property>
             <property name="maximumSize">
              <size>
               <width>210</width>
               <height>290</height>
              </size>
             </property>
             <property name="title">
              <string/>
             </property>
             <layout class="QGridLayout" name="gridLayout_3">
              <property name="rightMargin">
               <number>6</number>
              </property>
              <item row="4" column="0">
               <spacer name="verticalSpacer_10">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>30</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="5" column="0" colspan="2">
               <widget class="QPushButton" name="btn_setting_ok_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>确   定</string>
                </property>
               </widget>
              </item>
              <item row="1" column="0">
               <widget class="QLabel" name="label_9">
                <property name="font">
                 <font>
                  <pointsize>15</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>2#油泵</string>
                </property>
               </widget>
              </item>
              <item row="6" column="0" colspan="2">
               <widget class="QPushButton" name="btn_setting_cancel_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Maximum">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>180</width>
                  <height>50</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>取   消</string>
                </property>
               </widget>
              </item>
              <item row="2" column="0">
               <spacer name="verticalSpacer_11">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeType">
                 <enum>QSizePolicy::Fixed</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>5</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="3" column="1">
               <widget class="QLabel" name="label_10">
                <property name="font">
                 <font>
                  <pointsize>13</pointsize>
                 </font>
                </property>
                <property name="text">
                 <string>MPa</string>
                </property>
               </widget>
              </item>
              <item row="0" column="0">
               <spacer name="verticalSpacer_12">
                <property name="orientation">
                 <enum>Qt::Vertical</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>20</width>
                  <height>40</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item row="3" column="0">
               <widget class="QLineEdit" name="lineEdit_setting_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>150</width>
                  <height>40</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>150</width>
                  <height>40</height>
                 </size>
                </property>
                <property name="font">
                 <font>
                  <family>黑体</family>
                  <pointsize>11</pointsize>
                 </font>
                </property>
               </widget>
              </item>
             </layout>
            </widget>
           </item>
          </layout>
         </widget>
        </widget>
       </item>
      </layout>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

mainWindow_ui.py:

python 复制代码
# -*- coding: utf-8 -*-

################################################################################
## Form generated from reading UI file 'mainWindow.ui'
##
## Created by: Qt User Interface Compiler version 6.6.3
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
    QFont, QFontDatabase, QGradient, QIcon,
    QImage, QKeySequence, QLinearGradient, QPainter,
    QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QGroupBox,
    QHBoxLayout, QLabel, QLineEdit, QMainWindow,
    QMenuBar, QPushButton, QSizePolicy, QSpacerItem,
    QStackedWidget, QStatusBar, QVBoxLayout, QWidget)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName(u"verticalLayout")
        self.groupBox_2 = QGroupBox(self.centralwidget)
        self.groupBox_2.setObjectName(u"groupBox_2")
        sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth())
        self.groupBox_2.setSizePolicy(sizePolicy)
        self.horizontalLayout = QHBoxLayout(self.groupBox_2)
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.horizontalLayout.setContentsMargins(20, -1, 30, -1)
        self.label_top_left = QLabel(self.groupBox_2)
        self.label_top_left.setObjectName(u"label_top_left")

        self.horizontalLayout.addWidget(self.label_top_left, 0, Qt.AlignLeft)

        self.label_top_mid = QLabel(self.groupBox_2)
        self.label_top_mid.setObjectName(u"label_top_mid")
        font = QFont()
        font.setPointSize(16)
        self.label_top_mid.setFont(font)

        self.horizontalLayout.addWidget(self.label_top_mid, 0, Qt.AlignHCenter)

        self.label_top_right = QLabel(self.groupBox_2)
        self.label_top_right.setObjectName(u"label_top_right")

        self.horizontalLayout.addWidget(self.label_top_right, 0, Qt.AlignRight)


        self.verticalLayout.addWidget(self.groupBox_2)

        self.groupBox_3 = QGroupBox(self.centralwidget)
        self.groupBox_3.setObjectName(u"groupBox_3")
        self.horizontalLayout_2 = QHBoxLayout(self.groupBox_3)
        self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
        self.groupBox = QGroupBox(self.groupBox_3)
        self.groupBox.setObjectName(u"groupBox")
        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Expanding)
        sizePolicy1.setHorizontalStretch(0)
        sizePolicy1.setVerticalStretch(0)
        sizePolicy1.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
        self.groupBox.setSizePolicy(sizePolicy1)
        self.groupBox.setMinimumSize(QSize(200, 0))
        self.groupBox.setMaximumSize(QSize(200, 16777215))
        self.verticalLayout_2 = QVBoxLayout(self.groupBox)
        self.verticalLayout_2.setSpacing(34)
        self.verticalLayout_2.setObjectName(u"verticalLayout_2")
        self.verticalSpacer_6 = QSpacerItem(20, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)

        self.verticalLayout_2.addItem(self.verticalSpacer_6)

        self.btn_setting = QPushButton(self.groupBox)
        self.btn_setting.setObjectName(u"btn_setting")
        sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
        sizePolicy2.setHorizontalStretch(0)
        sizePolicy2.setVerticalStretch(0)
        sizePolicy2.setHeightForWidth(self.btn_setting.sizePolicy().hasHeightForWidth())
        self.btn_setting.setSizePolicy(sizePolicy2)
        self.btn_setting.setMinimumSize(QSize(180, 50))
        self.btn_setting.setMaximumSize(QSize(180, 50))
        font1 = QFont()
        font1.setPointSize(13)
        self.btn_setting.setFont(font1)

        self.verticalLayout_2.addWidget(self.btn_setting)

        self.btn_control = QPushButton(self.groupBox)
        self.btn_control.setObjectName(u"btn_control")
        sizePolicy2.setHeightForWidth(self.btn_control.sizePolicy().hasHeightForWidth())
        self.btn_control.setSizePolicy(sizePolicy2)
        self.btn_control.setMinimumSize(QSize(180, 50))
        self.btn_control.setMaximumSize(QSize(180, 50))
        self.btn_control.setFont(font1)

        self.verticalLayout_2.addWidget(self.btn_control, 0, Qt.AlignTop)

        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.verticalLayout_2.addItem(self.verticalSpacer)


        self.horizontalLayout_2.addWidget(self.groupBox, 0, Qt.AlignLeft)

        self.stackedWidget = QStackedWidget(self.groupBox_3)
        self.stackedWidget.setObjectName(u"stackedWidget")
        self.stackedWidget.setCursor(QCursor(Qt.ArrowCursor))
        self.stackedWidget.setFrameShape(QFrame.StyledPanel)
        self.page_setting = QWidget()
        self.page_setting.setObjectName(u"page_setting")
        self.horizontalLayout_4 = QHBoxLayout(self.page_setting)
        self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
        self.verticalSpacer_13 = QSpacerItem(5, 10, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)

        self.horizontalLayout_4.addItem(self.verticalSpacer_13)

        self.groupBox_7 = QGroupBox(self.page_setting)
        self.groupBox_7.setObjectName(u"groupBox_7")
        sizePolicy2.setHeightForWidth(self.groupBox_7.sizePolicy().hasHeightForWidth())
        self.groupBox_7.setSizePolicy(sizePolicy2)
        self.groupBox_7.setMinimumSize(QSize(210, 240))
        self.groupBox_7.setMaximumSize(QSize(210, 290))
        self.gridLayout_4 = QGridLayout(self.groupBox_7)
        self.gridLayout_4.setObjectName(u"gridLayout_4")
        self.verticalSpacer_16 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.gridLayout_4.addItem(self.verticalSpacer_16, 0, 0, 1, 1)

        self.label_5 = QLabel(self.groupBox_7)
        self.label_5.setObjectName(u"label_5")
        font2 = QFont()
        font2.setPointSize(15)
        self.label_5.setFont(font2)

        self.gridLayout_4.addWidget(self.label_5, 1, 0, 1, 1)

        self.verticalSpacer_15 = QSpacerItem(20, 5, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)

        self.gridLayout_4.addItem(self.verticalSpacer_15, 2, 0, 1, 1)

        self.lineEdit_setting_1 = QLineEdit(self.groupBox_7)
        self.lineEdit_setting_1.setObjectName(u"lineEdit_setting_1")
        sizePolicy2.setHeightForWidth(self.lineEdit_setting_1.sizePolicy().hasHeightForWidth())
        self.lineEdit_setting_1.setSizePolicy(sizePolicy2)
        self.lineEdit_setting_1.setMinimumSize(QSize(150, 40))
        self.lineEdit_setting_1.setMaximumSize(QSize(150, 40))
        font3 = QFont()
        font3.setFamilies([u"\u9ed1\u4f53"])
        font3.setPointSize(11)
        self.lineEdit_setting_1.setFont(font3)

        self.gridLayout_4.addWidget(self.lineEdit_setting_1, 3, 0, 1, 1)

        self.label_11 = QLabel(self.groupBox_7)
        self.label_11.setObjectName(u"label_11")
        self.label_11.setFont(font1)

        self.gridLayout_4.addWidget(self.label_11, 3, 1, 1, 1)

        self.verticalSpacer_14 = QSpacerItem(20, 30, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.gridLayout_4.addItem(self.verticalSpacer_14, 4, 0, 1, 1)

        self.btn_setting_ok_1 = QPushButton(self.groupBox_7)
        self.btn_setting_ok_1.setObjectName(u"btn_setting_ok_1")
        sizePolicy2.setHeightForWidth(self.btn_setting_ok_1.sizePolicy().hasHeightForWidth())
        self.btn_setting_ok_1.setSizePolicy(sizePolicy2)
        self.btn_setting_ok_1.setMinimumSize(QSize(180, 50))
        self.btn_setting_ok_1.setMaximumSize(QSize(180, 50))
        self.btn_setting_ok_1.setFont(font1)

        self.gridLayout_4.addWidget(self.btn_setting_ok_1, 5, 0, 1, 2)

        self.btn_setting_cancel_1 = QPushButton(self.groupBox_7)
        self.btn_setting_cancel_1.setObjectName(u"btn_setting_cancel_1")
        sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Maximum)
        sizePolicy3.setHorizontalStretch(0)
        sizePolicy3.setVerticalStretch(0)
        sizePolicy3.setHeightForWidth(self.btn_setting_cancel_1.sizePolicy().hasHeightForWidth())
        self.btn_setting_cancel_1.setSizePolicy(sizePolicy3)
        self.btn_setting_cancel_1.setMinimumSize(QSize(180, 50))
        self.btn_setting_cancel_1.setMaximumSize(QSize(180, 50))
        self.btn_setting_cancel_1.setFont(font1)

        self.gridLayout_4.addWidget(self.btn_setting_cancel_1, 6, 0, 1, 2)


        self.horizontalLayout_4.addWidget(self.groupBox_7, 0, Qt.AlignTop)

        self.groupBox_6 = QGroupBox(self.page_setting)
        self.groupBox_6.setObjectName(u"groupBox_6")
        sizePolicy2.setHeightForWidth(self.groupBox_6.sizePolicy().hasHeightForWidth())
        self.groupBox_6.setSizePolicy(sizePolicy2)
        self.groupBox_6.setMinimumSize(QSize(210, 240))
        self.groupBox_6.setMaximumSize(QSize(210, 290))
        self.gridLayout_3 = QGridLayout(self.groupBox_6)
        self.gridLayout_3.setObjectName(u"gridLayout_3")
        self.gridLayout_3.setContentsMargins(-1, -1, 6, -1)
        self.verticalSpacer_10 = QSpacerItem(20, 30, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.gridLayout_3.addItem(self.verticalSpacer_10, 4, 0, 1, 1)

        self.btn_setting_ok_2 = QPushButton(self.groupBox_6)
        self.btn_setting_ok_2.setObjectName(u"btn_setting_ok_2")
        sizePolicy2.setHeightForWidth(self.btn_setting_ok_2.sizePolicy().hasHeightForWidth())
        self.btn_setting_ok_2.setSizePolicy(sizePolicy2)
        self.btn_setting_ok_2.setMinimumSize(QSize(180, 50))
        self.btn_setting_ok_2.setMaximumSize(QSize(180, 50))
        self.btn_setting_ok_2.setFont(font1)

        self.gridLayout_3.addWidget(self.btn_setting_ok_2, 5, 0, 1, 2)

        self.label_9 = QLabel(self.groupBox_6)
        self.label_9.setObjectName(u"label_9")
        self.label_9.setFont(font2)

        self.gridLayout_3.addWidget(self.label_9, 1, 0, 1, 1)

        self.btn_setting_cancel_2 = QPushButton(self.groupBox_6)
        self.btn_setting_cancel_2.setObjectName(u"btn_setting_cancel_2")
        sizePolicy3.setHeightForWidth(self.btn_setting_cancel_2.sizePolicy().hasHeightForWidth())
        self.btn_setting_cancel_2.setSizePolicy(sizePolicy3)
        self.btn_setting_cancel_2.setMinimumSize(QSize(180, 50))
        self.btn_setting_cancel_2.setMaximumSize(QSize(180, 50))
        self.btn_setting_cancel_2.setFont(font1)

        self.gridLayout_3.addWidget(self.btn_setting_cancel_2, 6, 0, 1, 2)

        self.verticalSpacer_11 = QSpacerItem(20, 5, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)

        self.gridLayout_3.addItem(self.verticalSpacer_11, 2, 0, 1, 1)

        self.label_10 = QLabel(self.groupBox_6)
        self.label_10.setObjectName(u"label_10")
        self.label_10.setFont(font1)

        self.gridLayout_3.addWidget(self.label_10, 3, 1, 1, 1)

        self.verticalSpacer_12 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.gridLayout_3.addItem(self.verticalSpacer_12, 0, 0, 1, 1)

        self.lineEdit_setting_2 = QLineEdit(self.groupBox_6)
        self.lineEdit_setting_2.setObjectName(u"lineEdit_setting_2")
        sizePolicy2.setHeightForWidth(self.lineEdit_setting_2.sizePolicy().hasHeightForWidth())
        self.lineEdit_setting_2.setSizePolicy(sizePolicy2)
        self.lineEdit_setting_2.setMinimumSize(QSize(150, 40))
        self.lineEdit_setting_2.setMaximumSize(QSize(150, 40))
        self.lineEdit_setting_2.setFont(font3)

        self.gridLayout_3.addWidget(self.lineEdit_setting_2, 3, 0, 1, 1)


        self.horizontalLayout_4.addWidget(self.groupBox_6, 0, Qt.AlignTop)

        self.stackedWidget.addWidget(self.page_setting)
        self.page_contorl = QWidget()
        self.page_contorl.setObjectName(u"page_contorl")
        self.horizontalLayout_3 = QHBoxLayout(self.page_contorl)
        self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
        self.verticalSpacer_9 = QSpacerItem(5, 10, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)

        self.horizontalLayout_3.addItem(self.verticalSpacer_9)

        self.groupBox_4 = QGroupBox(self.page_contorl)
        self.groupBox_4.setObjectName(u"groupBox_4")
        sizePolicy2.setHeightForWidth(self.groupBox_4.sizePolicy().hasHeightForWidth())
        self.groupBox_4.setSizePolicy(sizePolicy2)
        self.groupBox_4.setMinimumSize(QSize(210, 240))
        self.groupBox_4.setMaximumSize(QSize(210, 290))
        self.gridLayout = QGridLayout(self.groupBox_4)
        self.gridLayout.setObjectName(u"gridLayout")
        self.gridLayout.setContentsMargins(-1, -1, 6, -1)
        self.label_4 = QLabel(self.groupBox_4)
        self.label_4.setObjectName(u"label_4")
        self.label_4.setFont(font2)

        self.gridLayout.addWidget(self.label_4, 1, 0, 1, 1)

        self.btn_stop_P_1 = QPushButton(self.groupBox_4)
        self.btn_stop_P_1.setObjectName(u"btn_stop_P_1")
        sizePolicy3.setHeightForWidth(self.btn_stop_P_1.sizePolicy().hasHeightForWidth())
        self.btn_stop_P_1.setSizePolicy(sizePolicy3)
        self.btn_stop_P_1.setMinimumSize(QSize(180, 50))
        self.btn_stop_P_1.setMaximumSize(QSize(180, 50))
        self.btn_stop_P_1.setFont(font1)

        self.gridLayout.addWidget(self.btn_stop_P_1, 6, 0, 1, 2)

        self.real_pressure_P_1 = QLabel(self.groupBox_4)
        self.real_pressure_P_1.setObjectName(u"real_pressure_P_1")
        sizePolicy2.setHeightForWidth(self.real_pressure_P_1.sizePolicy().hasHeightForWidth())
        self.real_pressure_P_1.setSizePolicy(sizePolicy2)
        self.real_pressure_P_1.setMinimumSize(QSize(150, 40))
        self.real_pressure_P_1.setMaximumSize(QSize(150, 40))
        self.real_pressure_P_1.setFont(font1)
        self.real_pressure_P_1.setFrameShape(QFrame.Box)
        self.real_pressure_P_1.setFrameShadow(QFrame.Raised)

        self.gridLayout.addWidget(self.real_pressure_P_1, 3, 0, 1, 1)

        self.label_7 = QLabel(self.groupBox_4)
        self.label_7.setObjectName(u"label_7")
        self.label_7.setFont(font1)

        self.gridLayout.addWidget(self.label_7, 3, 1, 1, 1)

        self.btn_start_P_1 = QPushButton(self.groupBox_4)
        self.btn_start_P_1.setObjectName(u"btn_start_P_1")
        sizePolicy2.setHeightForWidth(self.btn_start_P_1.sizePolicy().hasHeightForWidth())
        self.btn_start_P_1.setSizePolicy(sizePolicy2)
        self.btn_start_P_1.setMinimumSize(QSize(180, 50))
        self.btn_start_P_1.setMaximumSize(QSize(180, 50))
        self.btn_start_P_1.setFont(font1)

        self.gridLayout.addWidget(self.btn_start_P_1, 5, 0, 1, 2)

        self.verticalSpacer_2 = QSpacerItem(20, 30, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.gridLayout.addItem(self.verticalSpacer_2, 4, 0, 1, 1)

        self.verticalSpacer_3 = QSpacerItem(20, 5, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)

        self.gridLayout.addItem(self.verticalSpacer_3, 2, 0, 1, 1)

        self.verticalSpacer_7 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.gridLayout.addItem(self.verticalSpacer_7, 0, 0, 1, 1)


        self.horizontalLayout_3.addWidget(self.groupBox_4, 0, Qt.AlignTop)

        self.groupBox_5 = QGroupBox(self.page_contorl)
        self.groupBox_5.setObjectName(u"groupBox_5")
        sizePolicy2.setHeightForWidth(self.groupBox_5.sizePolicy().hasHeightForWidth())
        self.groupBox_5.setSizePolicy(sizePolicy2)
        self.groupBox_5.setMinimumSize(QSize(210, 240))
        self.groupBox_5.setMaximumSize(QSize(210, 290))
        self.gridLayout_2 = QGridLayout(self.groupBox_5)
        self.gridLayout_2.setObjectName(u"gridLayout_2")
        self.gridLayout_2.setContentsMargins(-1, -1, 6, -1)
        self.verticalSpacer_4 = QSpacerItem(20, 30, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.gridLayout_2.addItem(self.verticalSpacer_4, 4, 0, 1, 1)

        self.btn_start_P_2 = QPushButton(self.groupBox_5)
        self.btn_start_P_2.setObjectName(u"btn_start_P_2")
        sizePolicy2.setHeightForWidth(self.btn_start_P_2.sizePolicy().hasHeightForWidth())
        self.btn_start_P_2.setSizePolicy(sizePolicy2)
        self.btn_start_P_2.setMinimumSize(QSize(180, 50))
        self.btn_start_P_2.setMaximumSize(QSize(180, 50))
        self.btn_start_P_2.setFont(font1)

        self.gridLayout_2.addWidget(self.btn_start_P_2, 5, 0, 1, 2)

        self.label_6 = QLabel(self.groupBox_5)
        self.label_6.setObjectName(u"label_6")
        self.label_6.setFont(font2)

        self.gridLayout_2.addWidget(self.label_6, 1, 0, 1, 1)

        self.real_pressure_P_2 = QLabel(self.groupBox_5)
        self.real_pressure_P_2.setObjectName(u"real_pressure_P_2")
        sizePolicy2.setHeightForWidth(self.real_pressure_P_2.sizePolicy().hasHeightForWidth())
        self.real_pressure_P_2.setSizePolicy(sizePolicy2)
        self.real_pressure_P_2.setMinimumSize(QSize(150, 40))
        self.real_pressure_P_2.setMaximumSize(QSize(150, 40))
        self.real_pressure_P_2.setFont(font1)
        self.real_pressure_P_2.setFrameShape(QFrame.Box)
        self.real_pressure_P_2.setFrameShadow(QFrame.Raised)

        self.gridLayout_2.addWidget(self.real_pressure_P_2, 3, 0, 1, 1)

        self.btn_stop_P_2 = QPushButton(self.groupBox_5)
        self.btn_stop_P_2.setObjectName(u"btn_stop_P_2")
        sizePolicy3.setHeightForWidth(self.btn_stop_P_2.sizePolicy().hasHeightForWidth())
        self.btn_stop_P_2.setSizePolicy(sizePolicy3)
        self.btn_stop_P_2.setMinimumSize(QSize(180, 50))
        self.btn_stop_P_2.setMaximumSize(QSize(180, 50))
        self.btn_stop_P_2.setFont(font1)

        self.gridLayout_2.addWidget(self.btn_stop_P_2, 6, 0, 1, 2)

        self.verticalSpacer_5 = QSpacerItem(20, 5, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)

        self.gridLayout_2.addItem(self.verticalSpacer_5, 2, 0, 1, 1)

        self.label_8 = QLabel(self.groupBox_5)
        self.label_8.setObjectName(u"label_8")
        self.label_8.setFont(font1)

        self.gridLayout_2.addWidget(self.label_8, 3, 1, 1, 1)

        self.verticalSpacer_8 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)

        self.gridLayout_2.addItem(self.verticalSpacer_8, 0, 0, 1, 1)


        self.horizontalLayout_3.addWidget(self.groupBox_5, 0, Qt.AlignTop)

        self.stackedWidget.addWidget(self.page_contorl)

        self.horizontalLayout_2.addWidget(self.stackedWidget)


        self.verticalLayout.addWidget(self.groupBox_3)

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setObjectName(u"menubar")
        self.menubar.setGeometry(QRect(0, 0, 800, 21))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(u"statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)

        self.stackedWidget.setCurrentIndex(0)


        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.groupBox_2.setTitle("")
        self.label_top_left.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))
        self.label_top_mid.setText(QCoreApplication.translate("MainWindow", u"\u6cb9\u6cf5\u63a7\u5236\u7cfb\u7edf", None))
        self.label_top_right.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))
        self.groupBox_3.setTitle("")
        self.groupBox.setTitle("")
        self.btn_setting.setText(QCoreApplication.translate("MainWindow", u"\u53c2\u6570\u8bbe\u5b9a\u753b\u9762", None))
        self.btn_control.setText(QCoreApplication.translate("MainWindow", u"\u6cb9\u6cf5\u64cd\u4f5c\u753b\u9762", None))
        self.groupBox_7.setTitle("")
        self.label_5.setText(QCoreApplication.translate("MainWindow", u"1#\u6cb9\u6cf5", None))
        self.label_11.setText(QCoreApplication.translate("MainWindow", u"MPa", None))
        self.btn_setting_ok_1.setText(QCoreApplication.translate("MainWindow", u"\u786e   \u5b9a", None))
        self.btn_setting_cancel_1.setText(QCoreApplication.translate("MainWindow", u"\u53d6   \u6d88", None))
        self.groupBox_6.setTitle("")
        self.btn_setting_ok_2.setText(QCoreApplication.translate("MainWindow", u"\u786e   \u5b9a", None))
        self.label_9.setText(QCoreApplication.translate("MainWindow", u"2#\u6cb9\u6cf5", None))
        self.btn_setting_cancel_2.setText(QCoreApplication.translate("MainWindow", u"\u53d6   \u6d88", None))
        self.label_10.setText(QCoreApplication.translate("MainWindow", u"MPa", None))
        self.groupBox_4.setTitle("")
        self.label_4.setText(QCoreApplication.translate("MainWindow", u"1#\u6cb9\u6cf5", None))
        self.btn_stop_P_1.setText(QCoreApplication.translate("MainWindow", u"\u505c    \u6b62", None))
        self.real_pressure_P_1.setText("")
        self.label_7.setText(QCoreApplication.translate("MainWindow", u"MPa", None))
        self.btn_start_P_1.setText(QCoreApplication.translate("MainWindow", u"\u542f    \u52a8", None))
        self.groupBox_5.setTitle("")
        self.btn_start_P_2.setText(QCoreApplication.translate("MainWindow", u"\u542f    \u52a8", None))
        self.label_6.setText(QCoreApplication.translate("MainWindow", u"2#\u6cb9\u6cf5", None))
        self.real_pressure_P_2.setText("")
        self.btn_stop_P_2.setText(QCoreApplication.translate("MainWindow", u"\u505c    \u6b62", None))
        self.label_8.setText(QCoreApplication.translate("MainWindow", u"MPa", None))
    # retranslateUi

运行截图:

相关推荐
2402_854808372 小时前
C#怎么开发CAD自定义命令_C#如何调用AutoCAD的API【教程】
jvm·数据库·python
椰羊~王小美2 小时前
讲解“实时”是怎么实现的
学习
lkbhua莱克瓦242 小时前
记单词功能深度优化项目 - 业务需求开发文档(BRD+技术拆分版)
笔记
m0_716430072 小时前
mysql乐观锁更新失败如何处理_应用层重试逻辑编写建议
jvm·数据库·python
qq_654366982 小时前
SQL嵌套查询中的变量传值_优化存储过程逻辑
jvm·数据库·python
m0_748920362 小时前
持久化存储如何与后端接口同步?解决本地缓存与数据库不一致痛点
jvm·数据库·python
qq_330037992 小时前
Python如何安装特定架构包_32位与64位系统兼容性处理
jvm·数据库·python
子午2 小时前
蔬菜识别~Python+深度学习+卷积网络算法+图像识别+2026原创+蔬菜识别
python·深度学习·算法
测试19982 小时前
软件测试之持续集成
自动化测试·软件测试·python·功能测试·测试工具·测试用例·持续集成