添加两个版本+添加一个重连机制的版本,待测试

This commit is contained in:
2025-10-31 16:56:02 +08:00
parent b7fc062f3f
commit 3e0c62ac01
8 changed files with 674 additions and 274 deletions

View File

@ -3,7 +3,8 @@
''' '''
# @Time : 2025/9/10 11:29 # @Time : 2025/9/10 11:29
# @Author : reenrr # @Author : reenrr
# @File : test.py # @Description : 通过tcp连接获取信息并显示在界面上版本1
# @File : main.py
''' '''
import sys import sys
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
@ -24,15 +25,11 @@ import os
tcp_server_host = "127.0.0.1" tcp_server_host = "127.0.0.1"
tcp_server_port = 8888 tcp_server_port = 8888
# 数据保存目录
SAVE_DIR = "operation_records"
class StatusMonitor(QWidget): class StatusMonitor(QWidget):
""" """
中交三航精准布料浇筑要料系统 - 主界面类深色主题 中交三航精准布料浇筑要料系统 - 主界面类深色主题
使用TCP进行数据传输客户端模型与TCP服务器通信 使用TCP进行数据传输客户端模型与TCP服务器通信
""" """
def __init__(self, parent=None): def __init__(self, parent=None):
"""构造函数初始化主界面的UI布局、控件和定时器""" """构造函数初始化主界面的UI布局、控件和定时器"""
super().__init__(parent=parent) super().__init__(parent=parent)
@ -66,7 +63,6 @@ class StatusMonitor(QWidget):
self._init_title_label() self._init_title_label()
self._init_status_container() self._init_status_container()
self._init_timers() self._init_timers()
self._init_save_dir()
# ---------------- # ----------------
# 客户端自动后自动连接服务端 # 客户端自动后自动连接服务端
@ -74,14 +70,6 @@ class StatusMonitor(QWidget):
print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...") print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...")
self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port) self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port)
def _init_save_dir(self):
"""初始化数据保存目录"""
if not os.path.exists(SAVE_DIR):
os.makedirs(SAVE_DIR)
print(f"已创建数据保存目录:{os.path.abspath(SAVE_DIR)}")
else:
print(f"数据保存目录已存在:{os.path.abspath(SAVE_DIR)}")
def _bind_tcp_signals(self): def _bind_tcp_signals(self):
"""绑定TCP socket的核心信号连接、断开、接收数据、错误""" """绑定TCP socket的核心信号连接、断开、接收数据、错误"""
# 连接成功信号 # 连接成功信号
@ -93,6 +81,9 @@ class StatusMonitor(QWidget):
# 错误信号(连接/通信出错时触发) # 错误信号(连接/通信出错时触发)
self.tcp_socket.errorOccurred.connect(self._on_tcp_error) self.tcp_socket.errorOccurred.connect(self._on_tcp_error)
# ----------------
# 界面初始化函数
# ----------------
def _init_title_label(self): def _init_title_label(self):
"""初始化系统标题标签""" """初始化系统标题标签"""
titleLabel = QLabel("中交三航精准布料浇筑要料系统") titleLabel = QLabel("中交三航精准布料浇筑要料系统")
@ -149,19 +140,15 @@ class StatusMonitor(QWidget):
# 左边5个状态项及对应初始值 # 左边5个状态项及对应初始值
leftStatusInfo = [ leftStatusInfo = [
{"name": "任务单号", "value": "20250706-01", "api_field": "task_id"}, {"name": "任务单号", "value": "", "api_field": "task_id"},
{"name": "工程名称", "value": "18号线二期工程", "api_field": "project_name"}, {"name": "工程名称", "value": "", "api_field": "project_name"},
{"name": "区间段", "value": "停车场工作并上行", "api_field": "section"}, {"name": "配比号", "value": "", "api_field": "produce_mix_id"}
{"name": "坍落度", "value": "50~70 mm", "api_field": "slump"},
{"name": "配合比编号", "value": "P2022=001", "api_field": "mix_ratio_id"}
] ]
# 右边5个状态项及对应初始值 # 右边5个状态项及对应初始值
rightStatusInfo = [ rightStatusInfo = [
{"name": "要料状态", "value": "请求中", "api_field": "request_status"}, {"name": "要料状态", "value": "", "api_field": "flag"},
{"name": "要料标号", "value": "C50P12", "api_field": "material_grade"}, {"name": "砼强度", "value": "", "api_field": "beton_grade"},
{"name": "要料方量", "value": "2m³", "api_field": "volume"}, {"name": "要料方量", "value": "", "api_field": "adjusted_volume"},
{"name": "要料时间", "value": "2分钟后", "api_field": "request_time"},
{"name": "小车状态", "value": "移动后", "api_field": "car_status"}
] ]
self.statusWidgets = [] self.statusWidgets = []
@ -256,25 +243,17 @@ class StatusMonitor(QWidget):
buttonLayout.setSpacing(30) buttonLayout.setSpacing(30)
# 按钮图标(需替换为实际图标路径) # 按钮图标(需替换为实际图标路径)
start_icon_path = "img.png"
down_icon_path = "img.png"
error_icon_path = "img.png" error_icon_path = "img.png"
cancel_icon_path = "img.png" cancel_icon_path = "img.png"
self.startFeedButton = QPushButton("开始下料")
self.finishButton = QPushButton("下料完成")
self.errorButton = QPushButton("生产异常") self.errorButton = QPushButton("生产异常")
self.cancelButton = QPushButton("生产取消") self.cancelButton = QPushButton("生产取消")
# 设置按钮图标 # 设置按钮图标
self.startFeedButton.setIcon(QIcon(start_icon_path))
self.finishButton.setIcon(QIcon(down_icon_path))
self.errorButton.setIcon(QIcon(error_icon_path)) self.errorButton.setIcon(QIcon(error_icon_path))
self.cancelButton.setIcon(QIcon(cancel_icon_path)) self.cancelButton.setIcon(QIcon(cancel_icon_path))
# 设置图标大小 # 设置图标大小
self.startFeedButton.setIconSize(QSize(20, 20))
self.finishButton.setIconSize(QSize(20, 20))
self.errorButton.setIconSize(QSize(20, 20)) self.errorButton.setIconSize(QSize(20, 20))
self.cancelButton.setIconSize(QSize(20, 20)) self.cancelButton.setIconSize(QSize(20, 20))
@ -294,23 +273,6 @@ class StatusMonitor(QWidget):
opacity: 0.8; opacity: 0.8;
} }
""" """
self.startFeedButton.setStyleSheet(button_base_style + """
QPushButton {
background-color: #2196F3;
color: white;
border-color: #1976D2;
}
""")
self.finishButton.setStyleSheet(button_base_style + """
QPushButton {
background-color: #00796B;
color: white;
border-color: #004D40;
}
""")
self.errorButton.setStyleSheet(button_base_style + """ self.errorButton.setStyleSheet(button_base_style + """
QPushButton { QPushButton {
background-color: #E65100; background-color: #E65100;
@ -328,25 +290,17 @@ class StatusMonitor(QWidget):
""") """)
button_font = QFont("Microsoft YaHei", 12, QFont.Bold) button_font = QFont("Microsoft YaHei", 12, QFont.Bold)
self.startFeedButton.setFont(button_font)
self.finishButton.setFont(button_font)
self.errorButton.setFont(button_font) self.errorButton.setFont(button_font)
self.cancelButton.setFont(button_font) self.cancelButton.setFont(button_font)
self.startFeedButton.clicked.connect(self.on_start_clicked)
self.finishButton.clicked.connect(self.on_finish_clicked)
self.errorButton.clicked.connect(self.on_error_clicked) self.errorButton.clicked.connect(self.on_error_clicked)
self.cancelButton.clicked.connect(self.on_cancel_clicked) self.cancelButton.clicked.connect(self.on_cancel_clicked)
# 初始禁用“停止”和“异常”按钮(未连接时不可用) # 初始禁用“停止”和“异常”按钮(未连接时不可用)
self.startFeedButton.setDisabled(False)
self.finishButton.setDisabled(True)
self.errorButton.setDisabled(True) self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True) self.cancelButton.setDisabled(True)
buttonLayout.addStretch(1) buttonLayout.addStretch(1)
buttonLayout.addWidget(self.startFeedButton)
buttonLayout.addWidget(self.finishButton)
buttonLayout.addWidget(self.errorButton) buttonLayout.addWidget(self.errorButton)
buttonLayout.addWidget(self.cancelButton) buttonLayout.addWidget(self.cancelButton)
buttonLayout.addStretch(1) buttonLayout.addStretch(1)
@ -397,35 +351,22 @@ class StatusMonitor(QWidget):
# 绘制文本 # 绘制文本
painter.drawText(x, y + text_rect.height(), text) painter.drawText(x, y + text_rect.height(), text)
def _save_data_to_file(self, button_name): # --------------------
""" # 清空界面信息的通用方法
将服务端数据+按钮操作信息保存到JSON文件 # --------------------
def _clear_ui_info(self):
参数button_name:点击的按钮名称 """清空所有状态项的显示内容,并并设置指示灯颜色"""
""" for widget in self.statusWidgets:
# 1、检查是否有服务端数据 widget['valueLabel'].setText("")
if not self.latest_server_data: # 指示灯设为初始灰色与_create_status_item中初始样式一致
print(f"⚠️ 未收到服务端数据,无法保存「{button_name}」操作记录") widget['indicator'].setStyleSheet("""
return QLabel {
background-color: #9E9E9E;
# 2、构建完整数据服务端数据+按钮操作信息+存档时间) border-radius: 10px;
save_data = { border: 2px solid #555555;
"opration_button": button_name,
"save_time": self.get_current_time(),
"server_data":self.latest_server_data
} }
""")
# 3、生成唯一文件名按时间戳命名 print(" 界面信息已清空")
file_name = f"operation_record_{self.get_timestamp()}.json"
file_path = os.path.join(SAVE_DIR, file_name)
# 4、写入JSON文件
try:
with open(file_path, "w", encoding="utf-8") as f:
json.dump(save_data, f, ensure_ascii=False, indent=4)
print(f"💾 保存「{button_name}」操作记录成功:{os.path.abspath(file_path)}")
except Exception as e:
print(f"💾 保存「{button_name}」操作记录失败:{str(e)}")
# ------------------ # ------------------
# TCP客户端核心功能 # TCP客户端核心功能
@ -441,7 +382,6 @@ class StatusMonitor(QWidget):
self._send_tcp_request("get_initial_data") self._send_tcp_request("get_initial_data")
# 更新按钮状态:启用“下料完成”“生产异常”“生产取消” # 更新按钮状态:启用“下料完成”“生产异常”“生产取消”
self.finishButton.setDisabled(False)
self.errorButton.setDisabled(False) self.errorButton.setDisabled(False)
self.cancelButton.setDisabled(False) self.cancelButton.setDisabled(False)
@ -453,8 +393,6 @@ class StatusMonitor(QWidget):
print(f"TCP连接断开{self.tcp_server_host}:{self.tcp_server_port}") print(f"TCP连接断开{self.tcp_server_host}:{self.tcp_server_port}")
# 启用/禁用按钮 # 启用/禁用按钮
self.startFeedButton.setDisabled(False)
self.finishButton.setDisabled(True)
self.errorButton.setDisabled(True) self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True) self.cancelButton.setDisabled(True)
@ -493,8 +431,6 @@ class StatusMonitor(QWidget):
self.is_running = False self.is_running = False
# 启用/禁用按钮 # 启用/禁用按钮
self.startFeedButton.setDisabled(False)
self.finishButton.setDisabled(True)
self.errorButton.setDisabled(True) self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True) self.cancelButton.setDisabled(True)
@ -551,34 +487,17 @@ class StatusMonitor(QWidget):
# ------------------ # ------------------
# 按钮点击事件 # 按钮点击事件
# ------------------ # ------------------
def on_start_clicked(self):
"""点击“开始下料”:向服务端发送开始指令"""
print("🔘 点击「开始下料」按钮")
if not self.is_tcp_connected:
print("TCP连接未建立尝试重新连接")
self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port)
QTimer.singleShot(1000, lambda: self._send_tcp_request("start_feed")) # 等待连接成功后再发送请求
else:
print("TCP连接已建立")
self._send_tcp_request("start_feed")
def on_finish_clicked(self):
"""点击“下料完成”:向服务端发送完成指令"""
print("🔘 点击「下料完成」按钮")
self._send_tcp_request("finish_feed")
self._save_data_to_file("finish_feed")
def on_error_clicked(self): def on_error_clicked(self):
"""点击“生产异常”:向服务端发送异常指令""" """点击“生产异常”:向服务端发送异常指令"""
print("🔘 点击「生产异常」按钮") print("🔘 点击「生产异常」按钮")
self._clear_ui_info()
self._send_tcp_request("production_error") self._send_tcp_request("production_error")
self._save_data_to_file("production_error")
def on_cancel_clicked(self): def on_cancel_clicked(self):
"""点击“生产取消”:向服务端发送取消指令""" """点击“生产取消”:向服务端发送取消指令"""
print("🔘 点击「生产取消」按钮") print("🔘 点击「生产取消」按钮")
self._clear_ui_info()
self._send_tcp_request("cancel_feed") self._send_tcp_request("cancel_feed")
self._save_data_to_file("cancel_feed")
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) app = QApplication(sys.argv)

569
main2.py Normal file
View File

@ -0,0 +1,569 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time : 2025/10/31 14:39
# @Author : reenrr
# @Description : 通过tcp连接获取信息并显示在界面上版本2
# @File : main2.py
'''
import sys
from PySide6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QFrame, QSizePolicy, QPushButton
)
from PySide6.QtCore import Qt, QTimer, QPoint, QSize, Slot
from PySide6.QtGui import QFont, QPainter, QColor, QPen, QIcon
from datetime import datetime
from PySide6.QtNetwork import QTcpSocket, QAbstractSocket
import json
import os
# -----------
# 参数配置
# -----------
tcp_server_host = "127.0.0.1"
tcp_server_port = 8888
# 数据保存目录
SAVE_DIR = "operation_records"
class StatusMonitor(QWidget):
"""
中交三航精准布料浇筑要料系统 - 主界面类(深色主题)
使用TCP进行数据传输客户端模型与TCP服务器通信
"""
def __init__(self, parent=None):
"""构造函数初始化主界面的UI布局、控件和定时器"""
super().__init__(parent=parent)
self.is_running = False # 系统运行状态标记
self.current_datetime = self.get_current_time() # 当前日期时间
# 缓存服务端发送的最新JSON数据统一变量名避免保存时出错
self.latest_server_data = {}
# ---------------
# TCP客户端核心配置
# ---------------
self.tcp_socket = QTcpSocket(self) # TCP socket实例
self.tcp_server_host = tcp_server_host
self.tcp_server_port = tcp_server_port
self.is_tcp_connected = False # TCP连接状态标记
# 绑定TCP信号与槽事件驱动
self._bind_tcp_signals()
# 窗口基础设置
self.setWindowTitle("中交三航精准布料浇筑要料系统")
self.setGeometry(100, 100, 850, 500) # 设置窗口位置和大小
self.setStyleSheet("background-color: #121212;") # 窗口背景设为深黑色
# 初始化主布局(垂直布局)
self.mainLayout = QVBoxLayout(self)
self.mainLayout.setContentsMargins(10, 40, 10, 10) # 上边距留空用于显示日期
self.mainLayout.setSpacing(10) # 相邻控件的间距
# 初始化界面组件
self._init_title_label()
self._init_status_container()
self._init_timers()
# ----------------
# 客户端自动连接服务端
# ----------------
print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...")
self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port)
def _bind_tcp_signals(self):
"""绑定TCP socket的核心信号连接、断开、接收数据、错误"""
# 连接成功信号
self.tcp_socket.connected.connect(self._on_tcp_connected)
# 断开连接信号
self.tcp_socket.disconnected.connect(self._on_tcp_disconnected)
# 接收数据信号(有新数据时触发)
self.tcp_socket.readyRead.connect(self._on_tcp_data_received)
# 错误信号(连接/通信出错时触发)
self.tcp_socket.errorOccurred.connect(self._on_tcp_error)
# ----------------
# 界面初始化函数
# ----------------
def _init_title_label(self):
"""初始化系统标题标签"""
titleLabel = QLabel("中交三航精准布料浇筑要料系统")
titleLabel.setStyleSheet("""
QLabel {
color: #00FF9D;
font-size: 20px;
font-weight: bold;
}
""")
titleLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
titleLabel.setFont(QFont("Microsoft YaHei", 24, QFont.Bold))
self.mainLayout.addWidget(titleLabel)
def _init_status_container(self):
"""初始化核心状态监控容器(包含状态组和操作按钮)"""
self.bigContainer = QFrame()
self.bigContainer.setStyleSheet("""
QFrame {
background-color: #1E1E1E;
border: 2px solid #333333;
border-radius: 8px;
}
""")
self.bigContainer.setSizePolicy(
QSizePolicy.Policy.Expanding,
QSizePolicy.Policy.Expanding
)
containerLayout = QVBoxLayout(self.bigContainer)
containerLayout.setContentsMargins(20, 20, 20, 20)
self._init_status_groups(containerLayout)
self._init_operation_buttons(containerLayout) # 操作按钮包含新增的3个状态按钮
self.mainLayout.addWidget(self.bigContainer, 1)
def _init_status_groups(self, parent_layout):
"""初始化左右信息各包含3个状态项"""
statusWidget = QWidget()
statusLayout = QHBoxLayout(statusWidget)
statusLayout.setContentsMargins(0, 0, 0, 0)
statusLayout.setSpacing(30) # 减小中间空白间距
leftGroup = QWidget()
leftLayout = QVBoxLayout(leftGroup)
leftLayout.setSpacing(15)
leftLayout.setContentsMargins(30, 0, 0, 0) # 左边组左内边距
rightGroup = QWidget()
rightLayout = QVBoxLayout(rightGroup)
rightLayout.setSpacing(15)
rightLayout.setContentsMargins(0, 0, 30, 0) # 右边组右内边距
# 左边状态项
leftStatusInfo = [
{"name": "任务单号", "value": "", "api_field": "task_id"},
{"name": "工程名称", "value": "", "api_field": "project_name"},
{"name": "配比号", "value": "", "api_field": "produce_mix_id"}
]
# 右边状态项
rightStatusInfo = [
{"name": "要料状态", "value": "", "api_field": "flag"},
{"name": "砼强度", "value": "", "api_field": "beton_grade"},
{"name": "要料方量", "value": "", "api_field": "adjusted_volume"},
]
self.statusWidgets = []
# 处理左边状态项
for info in leftStatusInfo:
statusItem = self._create_status_item(info)
leftLayout.addWidget(statusItem)
# 处理右边状态项
for info in rightStatusInfo:
statusItem = self._create_status_item(info)
rightLayout.addWidget(statusItem)
statusLayout.addWidget(leftGroup)
statusLayout.addStretch(0)
statusLayout.addWidget(rightGroup)
parent_layout.addWidget(statusWidget)
def _create_status_item(self, info):
"""创建单个状态项"""
statusItem = QFrame()
statusItem.setStyleSheet("""
QFrame {
background-color: #2D2D2D;
border: 1px solid #444444;
border-radius: 6px;
padding: 10px;
}
""")
statusItem.setFixedHeight(80)
statusItem.setFixedWidth(320) # 统一状态项宽度
itemLayout = QHBoxLayout(statusItem)
itemLayout.setContentsMargins(10, 5, 10, 5)
# 状态指示灯
indicator = QLabel()
indicator.setFixedSize(20, 20)
indicator.setStyleSheet("""
QLabel {
background-color: #9E9E9E;
border-radius: 10px;
border: 2px solid #555555;
}
""")
# 状态名称标签
nameLabel = QLabel(info["name"])
nameLabel.setFixedWidth(100)
nameLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
nameLabel.setStyleSheet("font-size: 14px; color: #FFFFFF;")
nameLabel.setFont(QFont("Microsoft YaHei", 12))
# 状态值标签
valueLabel = QLabel(info["value"])
valueLabel.setStyleSheet("""
QLabel {
font-size: 16px;
font-weight: bold;
color: #FFFFFF;
background-color: #2D2D2D;
border: none;
padding: 0px;
}
""")
valueLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
valueLabel.setMinimumWidth(150)
itemLayout.addWidget(indicator)
itemLayout.addSpacing(10)
itemLayout.addWidget(nameLabel)
itemLayout.addStretch()
itemLayout.addWidget(valueLabel)
self.statusWidgets.append({
'indicator': indicator,
'nameLabel': nameLabel,
'valueLabel': valueLabel,
'status': False,
'initial_value': info["value"],
'api_field': info["api_field"]
})
return statusItem
def _init_operation_buttons(self, parent_layout):
"""初始化操作按钮(新增未下料/下料中/下料完成 + 原有生产异常/生产取消)"""
buttonContainer = QWidget()
buttonLayout = QHBoxLayout(buttonContainer)
buttonLayout.setContentsMargins(0, 20, 0, 0)
buttonLayout.setSpacing(20) # 按钮间距适配5个按钮避免拥挤
# 按钮图标(复用现有图标路径,可根据需求替换)
status_icon_path = "img.png" # 状态类按钮(未下料/下料中/下料完成)共用图标
error_icon_path = "img.png"
cancel_icon_path = "img.png"
self.notFeedingBtn = QPushButton("未下料") # 未下料按钮
self.feedingBtn = QPushButton("下料中") # 下料中按钮
self.feedFinishBtn = QPushButton("下料完成")# 下料完成按钮
self.errorButton = QPushButton("生产异常")
self.cancelButton = QPushButton("生产取消")
# 设置按钮设置(图标、大小、样式)
status_buttons = [self.notFeedingBtn, self.feedingBtn, self.feedFinishBtn]
for btn in status_buttons:
btn.setIcon(QIcon(status_icon_path))
btn.setIconSize(QSize(20, 20))
btn.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
self.errorButton.setIcon(QIcon(error_icon_path))
self.cancelButton.setIcon(QIcon(cancel_icon_path))
self.errorButton.setIconSize(QSize(20, 20))
self.cancelButton.setIconSize(QSize(20, 20))
self.errorButton.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
self.cancelButton.setFont(QFont("Microsoft YaHei", 12, QFont.Bold))
# 按钮基础样式(统一风格)
button_base_style = """
QPushButton {
font-size: 16px;
font-weight: bold;
padding: 10px 15px; /* 缩小内边距适配5个按钮布局 */
border-radius: 15px;
border: 1px solid;
min-width: 90px; /* 缩小最小宽度 */
}
QPushButton:hover {
opacity: 0.9;
}
QPushButton:pressed {
opacity: 0.8;
}
"""
# 单个按钮样式(不同颜色区分状态)
self.notFeedingBtn.setStyleSheet(button_base_style + """
QPushButton {
background-color: #616161; /* 灰色:未开始状态 */
color: white;
border-color: #424242;
}
""")
self.feedingBtn.setStyleSheet(button_base_style + """
QPushButton {
background-color: #2196F3; /* 蓝色:进行中状态 */
color: white;
border-color: #1976D2;
}
""")
self.feedFinishBtn.setStyleSheet(button_base_style + """
QPushButton {
background-color: #4CAF50; /* 绿色:完成状态 */
color: white;
border-color: #388E3C;
}
""")
self.errorButton.setStyleSheet(button_base_style + """
QPushButton {
background-color: #E65100;
color: white;
border-color: #BF360C;
}
""")
self.cancelButton.setStyleSheet(button_base_style + """
QPushButton {
background-color: #C62828;
color: white;
border-color: #8E0000;
}
""")
# ---------------- 绑定按钮点击事件 ----------------
self.notFeedingBtn.clicked.connect(self.on_not_feeding_clicked)
self.feedingBtn.clicked.connect(self.on_feeding_clicked)
self.feedFinishBtn.clicked.connect(self.on_feed_finish_clicked)
self.errorButton.clicked.connect(self.on_error_clicked)
self.cancelButton.clicked.connect(self.on_cancel_clicked)
# ---------------- 初始禁用所有按钮TCP连接后启用 ----------------
all_buttons = status_buttons + [self.errorButton, self.cancelButton]
for btn in all_buttons:
btn.setDisabled(True)
# ---------------- 按钮布局5个按钮横向排列 ----------------
buttonLayout.addStretch(1)
buttonLayout.addWidget(self.notFeedingBtn)
buttonLayout.addWidget(self.feedingBtn)
buttonLayout.addWidget(self.feedFinishBtn)
buttonLayout.addWidget(self.errorButton)
buttonLayout.addWidget(self.cancelButton)
buttonLayout.addStretch(1)
parent_layout.addWidget(buttonContainer)
def _init_timers(self):
"""初始化定时器(时间更新+状态模拟)"""
# 时间更新定时器(每秒更新一次)
self.time_timer = QTimer()
self.time_timer.timeout.connect(self.update_time)
self.time_timer.start(1000)
def get_current_time(self):
"""获取格式化的当前时间"""
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def get_timestamp(self):
"""获取当前时间戳(秒级)"""
return datetime.now().strftime('%Y%m%d_%H%M%S_%f')[:-3]
def update_time(self):
"""更新时间显示并触发重绘"""
self.current_datetime = self.get_current_time()
self.update() # 触发paintEvent重绘
def paintEvent(self, event):
"""重写绘画事件,在右上角绘制日期时间文本"""
super().paintEvent(event) # 调用父类方法保持原有绘制
# 创建QPainter对象
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.TextAntialiasing) # 文本抗锯齿
# 设置字体
font = QFont("Arial", 12, QFont.Bold)
painter.setFont(font)
# 设置文本颜色
painter.setPen(QColor("#00FF9D"))
# 计算文本位置(右上角,留出边距)
text = f"🕒 {self.current_datetime}"
text_rect = painter.boundingRect(self.rect(), Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop, text)
x = self.width() - text_rect.width() - 15 # 右边距15px
y = 15 # 上边距15px
# 绘制文本
painter.drawText(x, y + text_rect.height(), text)
# --------------------
# 清空界面信息的通用方法
# --------------------
def _clear_ui_info(self):
"""清空所有状态项的显示内容,并并设置指示灯颜色"""
for widget in self.statusWidgets:
widget['valueLabel'].setText("")
# 指示灯设为初始灰色与_create_status_item中初始样式一致
widget['indicator'].setStyleSheet("""
QLabel {
background-color: #9E9E9E;
border-radius: 10px;
border: 2px solid #555555;
}
""")
print(" 界面信息已清空")
# ------------------
# TCP客户端核心功能
# ------------------
@Slot()
def _on_tcp_connected(self):
"""TCP连接成功回调启用所有操作按钮"""
self.is_tcp_connected = True
self.is_running = True
print(f"TCP连接成功{self.tcp_server_host}:{self.tcp_server_port}")
# 连接成功后,向服务器发送“请求初始数据”指令
self._send_tcp_request("get_initial_data")
# 启用所有操作按钮新增的3个状态按钮+原有2个功能按钮
all_buttons = [self.notFeedingBtn, self.feedingBtn, self.feedFinishBtn, self.errorButton, self.cancelButton]
for btn in all_buttons:
btn.setDisabled(False)
@Slot()
def _on_tcp_disconnected(self):
"""TCP连接断开回调禁用所有操作按钮"""
self.is_tcp_connected = False
self.is_running = False
print(f"TCP连接断开{self.tcp_server_host}:{self.tcp_server_port}")
# 禁用所有操作按钮
all_buttons = [self.notFeedingBtn, self.feedingBtn, self.feedFinishBtn, self.errorButton, self.cancelButton]
for btn in all_buttons:
btn.setDisabled(True)
# 重置状态指示灯为“未连接”状态
for widget in self.statusWidgets:
widget['indicator'].setStyleSheet("""
QLabel {
background-color: #9E9E9E;
border-radius: 10px;
border: 2px solid #555555;
}
""")
@Slot()
def _on_tcp_data_received(self):
"""TCP数据接收回调服务器发送数据时触发"""
tcp_data = self.tcp_socket.readAll().data().decode("utf-8").strip()
print(f"TCP数据接收{tcp_data}")
# 解析数据
try:
status_data = json.loads(tcp_data)
self.latest_server_data = status_data
self._update_ui_from_data(status_data)
except json.JSONDecodeError as e:
print(f"TCP数据解析失败非JSON格式{e}, 原始数据:{tcp_data}")
except Exception as e:
print(f"TCP数据处理异常{e}")
@Slot(QAbstractSocket.SocketError)
def _on_tcp_error(self, error):
"""TCP错误回调禁用所有操作按钮"""
error_str = self.tcp_socket.errorString()
print(f"TCP错误{error_str}")
self.is_tcp_connected = False
self.is_running = False
# 禁用所有操作按钮
all_buttons = [self.notFeedingBtn, self.feedingBtn, self.feedFinishBtn, self.errorButton, self.cancelButton]
for btn in all_buttons:
btn.setDisabled(True)
def _send_tcp_request(self, request_cmd="get_status"):
"""向TCP服务器发送请求指令"""
if not self.is_tcp_connected:
print("TCP连接未建立无法发送请求")
return
# 构造请求数据
request_data = json.dumps({
"cmd": request_cmd,
"timestamp": self.get_current_time(),
"client_info": "布料系统客户端"
}) + "\n" # 增加换行符作为数据结束标识
# 发送请求数据
self.tcp_socket.write(request_data.encode("utf-8"))
print(f"TCP请求发送{request_data.strip()}")
def _update_ui_from_data(self, data):
"""根据TCP获取的数据更新界面状态"""
for widget in self.statusWidgets:
api_field = widget['api_field']
if api_field in data:
new_value = str(data[api_field])
widget['valueLabel'].setText(new_value)
self.set_indicator_status(widget, new_value)
# ------------------
# 状态指示灯逻辑
# ------------------
def set_indicator_status(self, widget, value):
"""根据值设置状态指示灯颜色"""
if value and value != "未知" and value != "" and value != "None":
# 有效数据:绿色指示灯
widget['indicator'].setStyleSheet("""
QLabel {
background-color: #00E676;
border-radius: 10px;
border: 2px solid #00796B;
}
""")
else:
# 无效数据:红色指示灯
widget['indicator'].setStyleSheet("""
QLabel {
background-color: #FF5252;
border-radius: 10px;
border: 2px solid #C62828;
}
""")
# ------------------
# 按钮点击事件
# ------------------
def on_not_feeding_clicked(self):
"""点击“未下料”:向服务端发送“未下料”状态指令"""
print("🔘 点击「未下料」按钮")
self._clear_ui_info()
self._send_tcp_request("not_feeding") # 指令名可根据服务端需求修改
def on_feeding_clicked(self):
"""点击“下料中”:向服务端发送“下料中”状态指令"""
print("🔘 点击「下料中」按钮")
self._clear_ui_info()
self._send_tcp_request("feeding") # 指令名可根据服务端需求修改
def on_feed_finish_clicked(self):
"""点击“下料完成”:向服务端发送“下料完成”状态指令"""
print("🔘 点击「下料完成」按钮")
self._clear_ui_info()
self._send_tcp_request("feed_finish") # 指令名可根据服务端需求修改
def on_error_clicked(self):
"""点击“生产异常”:向服务端发送异常指令"""
print("🔘 点击「生产异常」按钮")
self._clear_ui_info()
self._send_tcp_request("production_error")
def on_cancel_clicked(self):
"""点击“生产取消”:向服务端发送取消指令"""
print("🔘 点击「生产取消」按钮")
self._clear_ui_info()
self._send_tcp_request("cancel_feed")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = StatusMonitor()
window.show()
sys.exit(app.exec())

View File

@ -1,17 +0,0 @@
{
"opration_button": "finish_feed",
"save_time": "2025-09-19 20:45:18",
"server_data": {
"task_id": "20250706-01",
"project_name": "18号线二期工程",
"section": "停车场工作井上行",
"slump": "50~70 mm",
"mix_ratio_id": "P2022=001",
"request_status": "请求中",
"material_grade": "C50P12",
"volume": "2m³",
"request_time": "10分钟后",
"car_status": "移动后",
"timestamp": "2025-09-19 20:45:16"
}
}

View File

@ -1,17 +0,0 @@
{
"opration_button": "production_error",
"save_time": "2025-09-19 20:45:39",
"server_data": {
"task_id": "20250706-01",
"project_name": "18号线二期工程",
"section": "停车场工作井上行",
"slump": "50~70 mm",
"mix_ratio_id": "P2022=001",
"request_status": "请求中",
"material_grade": "C50P12",
"volume": "2m³",
"request_time": "10分钟后",
"car_status": "移动后",
"timestamp": "2025-09-19 20:45:16"
}
}

View File

@ -1,17 +0,0 @@
{
"opration_button": "cancel_feed",
"save_time": "2025-09-19 20:46:05",
"server_data": {
"task_id": "20250706-01",
"project_name": "18号线二期工程",
"section": "停车场工作井上行",
"slump": "50~70 mm",
"mix_ratio_id": "P2022=001",
"request_status": "请求中",
"material_grade": "C50P12",
"volume": "2m³",
"request_time": "10分钟后",
"car_status": "移动后",
"timestamp": "2025-09-19 20:45:16"
}
}

View File

@ -1,17 +0,0 @@
{
"opration_button": "finish_feed",
"save_time": "2025-09-19 20:48:07",
"server_data": {
"task_id": "20250706-01",
"project_name": "18号线二期工程",
"section": "停车场工作井上行",
"slump": "50~70 mm",
"mix_ratio_id": "P2022=001",
"request_status": "请求中",
"material_grade": "C50P12",
"volume": "2m³",
"request_time": "10分钟后",
"car_status": "移动后",
"timestamp": "2025-09-19 20:47:57"
}
}

View File

@ -1,17 +0,0 @@
{
"opration_button": "production_error",
"save_time": "2025-09-19 20:48:58",
"server_data": {
"task_id": "20250706-01",
"project_name": "18号线二期工程",
"section": "停车场工作井上行",
"slump": "50~70 mm",
"mix_ratio_id": "P2022=001",
"request_status": "请求中",
"material_grade": "C50P12",
"volume": "2m³",
"request_time": "10分钟后",
"car_status": "移动后",
"timestamp": "2025-09-19 20:48:53"
}
}

137
test.py
View File

@ -3,6 +3,7 @@
''' '''
# @Time : 2025/9/10 11:29 # @Time : 2025/9/10 11:29
# @Author : reenrr # @Author : reenrr
# @Description : 在main函数的基础上添加了重连机制为连接成功
# @File : test.py # @File : test.py
''' '''
import sys import sys
@ -26,13 +27,14 @@ tcp_server_port = 8888
# 数据保存目录 # 数据保存目录
SAVE_DIR = "operation_records" SAVE_DIR = "operation_records"
MAX_RECONNECT = 3 # 最大重连次数
RECONNECT_INTERVAL = 2000 # 重连间隔(毫秒)
class StatusMonitor(QWidget): class StatusMonitor(QWidget):
""" """
中交三航精准布料浇筑要料系统 - 主界面类(深色主题) 中交三航精准布料浇筑要料系统 - 主界面类(深色主题)
使用TCP进行数据传输客户端模型与TCP服务器通信 使用TCP进行数据传输客户端模型与TCP服务器通信
""" """
def __init__(self, parent=None): def __init__(self, parent=None):
"""构造函数初始化主界面的UI布局、控件和定时器""" """构造函数初始化主界面的UI布局、控件和定时器"""
super().__init__(parent=parent) super().__init__(parent=parent)
@ -48,6 +50,12 @@ class StatusMonitor(QWidget):
self.tcp_server_host = tcp_server_host self.tcp_server_host = tcp_server_host
self.tcp_server_port = tcp_server_port self.tcp_server_port = tcp_server_port
self.is_tcp_connected = False # TCP连接状态标记 self.is_tcp_connected = False # TCP连接状态标记
self.has_connected_once = False # 连接至服务器至少一次标记(区别首次连接和断开后重连)
self.reconnect_count = 0 # 重连次数计数器
# 重连定时器每隔RECONNECT_INTERVAL毫秒重连一次
self.reconnect_timer = QTimer(self)
self.reconnect_timer.setInterval(RECONNECT_INTERVAL)
self.reconnect_timer.timeout.connect(self._reconnect_to_server) # 绑定重连函数
# 绑定TCP信号与槽事件驱动 # 绑定TCP信号与槽事件驱动
self._bind_tcp_signals() self._bind_tcp_signals()
@ -72,8 +80,24 @@ class StatusMonitor(QWidget):
# 客户端自动后自动连接服务端 # 客户端自动后自动连接服务端
# ---------------- # ----------------
print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...") print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...")
self._connect_to_server()
def _connect_to_server(self):
"""主动发起连接(仅在未连接状态下有效"""
if not self.is_tcp_connected:
self.tcp_socket.abort() # 终止现有连接
self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port) self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port)
def _reconnect_to_server(self):
"""重连执行函数:仅在未连接且未达最大次数时触发"""
if not self.is_tcp_connected and self.reconnect_count < MAX_RECONNECT:
self.reconnect_count += 1
print(f"{self.reconnect_count}次重连(共{MAX_RECONNECT}次尝试)...")
self._connect_to_server()
elif self.reconnect_count >= MAX_RECONNECT:
self.reconnect_timer.stop() # 停止重连定时器
print(f"已达最大重连次数({MAX_RECONNECT}次),停止重连,请检查服务端状态")
def _init_save_dir(self): def _init_save_dir(self):
"""初始化数据保存目录""" """初始化数据保存目录"""
if not os.path.exists(SAVE_DIR): if not os.path.exists(SAVE_DIR):
@ -93,6 +117,9 @@ class StatusMonitor(QWidget):
# 错误信号(连接/通信出错时触发) # 错误信号(连接/通信出错时触发)
self.tcp_socket.errorOccurred.connect(self._on_tcp_error) self.tcp_socket.errorOccurred.connect(self._on_tcp_error)
# ------------------
# 界面初始化函数
# ------------------
def _init_title_label(self): def _init_title_label(self):
"""初始化系统标题标签""" """初始化系统标题标签"""
titleLabel = QLabel("中交三航精准布料浇筑要料系统") titleLabel = QLabel("中交三航精准布料浇筑要料系统")
@ -131,7 +158,7 @@ class StatusMonitor(QWidget):
self.mainLayout.addWidget(self.bigContainer, 1) self.mainLayout.addWidget(self.bigContainer, 1)
def _init_status_groups(self, parent_layout): def _init_status_groups(self, parent_layout):
"""初始化左右信息(各包含5个状态项)""" """初始化左右信息(各包含3个状态项)"""
statusWidget = QWidget() statusWidget = QWidget()
statusLayout = QHBoxLayout(statusWidget) statusLayout = QHBoxLayout(statusWidget)
statusLayout.setContentsMargins(0, 0, 0, 0) statusLayout.setContentsMargins(0, 0, 0, 0)
@ -149,19 +176,15 @@ class StatusMonitor(QWidget):
# 左边5个状态项及对应初始值 # 左边5个状态项及对应初始值
leftStatusInfo = [ leftStatusInfo = [
{"name": "任务单号", "value": "20250706-01", "api_field": "task_id"}, {"name": "任务单号", "value": "", "api_field": "task_id"},
{"name": "工程名称", "value": "18号线二期工程", "api_field": "project_name"}, {"name": "工程名称", "value": "", "api_field": "project_name"},
{"name": "区间段", "value": "停车场工作并上行", "api_field": "section"}, {"name": "配比号", "value": "", "api_field": "produce_mix_id"}
{"name": "坍落度", "value": "50~70 mm", "api_field": "slump"},
{"name": "配合比编号", "value": "P2022=001", "api_field": "mix_ratio_id"}
] ]
# 右边5个状态项及对应初始值 # 右边5个状态项及对应初始值
rightStatusInfo = [ rightStatusInfo = [
{"name": "要料状态", "value": "请求中", "api_field": "request_status"}, {"name": "要料状态", "value": "", "api_field": "flag"},
{"name": "要料标号", "value": "C50P12", "api_field": "material_grade"}, {"name": "砼强度", "value": "", "api_field": "beton_grade"},
{"name": "要料方量", "value": "2m³", "api_field": "volume"}, {"name": "要料方量", "value": "", "api_field": "adjusted_volume"},
{"name": "要料时间", "value": "2分钟后", "api_field": "request_time"},
{"name": "小车状态", "value": "移动后", "api_field": "car_status"}
] ]
self.statusWidgets = [] self.statusWidgets = []
@ -256,25 +279,17 @@ class StatusMonitor(QWidget):
buttonLayout.setSpacing(30) buttonLayout.setSpacing(30)
# 按钮图标(需替换为实际图标路径) # 按钮图标(需替换为实际图标路径)
start_icon_path = "img.png"
down_icon_path = "img.png"
error_icon_path = "img.png" error_icon_path = "img.png"
cancel_icon_path = "img.png" cancel_icon_path = "img.png"
self.startFeedButton = QPushButton("开始下料")
self.finishButton = QPushButton("下料完成")
self.errorButton = QPushButton("生产异常") self.errorButton = QPushButton("生产异常")
self.cancelButton = QPushButton("生产取消") self.cancelButton = QPushButton("生产取消")
# 设置按钮图标 # 设置按钮图标
self.startFeedButton.setIcon(QIcon(start_icon_path))
self.finishButton.setIcon(QIcon(down_icon_path))
self.errorButton.setIcon(QIcon(error_icon_path)) self.errorButton.setIcon(QIcon(error_icon_path))
self.cancelButton.setIcon(QIcon(cancel_icon_path)) self.cancelButton.setIcon(QIcon(cancel_icon_path))
# 设置图标大小 # 设置图标大小
self.startFeedButton.setIconSize(QSize(20, 20))
self.finishButton.setIconSize(QSize(20, 20))
self.errorButton.setIconSize(QSize(20, 20)) self.errorButton.setIconSize(QSize(20, 20))
self.cancelButton.setIconSize(QSize(20, 20)) self.cancelButton.setIconSize(QSize(20, 20))
@ -294,23 +309,6 @@ class StatusMonitor(QWidget):
opacity: 0.8; opacity: 0.8;
} }
""" """
self.startFeedButton.setStyleSheet(button_base_style + """
QPushButton {
background-color: #2196F3;
color: white;
border-color: #1976D2;
}
""")
self.finishButton.setStyleSheet(button_base_style + """
QPushButton {
background-color: #00796B;
color: white;
border-color: #004D40;
}
""")
self.errorButton.setStyleSheet(button_base_style + """ self.errorButton.setStyleSheet(button_base_style + """
QPushButton { QPushButton {
background-color: #E65100; background-color: #E65100;
@ -328,25 +326,17 @@ class StatusMonitor(QWidget):
""") """)
button_font = QFont("Microsoft YaHei", 12, QFont.Bold) button_font = QFont("Microsoft YaHei", 12, QFont.Bold)
self.startFeedButton.setFont(button_font)
self.finishButton.setFont(button_font)
self.errorButton.setFont(button_font) self.errorButton.setFont(button_font)
self.cancelButton.setFont(button_font) self.cancelButton.setFont(button_font)
self.startFeedButton.clicked.connect(self.on_start_clicked)
self.finishButton.clicked.connect(self.on_finish_clicked)
self.errorButton.clicked.connect(self.on_error_clicked) self.errorButton.clicked.connect(self.on_error_clicked)
self.cancelButton.clicked.connect(self.on_cancel_clicked) self.cancelButton.clicked.connect(self.on_cancel_clicked)
# 初始禁用“停止”和“异常”按钮(未连接时不可用) # 初始禁用“停止”和“异常”按钮(未连接时不可用)
self.startFeedButton.setDisabled(False)
self.finishButton.setDisabled(True)
self.errorButton.setDisabled(True) self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True) self.cancelButton.setDisabled(True)
buttonLayout.addStretch(1) buttonLayout.addStretch(1)
buttonLayout.addWidget(self.startFeedButton)
buttonLayout.addWidget(self.finishButton)
buttonLayout.addWidget(self.errorButton) buttonLayout.addWidget(self.errorButton)
buttonLayout.addWidget(self.cancelButton) buttonLayout.addWidget(self.cancelButton)
buttonLayout.addStretch(1) buttonLayout.addStretch(1)
@ -397,6 +387,9 @@ class StatusMonitor(QWidget):
# 绘制文本 # 绘制文本
painter.drawText(x, y + text_rect.height(), text) painter.drawText(x, y + text_rect.height(), text)
# ------------------
# 数据保存
# ------------------
def _save_data_to_file(self, button_name): def _save_data_to_file(self, button_name):
""" """
将服务端数据+按钮操作信息保存到JSON文件 将服务端数据+按钮操作信息保存到JSON文件
@ -427,6 +420,23 @@ class StatusMonitor(QWidget):
except Exception as e: except Exception as e:
print(f"💾 保存「{button_name}」操作记录失败:{str(e)}") print(f"💾 保存「{button_name}」操作记录失败:{str(e)}")
# --------------------
# 清空界面信息的通用方法
# --------------------
def _clear_ui_info(self):
"""清空所有状态项的显示内容,并并设置指示灯颜色"""
for widget in self.statusWidgets:
widget['valueLabel'].setText("")
# 指示灯设为初始灰色与_create_status_item中初始样式一致
widget['indicator'].setStyleSheet("""
QLabel {
background-color: #9E9E9E;
border-radius: 10px;
border: 2px solid #555555;
}
""")
print(" 界面信息已清空")
# ------------------ # ------------------
# TCP客户端核心功能 # TCP客户端核心功能
# ------------------ # ------------------
@ -434,14 +444,16 @@ class StatusMonitor(QWidget):
def _on_tcp_connected(self): def _on_tcp_connected(self):
"""TCP连接成功回调""" """TCP连接成功回调"""
self.is_tcp_connected = True self.is_tcp_connected = True
self.has_connected_once = True
self.reconnect_timer.stop() # 停止重连定时器
self.reconnect_count = 0 # 重连计数器清零
self.is_running = True self.is_running = True
print(f"TCP连接成功{self.tcp_server_host}:{self.tcp_server_port}") print(f"TCP连接成功{self.tcp_server_host}:{self.tcp_server_port}")
# 连接成功后,向服务器发送“请求初始数据”指令 # 连接成功后,向服务器发送“请求初始数据”指令
self._send_tcp_request("get_initial_data") self._send_tcp_request("get_initial_data")
# 更新按钮状态:启用“下料完成”“生产异常”“生产取消” # 更新按钮状态:启用“生产异常”“生产取消”
self.finishButton.setDisabled(False)
self.errorButton.setDisabled(False) self.errorButton.setDisabled(False)
self.cancelButton.setDisabled(False) self.cancelButton.setDisabled(False)
@ -453,8 +465,6 @@ class StatusMonitor(QWidget):
print(f"TCP连接断开{self.tcp_server_host}:{self.tcp_server_port}") print(f"TCP连接断开{self.tcp_server_host}:{self.tcp_server_port}")
# 启用/禁用按钮 # 启用/禁用按钮
self.startFeedButton.setDisabled(False)
self.finishButton.setDisabled(True)
self.errorButton.setDisabled(True) self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True) self.cancelButton.setDisabled(True)
@ -487,17 +497,21 @@ class StatusMonitor(QWidget):
@Slot(QAbstractSocket.SocketError) @Slot(QAbstractSocket.SocketError)
def _on_tcp_error(self, error): def _on_tcp_error(self, error):
"""TCP错误回调""" """TCP错误回调"""
if not self.is_tcp_connected:
error_str = self.tcp_socket.errorString() error_str = self.tcp_socket.errorString()
print(f"TCP错误{error_str}") print(f"TCP错误{error_str}")
self.is_tcp_connected = False self.is_tcp_connected = False
self.is_running = False self.is_running = False
# 启用/禁用按钮 # 启用/禁用按钮
self.startFeedButton.setDisabled(False)
self.finishButton.setDisabled(True)
self.errorButton.setDisabled(True) self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True) self.cancelButton.setDisabled(True)
# 首次连接失败时,启动重连定时器
if not self.has_connected_once and self.reconnect_count == 0:
print(f"将在{RECONNECT_INTERVAL / 1000}秒后启动重连(最多{MAX_RECONNECT}次)")
self.reconnect_timer.start()
def _send_tcp_request(self, request_cmd="get_status"): def _send_tcp_request(self, request_cmd="get_status"):
"""向TCP服务器发送请求指令""" """向TCP服务器发送请求指令"""
if not self.is_tcp_connected: if not self.is_tcp_connected:
@ -551,34 +565,17 @@ class StatusMonitor(QWidget):
# ------------------ # ------------------
# 按钮点击事件 # 按钮点击事件
# ------------------ # ------------------
def on_start_clicked(self):
"""点击“开始下料”:向服务端发送开始指令"""
print("🔘 点击「开始下料」按钮")
if not self.is_tcp_connected:
print("TCP连接未建立尝试重新连接")
self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port)
QTimer.singleShot(1000, lambda: self._send_tcp_request("start_feed")) # 等待连接成功后再发送请求
else:
print("TCP连接已建立")
self._send_tcp_request("start_feed")
def on_finish_clicked(self):
"""点击“下料完成”:向服务端发送完成指令"""
print("🔘 点击「下料完成」按钮")
self._send_tcp_request("finish_feed")
self._save_data_to_file("finish_feed")
def on_error_clicked(self): def on_error_clicked(self):
"""点击“生产异常”:向服务端发送异常指令""" """点击“生产异常”:向服务端发送异常指令"""
print("🔘 点击「生产异常」按钮") print("🔘 点击「生产异常」按钮")
self._clear_ui_info()
self._send_tcp_request("production_error") self._send_tcp_request("production_error")
self._save_data_to_file("production_error")
def on_cancel_clicked(self): def on_cancel_clicked(self):
"""点击“生产取消”:向服务端发送取消指令""" """点击“生产取消”:向服务端发送取消指令"""
print("🔘 点击「生产取消」按钮") print("🔘 点击「生产取消」按钮")
self._clear_ui_info()
self._send_tcp_request("cancel_feed") self._send_tcp_request("cancel_feed")
self._save_data_to_file("cancel_feed")
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) app = QApplication(sys.argv)