This commit is contained in:
2025-11-16 11:55:28 +08:00
commit 17b5f8348d
25 changed files with 874 additions and 0 deletions

3
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
# 默认忽略的文件
/shelf/
/workspace.xml

View File

@ -0,0 +1,18 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="5">
<item index="0" class="java.lang.String" itemvalue="scipy" />
<item index="1" class="java.lang.String" itemvalue="numpy" />
<item index="2" class="java.lang.String" itemvalue="snap7" />
<item index="3" class="java.lang.String" itemvalue="jsonchema" />
<item index="4" class="java.lang.String" itemvalue="werkzeung" />
</list>
</value>
</option>
</inspection_tool>
</profile>
</component>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="pyside6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="pyside6" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/中交三航背景界面.iml" filepath="$PROJECT_DIR$/.idea/中交三航背景界面.iml" />
</modules>
</component>
</project>

8
.idea/中交三航背景界面.iml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="pyside6" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

41
bottom_control_widget.py Normal file
View File

@ -0,0 +1,41 @@
from PySide6.QtWidgets import (QWidget, QHBoxLayout, QLabel, QPushButton,
QMessageBox, QSpacerItem, QSizePolicy)
from PySide6.QtGui import QPixmap, QPainter, QFont, QPen
from PySide6.QtCore import Qt, QDateTime, QEvent, QSize
class BottomControlWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.initUI()
def initUI(self):
# 1. 加载背景图并设置控件尺寸
bg_path = "底部背景.png"
self.bg_pixmap = QPixmap(bg_path)
if self.bg_pixmap.isNull():
print("警告:底部背景.png 加载失败,请检查路径!")
self.setFixedSize(1280, 66)
else:
self.setFixedSize(self.bg_pixmap.size())
# 2. 主布局水平布局组件间距6px
main_layout = QHBoxLayout(self)
main_layout.setContentsMargins(10, 10, 10, 10) # 适当留白避免贴边
main_layout.setSpacing(6)
def paintEvent(self, event):
"""绘制背景图"""
super().paintEvent(event)
if not self.bg_pixmap.isNull():
painter = QPainter(self)
painter.drawPixmap(0, 0, self.bg_pixmap)
if __name__ == "__main__":
import sys
from PySide6.QtWidgets import QApplication
app = QApplication(sys.argv)
widget = BottomControlWidget()
widget.show()
sys.exit(app.exec())

529
dispatch_task.py Normal file
View File

@ -0,0 +1,529 @@
#!/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
# -----------
# 参数配置
# -----------
tcp_server_host = "127.0.0.1"
tcp_server_port = 8888
RECONNECT_INTERVAL = 2000 # 重连间隔(毫秒)
class DispatchDetailsDialog(QDialog):
"""
派单任务的界面
"""
def __init__(self, parent=None):
super().__init__(parent)
self.setAttribute(Qt.WA_TranslucentBackground)
self.is_running = False # 系统运行状态标记
self.latest_json_data = {"erp_id": None, "artifact_id": None} # 缓存服务端发送的最新JSON数据
self.statusWidgets = [] # 存储api_field + 对应的value标签
# ---------------
# 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连接状态标记
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信号与槽事件驱动
self._bind_tcp_signals()
# 初始化存储需要修改的控件
self.id_value_label = None # 对应管片ID值标签
self.rows = [] # 所有行的单元格列表包含label、value
self._init_ui()
# ----------------
# 客户端自动后自动连接服务端
# ----------------
print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...")
self._connect_to_server()
# ---------------------
# TCP连接相关函数
# ---------------------
def _connect_to_server(self):
"""主动发起连接(仅在未连接状态下有效"""
if not self.is_tcp_connected and self.tcp_socket.state() != QAbstractSocket.ConnectingState:
self.tcp_socket.abort() # 终止现有连接
self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port)
print(f"发起连接请求:{self.tcp_server_host}:{self.tcp_server_port}")
def _reconnect_to_server(self):
"""重连执行函数:无线重连,知道连接成功"""
if not self.is_tcp_connected:
self.reconnect_count += 1
# 日志优化每10次重连提示一次避免日志刷屏
if self.reconnect_count % 10 == 0:
print(f"已连续重连{self.reconnect_count}次,仍未连接服务端,请检查服务端状态...")
else:
print(f"{self.reconnect_count}次重连请求:{self.tcp_server_host}:{self.tcp_server_port}")
self._connect_to_server()
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_ui(self):
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)
# 2. 对应管片ID区域
self._add_segment_id_area(main_layout)
# 3. 网格信息区域单列6行
self._add_grid_info_area(main_layout)
main_layout.addSpacing(30)
# 4. 操作按钮区域
self._init_operation_buttons(main_layout)
def _init_operation_buttons(self, parent_layout):
"""初始化操作按钮(生产异常/生产取消)"""
buttonContainer = QWidget()
buttonLayout = QHBoxLayout(buttonContainer)
buttonLayout.setSpacing(100)
self.errorButton = QPushButton("生产异常")
self.cancelButton = QPushButton("生产取消")
self.errorButton.setStyleSheet("""
QPushButton {
color: #1E1E1E;
font-size: 18px;
font-weight: bold;
padding: 15px 50px;
border: 1px solid;
background-color: #FF0000;
border-color: transparent;
}
QPushButton:hover {
opacity: 0.9;
background-color: #B71C1C;
}
QPushButton:pressed {
opacity: 0.8;
}
""")
self.cancelButton.setStyleSheet("""
QPushButton {
color: #1E1E1E;
font-size: 18px;
font-weight: bold;
padding: 15px 50px;
border: 1px solid;
background-color: #FFD700;
border-color: transparent;
}
QPushButton:hover {
opacity: 0.9;
background-color: #FFB300
}
QPushButton:pressed {
opacity: 0.8;
}
""")
self.errorButton.clicked.connect(self.on_error_clicked)
self.cancelButton.clicked.connect(self.on_cancel_clicked)
# 初始禁用“停止”和“异常”按钮(未连接时不可用)
self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True)
buttonLayout.addStretch(1)
buttonLayout.addWidget(self.errorButton)
buttonLayout.addWidget(self.cancelButton)
buttonLayout.addStretch(1)
parent_layout.addWidget(buttonContainer)
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):
top_layout = QHBoxLayout()
top_layout.setContentsMargins(0, 0, 0, 36)
top_layout.addStretch()
# 标题改为“任务派单”
title_label = QLabel("任务派单")
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_segment_id_area(self, parent_layout):
id_layout = QHBoxLayout()
id_label = QLabel("对应管片ID") # 标签文字修改
id_label.setFixedSize(318, 32)
id_font = QFont()
id_font.setPixelSize(18)
id_font.setLetterSpacing(QFont.AbsoluteSpacing, 2)
id_font.setBold(True)
id_label.setFont(id_font)
id_label.setStyleSheet(
"""
background-image: url("详情标题.png");
background-repeat: no-repeat;
background-position: center;
color: #13ffff;
"""
)
id_label.setContentsMargins(16, 0, 0, 0)
id_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
self.id_value_label = QLabel("") # 初始管片ID值
value_font = QFont()
value_font.setPixelSize(18)
value_font.setBold(True)
value_font.setLetterSpacing(QFont.AbsoluteSpacing, 2)
self.id_value_label.setFont(value_font)
self.id_value_label.setStyleSheet("color: #13ffff;")
self.id_value_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
id_layout.addWidget(id_label)
id_layout.addStretch()
id_layout.addWidget(self.id_value_label)
id_layout.setContentsMargins(0, 0, 0, 16)
parent_layout.addLayout(id_layout)
parent_layout.setAlignment(id_layout, Qt.AlignTop)
def _add_grid_info_area(self, parent_layout):
grid_layout = QGridLayout()
grid_layout.setSpacing(12)
# 初始化信息条目6行
info_items = [
{"name":"任务单号", "value": "", "api_field": "task_id"},
{"name": "工程名称", "value": "", "api_field": "project_name"},
{"name": "配比编号", "value": "", "api_field": "produce_mix_id"},
{"name": "要料状态", "value": "", "api_field": "flag"},
{"name": "砼强度", "value": "", "api_field": "beton_grade"},
{"name": "要料方量", "value": "", "api_field": "adjusted_volume"},
]
self.rows.clear()
self.statusWidgets.clear() # 清空缓存
for row, item in enumerate(info_items):
cell_widget = self._create_info_cell(item["name"], item["value"])
self.rows.append(cell_widget)
grid_layout.addWidget(cell_widget, row, 0)
self.statusWidgets.append({
'api_field': item["api_field"],
'valueLabel': cell_widget.value # 绑定实际UI控件
}
)
parent_layout.addLayout(grid_layout)
def _create_info_cell(self, label_text, value_text):
cell_widget = QWidget()
cell_bg = QPixmap("派单任务信息栏1.png") # 正常背景图
cell_widget.setObjectName("infoCell")
if not cell_bg.isNull():
cell_widget.setFixedSize(cell_bg.size())
cell_widget.setStyleSheet(
"""
QWidget {
background-image: url(派单任务信息栏1.png);
background-repeat: no-repeat;
background-position: Center;
}
QWidget:hover {
background-image: url(派单任务信息栏2.png);
}
QWidget QLabel#valueLabel {
color: #9fbfd4;
background: none;
}
"""
)
cell_layout = QHBoxLayout(cell_widget)
cell_layout.setContentsMargins(0, 0, 0, 0)
# 左侧标签
label = QLabel(label_text)
label.setFixedSize(136, 60)
label_font = QFont()
label_font.setPixelSize(16)
label_font.setLetterSpacing(QFont.AbsoluteSpacing, 2)
label.setFont(label_font)
label.setStyleSheet("background: none;color: #fffffd; font-weight:Bold;")
label.setAlignment(Qt.AlignCenter)
cell_widget.label = label
# 右侧值标签设置objectName以便样式选择
value = QLabel(value_text)
value.setObjectName("valueLabel")
value_font = QFont()
value_font.setPixelSize(20)
value.setFont(value_font)
value.setAlignment(Qt.AlignCenter)
cell_widget.value = value
cell_layout.addWidget(label) # 左侧的标题标签
cell_layout.addSpacing(60)
cell_layout.addWidget(value) # 右侧的值标签
cell_widget.installEventFilter(self)
return cell_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_ui_from_data(self, data):
"""根据TCP获取的数据更新界面状态"""
# 1、更新顶部独立的“对应管片ID”
if "artifact_id" in data:
self.id_value_label.setText(str(data["artifact_id"]))
# 2、更新网格中的所有字段
for widget in self.statusWidgets:
api_field = widget['api_field']
value_label = widget['valueLabel']
if api_field in data:
new_value = str(data[api_field])
value_label.setText(new_value)
# ------------------- 对外修改接口 -------------------
# row 对应行号(0-6)从0开始
# --------------------------------------------------
def set_segment_id(self, new_id):
"""修改上方的 对应的管片ID的值"""
if self.id_value_label:
self.id_value_label.setText(str(new_id))
def set_row_label(self, row, new_label_text: str):
"""修改左侧的显示的标签的文本,如: 创建时间、派单时间等"""
if 0 <= row < len(self.rows):
self.rows[row].label.setText(new_label_text)
def set_row_value(self, row, new_value_text: str):
"""修改右侧的显示的值, 如: 2025年9月9日 9:9:9"""
if 0 <= row < len(self.rows):
self.rows[row].value.setText(new_value_text)
# ------------------
# 按钮点击事件
# ------------------
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")
# --------------------
# 清空界面信息的通用方法
# --------------------
def _clear_ui_info(self):
"""清空管片ID和网格信息"""
if self.id_value_label:
self.id_value_label.setText("")
for widget in self.statusWidgets:
widget['valueLabel'].setText("")
print(" 界面信息已清空")
# ------------------
# TCP客户端核心功能
# ------------------
@Slot()
def _on_tcp_connected(self):
"""TCP连接成功回调"""
self.is_tcp_connected = True
self.has_connected_once = True
self.reconnect_timer.stop() # 停止重连定时器
self.reconnect_count = 0 # 重连计数器清零
self.is_running = True
print(f"TCP连接成功{self.tcp_server_host}:{self.tcp_server_port}")
# 连接成功后,向服务器发送“请求初始数据”指令
self._send_tcp_request("get_initial_data")
# 更新按钮状态:启用“生产异常”“生产取消”
self.errorButton.setDisabled(False)
self.cancelButton.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}")
# 启用/禁用按钮
self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True)
# 清空界面
self._clear_ui_info()
if not self.reconnect_timer.isActive():
print(f"连接断开,将在{RECONNECT_INTERVAL / 1000}秒后启动重连...")
self.reconnect_timer.start()
@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_json_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错误回调"""
if not self.is_tcp_connected:
error_str = self.tcp_socket.errorString()
print(f"TCP错误{error_str}")
self.is_tcp_connected = False
self.is_running = False
# 启用/禁用按钮
self.errorButton.setDisabled(True)
self.cancelButton.setDisabled(True)
# 首次连接失败时,启动重连定时器
if not self.reconnect_timer.isActive():
print(f"将在{RECONNECT_INTERVAL / 1000}秒后启动重连")
self.reconnect_timer.start()
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,
"erp_id": self.latest_json_data["erp_id"],
"artifact_id": self.latest_json_data["artifact_id"],
"timestamp": self.get_current_time(),
"client_info": "布料系统客户端"
}) + "\n" # 增加换行符作为数据结束标识
# 发送请求数据
self.tcp_socket.write(request_data.encode("utf-8"))
print(f"TCP请求发送{request_data.strip()}")
# ------------------
# 时间相关的通用方法
# ------------------
def get_current_time(self):
"""获取格式化的当前时间"""
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 测试代码
if __name__ == "__main__":
app = QApplication(sys.argv)
dialog = DispatchDetailsDialog()
dialog.show()
sys.exit(app.exec())

113
main_window.py Normal file
View File

@ -0,0 +1,113 @@
# coding: utf-8
from typing import List
from PySide6.QtCore import Qt, Signal, QEasingCurve, QUrl, QSize, QTimer, QEvent
from PySide6.QtGui import QIcon, QDesktopServices, QColor, QPalette, QBrush, QImage
from PySide6.QtWidgets import (QApplication, QHBoxLayout, QVBoxLayout,
QFrame, QWidget, QSpacerItem, QSizePolicy, QMainWindow, QPushButton)
from system_nav_bar import SystemNavBar
from bottom_control_widget import BottomControlWidget
from dispatch_task import DispatchDetailsDialog
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initWindow()
self.createSubWidgets() # 创建子部件
self.setupLayout() # 设置布局
def initWindow(self):
"""初始化窗口基本属性"""
self.setWindowTitle("中交三航主界面") # 设置窗口标题
# 设置最小尺寸(可根据需求调整)
# 触摸屏尺寸为 1280*800
self.setMinimumSize(1280, 800)
self.setObjectName("MainWindow")
# Qt.FramelessWindowHint
self.setWindowFlags(Qt.FramelessWindowHint) # 无边框窗口
# 设置主界面背景图片
try:
self.background_image = QImage("主界面背景.png")
if self.background_image.isNull():
raise Exception("图片为空,可能路径错误或格式不支持")
# print("图片加载成功")
except Exception as e:
print(f"主界面背景图片加载失败: {e}")
self.background_image = None
return # 加载背景失败
self.update_background()
def createSubWidgets(self):
"""创建所有子部件实例"""
self.system_nav_bar = SystemNavBar() # 最上方:系统导航栏
self.bottom_control_widget = BottomControlWidget() # 最下方: 控制的按钮 (系统诊断、系统中心等)
# 中间:任务派单
self.dispatch_dialog = DispatchDetailsDialog(self)
def setupLayout(self):
"""设置垂直布局,从上到下排列部件"""
main_layout = QVBoxLayout(self) # 主布局:垂直布局
main_layout.setSpacing(0) # 部件间距0px
main_layout.setContentsMargins(0, 0, 0, 0) # 左上右下边距0px
# 添加最上方的 系统导航栏包括系统标题、中交三航的logo等
main_layout.addWidget(self.system_nav_bar, alignment=Qt.AlignTop)
# 添加中间内容区
main_layout.addWidget(self.dispatch_dialog, alignment=Qt.AlignCenter)
# 添加最下方的 控制按钮控件
main_layout.addWidget(self.bottom_control_widget, alignment=Qt.AlignBottom)
# 关闭按钮
self.system_nav_bar.msg_container.close_btn.clicked.connect(self.close)
# 将布局应用到主窗口
self.setLayout(main_layout)
def show_dispatch_dialog(self):
"""显示派单详细弹窗(居中显示在主界面)"""
# 计算弹窗居中位置
main_geometry = self.frameGeometry()
dialog_geometry = self.dispatch_dialog.frameGeometry()
dialog_geometry.moveCenter(main_geometry.center())
self.dispatch_dialog.move(dialog_geometry.topLeft())
# 显示弹窗
self.dispatch_dialog.show()
def update_background(self):
"""更新主界面背景图片"""
if self.background_image and not self.background_image.isNull():
palette = self.palette()
# 按当前窗口尺寸缩放图片
scaled_image = self.background_image.scaled(
self.size(),
Qt.IgnoreAspectRatio,
Qt.SmoothTransformation
)
palette.setBrush(QPalette.Window, QBrush(scaled_image))
self.setPalette(palette)
self.setAutoFillBackground(True)
def resizeEvent(self, e):
"""窗口大小变化时的回调"""
super().resizeEvent(e)
self.update_background() # 重新加载背景图片
def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape: # 按下Esc键, 退出界面
self.close()
super().keyPressEvent(event)
if __name__ == "__main__":
import sys
app = QApplication([])
window = MainWindow()
window.show() # 显示主界面
# window.showFullScreen() # 全屏显示主界面
sys.exit(app.exec())

141
system_nav_bar.py Normal file
View File

@ -0,0 +1,141 @@
from PySide6.QtWidgets import (QWidget, QLabel, QHBoxLayout,
QSpacerItem, QSizePolicy, QPushButton)
from PySide6.QtGui import QPixmap, QFont, QPainter, QIcon
from PySide6.QtCore import Qt, QTimer, QDateTime
# 自定义消息容器, 显示系统消息
class MsgContainer(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedSize(770, 24)
# 加载消息区域背景图
self.bg_pixmap = QPixmap("系统消息背景.png") # 替换为实际路径
if self.bg_pixmap.isNull():
print("警告:系统消息背景.png 加载失败")
# 消息区域内部布局(喇叭+文本)
msg_layout = QHBoxLayout(self)
msg_layout.setContentsMargins(0, 0, 0, 0) # 调整内边距,避免内容贴边
msg_layout.setSpacing(3) # 喇叭和文本的间距
# 消息喇叭图标
self.msg_icon = QLabel()
self.msg_icon.setFixedSize(13, 18)
# self.msg_icon.setStyleSheet("background-color:red;")
self.msg_icon.setPixmap(QPixmap("系统消息喇叭.png")) # 替换为实际路径
msg_layout.addWidget(self.msg_icon, alignment=Qt.AlignVCenter | Qt.AlignLeft)
# 消息文本
current_time = QDateTime.currentDateTime().toString("hh:mm:ss")
self.msg_text = QLabel(f"{current_time} 开始启动智能浇筑系统")
self.msg_text.setFixedWidth(740)
# self.msg_text.setStyleSheet("color: white; font-size: 14px;background-color:red;") # 文本样式
self.msg_text.setStyleSheet("color: white; font-size: 16px;font-weight:Bold;")
self.msg_text.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
msg_layout.addWidget(self.msg_text)
# 关闭按钮
self._create_close_button(msg_layout)
def _create_close_button(self, parent_layout):
self.close_btn = QPushButton()
self.close_btn.setFixedSize(20, 20)
close_icon = QPixmap("关闭图标.png")
if not close_icon.isNull():
self.close_btn.setIcon(QIcon(close_icon))
self.close_btn.setStyleSheet(
"""
QPushButton {
background-color: transparent;
border: none;
padding: 0px;
}
QPushButton:hover {
background-color: red;
border-radius: 2px;
}
"""
)
parent_layout.addWidget(self.close_btn)
def paintEvent(self, event):
# 绘制消息区域背景图
super().paintEvent(event) # 确保子控件正常绘制
if self.bg_pixmap.isNull():
return # 图片加载失败则不绘制
painter = QPainter(self)
painter.setRenderHint(QPainter.SmoothPixmapTransform) # 缩放平滑
painter.drawPixmap(self.rect(), self.bg_pixmap)
class SystemNavBar(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# 设置尺寸
self.setFixedSize(1280, 80)
# 1. 加载背景图
self.bg_pixmap = QPixmap("系统主界面导航栏.png") # 替换为实际图片路径
if self.bg_pixmap.isNull():
print("警告:背景图加载失败,请检查路径!")
main_layout = QHBoxLayout(self)
main_layout.setContentsMargins(9, 9, 9, 19)
main_layout.setSpacing(100) # 注意左侧的logo+系统标题的容器 和 系统消息的间隔
# 左侧区域logo + 系统标题
left_container = QWidget()
left_container.setFixedSize(400, 53)
left_layout = QHBoxLayout(left_container) # 容器内部的水平布局
left_layout.setContentsMargins(0, 0, 0, 0) # 容器内边距
left_layout.setSpacing(6) # 设置logo和标题之间的间隙为6px
# 系统logo
self.logo = QLabel()
self.logo.setFixedSize(53, 53)
self.logo.setPixmap(QPixmap("系统logo.png"))
left_layout.addWidget(self.logo, alignment=Qt.AlignTop)
# 系统总标题
self.title = QLabel()
self.title.setPixmap(QPixmap("系统总标题.png"))
left_layout.addWidget(self.title, alignment=Qt.AlignCenter)
main_layout.addWidget(left_container, alignment=Qt.AlignTop)
# 中间区域:系统消息(喇叭+文本+背景)
self.msg_container = MsgContainer()
main_layout.addWidget(self.msg_container, alignment=Qt.AlignBottom | Qt.AlignRight)
# 右侧区域:实时时间
self.time_label = QLabel()
self.time_label.setStyleSheet("color: white; font-size: 16px;font-weight:Bold;")
main_layout.addWidget(self.time_label, alignment= Qt.AlignTop | Qt.AlignRight)
# 启动时间更新定时器
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_time)
self.timer.start(1000) # 每秒更新一次
def paintEvent(self, event):
super().paintEvent(event)
painter = QPainter(self)
painter.setRenderHint(QPainter.SmoothPixmapTransform) # 缩放时平滑
painter.drawPixmap(0, 0, self.bg_pixmap)
def update_time(self):
current_time = QDateTime.currentDateTime().toString("yyyy/MM/dd hh:mm:ss")
self.time_label.setText(current_time)
# 测试代码
if __name__ == "__main__":
import sys
from PySide6.QtWidgets import QApplication, QMainWindow
app = QApplication(sys.argv)
nav_bar = SystemNavBar()
nav_bar.show()
sys.exit(app.exec())

BIN
主界面背景.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
关闭图标.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

BIN
底部背景.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
派单任务信息栏1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

BIN
派单任务信息栏2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

BIN
派单最底部.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
生产取消按钮.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

BIN
生产异常按钮.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

BIN
系统logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
系统总标题.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
系统消息喇叭.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

BIN
系统消息背景.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
详情弹出背景.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
详情标题.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB