2025-11-16 11:58:22 +08:00
|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
'''
|
|
|
|
|
|
# @Time : 2025/11/10 11:29
|
|
|
|
|
|
# @Author : reenrr
|
|
|
|
|
|
# @Description : 重量显示界面,显示上料斗重量、下料斗重量
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
from PySide6.QtWidgets import (
|
|
|
|
|
|
QApplication,
|
|
|
|
|
|
QDialog,
|
|
|
|
|
|
QVBoxLayout,
|
|
|
|
|
|
QHBoxLayout,
|
|
|
|
|
|
QGridLayout,
|
|
|
|
|
|
QLabel,
|
|
|
|
|
|
QWidget,
|
|
|
|
|
|
QPushButton,
|
|
|
|
|
|
)
|
|
|
|
|
|
from PySide6.QtGui import QPixmap, QFont, QPainter, QIcon
|
|
|
|
|
|
from PySide6.QtCore import Qt, QEvent, QSize, QTimer, Slot
|
|
|
|
|
|
from PySide6.QtNetwork import QTcpSocket, QAbstractSocket
|
|
|
|
|
|
import sys
|
|
|
|
|
|
import json
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
|
|
class WeightDetailsDialog(QDialog):
|
|
|
|
|
|
"""
|
|
|
|
|
|
上料斗、下料斗重量显示界面
|
|
|
|
|
|
"""
|
|
|
|
|
|
def __init__(self, parent=None, title="上料斗重量" ):
|
|
|
|
|
|
super().__init__(parent)
|
|
|
|
|
|
self.setAttribute(Qt.WA_TranslucentBackground)
|
|
|
|
|
|
|
|
|
|
|
|
self.digit_labels = [] #用于存储数字标签的列表
|
|
|
|
|
|
self.default_icon_path = "选择_未实时.png" # 未连接图标
|
|
|
|
|
|
self.connected_icon_path = "选择_实时.png" # 已连接图标
|
|
|
|
|
|
self.check_label = None # 状态图标标签
|
|
|
|
|
|
|
|
|
|
|
|
self.is_running = False # 定时器是否运行
|
|
|
|
|
|
self.statusWidgets = [] # 状态显示控件列表
|
|
|
|
|
|
|
2025-11-18 11:22:04 +08:00
|
|
|
|
# 存储当前重量值(用于处理空值/异常值)
|
|
|
|
|
|
self.current_weight = 0.0
|
|
|
|
|
|
|
2025-11-16 11:58:22 +08:00
|
|
|
|
self._init_ui(title)
|
|
|
|
|
|
|
|
|
|
|
|
# -----------------------
|
|
|
|
|
|
# 界面初始化函数
|
|
|
|
|
|
# -----------------------
|
|
|
|
|
|
def _init_ui(self, title):
|
|
|
|
|
|
self.setWindowFlags(Qt.FramelessWindowHint)
|
|
|
|
|
|
self._load_background()
|
|
|
|
|
|
|
|
|
|
|
|
main_layout = QVBoxLayout(self)
|
|
|
|
|
|
main_layout.setContentsMargins(32, 20, 32, 50)
|
|
|
|
|
|
main_layout.setSpacing(0)
|
|
|
|
|
|
|
|
|
|
|
|
# 1. 顶部区域(标题 + 关闭按钮)
|
|
|
|
|
|
self._add_top_area(main_layout, title)
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 状态显示+重量框
|
|
|
|
|
|
self._add_state_weight_area(main_layout)
|
|
|
|
|
|
|
|
|
|
|
|
def _load_background(self):
|
|
|
|
|
|
self.bg_pixmap = QPixmap("重量背景.png") # 修改为派单任务背景图
|
|
|
|
|
|
if self.bg_pixmap.isNull():
|
|
|
|
|
|
print("错误:重量背景.png 加载失败,请检查路径!")
|
|
|
|
|
|
self.setFixedSize(800, 500)
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.setFixedSize(self.bg_pixmap.size())
|
|
|
|
|
|
|
|
|
|
|
|
def _add_top_area(self, parent_layout, title):
|
|
|
|
|
|
top_layout = QHBoxLayout()
|
|
|
|
|
|
top_layout.setContentsMargins(0, 0, 0, 36)
|
|
|
|
|
|
|
|
|
|
|
|
top_layout.addStretch()
|
|
|
|
|
|
|
|
|
|
|
|
title_label = QLabel(title)
|
|
|
|
|
|
font = QFont()
|
|
|
|
|
|
font.setPixelSize(24)
|
|
|
|
|
|
font.setLetterSpacing(QFont.AbsoluteSpacing, 2)
|
|
|
|
|
|
font.setBold(True)
|
|
|
|
|
|
title_label.setFont(font)
|
|
|
|
|
|
title_label.setStyleSheet("color: #13fffc; font-weight: Bold;")
|
|
|
|
|
|
title_label.setAlignment(Qt.AlignCenter)
|
|
|
|
|
|
top_layout.addWidget(title_label, alignment=Qt.AlignTop)
|
|
|
|
|
|
|
|
|
|
|
|
# 关闭按钮
|
|
|
|
|
|
top_layout.addStretch()
|
|
|
|
|
|
|
|
|
|
|
|
parent_layout.addLayout(top_layout)
|
|
|
|
|
|
|
|
|
|
|
|
def _add_state_weight_area(self, parent_layout):
|
|
|
|
|
|
grid_layout = QGridLayout()
|
|
|
|
|
|
grid_layout.setSpacing(12)
|
|
|
|
|
|
|
|
|
|
|
|
weight_widget = self._create_info_weight()
|
|
|
|
|
|
grid_layout.addWidget(weight_widget)
|
|
|
|
|
|
|
|
|
|
|
|
parent_layout.addLayout(grid_layout)
|
|
|
|
|
|
|
|
|
|
|
|
def _create_info_weight(self):
|
|
|
|
|
|
# 1、创建最外层水平布局(容纳所有元素)
|
|
|
|
|
|
weight_layout = QHBoxLayout()
|
|
|
|
|
|
weight_layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
|
|
weight_layout.setSpacing(0)
|
|
|
|
|
|
|
|
|
|
|
|
# 2、创建确认图标
|
|
|
|
|
|
self.check_label = QLabel()
|
2025-11-17 16:02:46 +08:00
|
|
|
|
self._update_status_icon1(False)
|
|
|
|
|
|
self._update_status_icon2(False)
|
2025-11-16 11:58:22 +08:00
|
|
|
|
weight_layout.addWidget(self.check_label)
|
|
|
|
|
|
weight_layout.setSpacing(50)
|
|
|
|
|
|
|
|
|
|
|
|
# 3、创建“6个数字单元格”
|
|
|
|
|
|
digit_font = QFont()
|
|
|
|
|
|
digit_font.setPixelSize(70)
|
|
|
|
|
|
digit_font.setLetterSpacing(QFont.AbsoluteSpacing, 2)
|
|
|
|
|
|
digit_font.setBold(False)
|
|
|
|
|
|
|
|
|
|
|
|
digit_pixmap = QPixmap("数字.png")
|
|
|
|
|
|
digit_size = digit_pixmap.size()
|
|
|
|
|
|
|
|
|
|
|
|
for i in range(6):
|
|
|
|
|
|
# 数字标签
|
|
|
|
|
|
digit_label = QLabel("")
|
|
|
|
|
|
digit_label.setFixedSize(digit_size)
|
|
|
|
|
|
digit_label.setFont(digit_font)
|
|
|
|
|
|
digit_label.setAlignment(Qt.AlignCenter)
|
|
|
|
|
|
digit_label.setStyleSheet("color: white")
|
|
|
|
|
|
# 若图片存在,设置背景图片
|
|
|
|
|
|
if not digit_pixmap.isNull():
|
|
|
|
|
|
digit_label.setStyleSheet("""
|
|
|
|
|
|
QLabel {
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
background-image: url(数字.png);
|
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
|
background-position: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
""")
|
|
|
|
|
|
weight_layout.addWidget(digit_label)
|
|
|
|
|
|
self.digit_labels.append(digit_label)
|
|
|
|
|
|
if i < 5:
|
|
|
|
|
|
weight_layout.addSpacing(5)
|
|
|
|
|
|
|
|
|
|
|
|
# 4、创建“kg”单位单元格
|
|
|
|
|
|
unit_label = QLabel("kg")
|
|
|
|
|
|
unit_label.setFixedSize(digit_size)
|
|
|
|
|
|
unit_label.setFont(digit_font)
|
|
|
|
|
|
unit_label.setAlignment(Qt.AlignCenter)
|
|
|
|
|
|
if not digit_pixmap.isNull():
|
|
|
|
|
|
unit_label.setStyleSheet("""
|
|
|
|
|
|
QLabel {
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
background-image: url(数字.png);
|
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
|
background-position: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
""")
|
|
|
|
|
|
weight_layout.addSpacing(5)
|
|
|
|
|
|
weight_layout.addWidget(unit_label)
|
|
|
|
|
|
|
|
|
|
|
|
# 5、将主布局设置到父控件
|
|
|
|
|
|
weight_widget = QWidget()
|
|
|
|
|
|
weight_widget.setLayout(weight_layout)
|
|
|
|
|
|
weight_widget.setObjectName("infoWeight")
|
|
|
|
|
|
return weight_widget
|
|
|
|
|
|
|
|
|
|
|
|
def eventFilter(self, obj, event):
|
|
|
|
|
|
"""
|
|
|
|
|
|
实现事件过滤器,动态修改右侧值颜色
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 只处理父控件(infoCell)的事件
|
|
|
|
|
|
if obj.objectName() == "infoCell":
|
|
|
|
|
|
# 鼠标进入父控件 → 改#13f0f3
|
|
|
|
|
|
if event.type() == QEvent.Enter:
|
|
|
|
|
|
if hasattr(obj, "value"): # 确保存在value控件
|
|
|
|
|
|
obj.value.setStyleSheet("background: none; color: #13f0f3;")
|
|
|
|
|
|
# 鼠标离开父控件 → 恢复默认色
|
|
|
|
|
|
elif event.type() == QEvent.Leave:
|
|
|
|
|
|
if hasattr(obj, "value"):
|
|
|
|
|
|
obj.value.setStyleSheet("background: none; color: #9fbfd4;")
|
|
|
|
|
|
return super().eventFilter(obj, event)
|
|
|
|
|
|
|
|
|
|
|
|
def paintEvent(self, event):
|
|
|
|
|
|
if not self.bg_pixmap.isNull():
|
|
|
|
|
|
painter = QPainter(self)
|
|
|
|
|
|
painter.drawPixmap(self.rect(), self.bg_pixmap)
|
|
|
|
|
|
super().paintEvent(event)
|
|
|
|
|
|
|
|
|
|
|
|
def update_weight(self, weight_data):
|
|
|
|
|
|
"""根据TCP获取的数据更新重量显示"""
|
|
|
|
|
|
# 更新6个数字标签(补零为6位,超过6位取后6位)
|
2025-11-18 11:22:04 +08:00
|
|
|
|
# 处理空值/异常值(客户端传递的 "" 或 "error")
|
|
|
|
|
|
if weight_data == "" or weight_data == "error" or weight_data is None:
|
2025-11-16 11:58:22 +08:00
|
|
|
|
weight_str = "000000"
|
2025-11-18 11:22:04 +08:00
|
|
|
|
self.current_weight = 0
|
|
|
|
|
|
else:
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 支持浮点数(如 648.06 → 保留2位小数后转为整数显示,避免丢失精度)
|
|
|
|
|
|
weight_int = int(float(weight_data))
|
|
|
|
|
|
self.current_weight = weight_int
|
|
|
|
|
|
weight_str = f"{weight_int:06d}"[-6:] # 超过6位取后6位
|
|
|
|
|
|
except (ValueError, TypeError):
|
|
|
|
|
|
weight_str = "000000"
|
|
|
|
|
|
self.current_weight = 0
|
|
|
|
|
|
|
|
|
|
|
|
# 更新6个数字标签
|
2025-11-16 11:58:22 +08:00
|
|
|
|
for i in range(min(len(self.digit_labels), 6)):
|
|
|
|
|
|
self.digit_labels[i].setText(weight_str[i] if i < len(weight_str) else "0")
|
|
|
|
|
|
|
2025-11-17 16:02:46 +08:00
|
|
|
|
def _update_status_icon1(self, is_connected):
|
2025-11-16 11:58:22 +08:00
|
|
|
|
"""根据连接状态切换图标"""
|
|
|
|
|
|
if not self.check_label:
|
|
|
|
|
|
return
|
|
|
|
|
|
icon_path = self.connected_icon_path if is_connected else self.default_icon_path
|
|
|
|
|
|
pixmap = QPixmap(icon_path)
|
|
|
|
|
|
if not pixmap.isNull():
|
|
|
|
|
|
self.check_label.setPixmap(pixmap.scaled(
|
|
|
|
|
|
pixmap.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
|
|
|
|
else:
|
|
|
|
|
|
print(f"错误:{icon_path} 加载失败,请检查路径!")
|
|
|
|
|
|
|
2025-11-17 16:02:46 +08:00
|
|
|
|
def _update_status_icon2(self, is_error):
|
|
|
|
|
|
"""根据是否有错误信息,切换图标"""
|
|
|
|
|
|
if not self.check_label:
|
|
|
|
|
|
return
|
|
|
|
|
|
icon_path = self.default_icon_path if is_error else self.connected_icon_path
|
|
|
|
|
|
pixmap = QPixmap(icon_path)
|
|
|
|
|
|
if not pixmap.isNull():
|
|
|
|
|
|
self.check_label.setPixmap(pixmap.scaled(
|
|
|
|
|
|
pixmap.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
|
|
|
|
else:
|
|
|
|
|
|
print(f"错误:{icon_path} 加载失败,请检查路径!")
|
|
|
|
|
|
|
2025-11-16 11:58:22 +08:00
|
|
|
|
# --------------------
|
|
|
|
|
|
# 清空界面信息的通用方法
|
|
|
|
|
|
# --------------------
|
|
|
|
|
|
def _clear_ui_info(self):
|
|
|
|
|
|
"""清空管片ID和网格信息"""
|
2025-11-18 11:22:04 +08:00
|
|
|
|
# 修复:避免访问未定义的 self.id_value_label
|
|
|
|
|
|
if hasattr(self, 'id_value_label') and self.id_value_label:
|
2025-11-16 11:58:22 +08:00
|
|
|
|
self.id_value_label.setText("")
|
|
|
|
|
|
for widget in self.statusWidgets:
|
2025-11-18 11:22:04 +08:00
|
|
|
|
if 'valueLabel' in widget and widget['valueLabel']:
|
|
|
|
|
|
widget['valueLabel'].setText("")
|
|
|
|
|
|
# 清空重量显示
|
|
|
|
|
|
for label in self.digit_labels:
|
|
|
|
|
|
label.setText("0")
|
2025-11-16 11:58:22 +08:00
|
|
|
|
print("ℹ️ 界面信息已清空")
|
|
|
|
|
|
|
|
|
|
|
|
# 测试代码
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
app = QApplication(sys.argv)
|
|
|
|
|
|
dialog = WeightDetailsDialog()
|
|
|
|
|
|
dialog.show()
|
|
|
|
|
|
sys.exit(app.exec())
|