Files
Feeding_control_system/view/widgets/task_widget.py

304 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QMessageBox, QApplication)
from PySide6.QtCore import Qt, Signal
from PySide6.QtGui import QPainter, QPixmap, QFont
import sys
import resources.resources_rc
from utils.image_paths import ImagePaths
"""
任务控件,如:管片任务、派单任务
"""
class TaskWidget(QWidget):
# 任务详情信号: task1表示第一条任务 (用于详情对话框)
task_details_signal = Signal(str)
# 任务选择按钮选中的信号 (用于上方的计划表单)
task_selected_signal = Signal(str)
def __init__(self, taskTitle:str, parent=None):
super().__init__(parent)
# 设置Widget大小与背景图一致
self.bg_pixmap = QPixmap(ImagePaths.TASK_INFO_BACKGROUND1)
self.setFixedSize(self.bg_pixmap.size())
# 主布局(垂直)
self.main_layout = QVBoxLayout(self)
self.main_layout.setContentsMargins(0, 0, 0, 6)
self.main_layout.setSpacing(0)
# 任务标题
title_label = QLabel(taskTitle, self)
title_label.setStyleSheet("font-size: 24px; color: #16ffff;padding-top:4px;")
title_label.setAlignment(Qt.AlignCenter)
self.main_layout.addWidget(title_label, alignment=Qt.AlignTop)
# 标题字体设置
# title_font = title_label.font()
title_font = QFont("Microsoft YaHei")
title_font.setLetterSpacing(QFont.AbsoluteSpacing, 3) # 字间距3px
title_font.setWeight(QFont.DemiBold)
title_label.setFont(title_font)
# 用字典存储每个任务的可修改控件(键:任务名,值:控件字典)
self.task_controls = {} # 结构:{"task1": {"volume_label": xxx, "time_label": xxx, ...}, ...}
self.current_selected_task = None # 选择按钮,当前选中的任务的任务名
# 三条任务条目
self._add_task("task1", "SHRB1-3", ImagePaths.TASK_RECT1)
self._add_task("task2", "SHRB2-3", ImagePaths.TASK_RECT2)
self._add_task("task3", "SHRB1-3", ImagePaths.TASK_RECT3)
def paintEvent(self, event):
"""绘制背景图片"""
painter = QPainter(self)
painter.drawPixmap(self.rect(), self.bg_pixmap)
super().paintEvent(event)
def _add_task(self, task_name, task_id, status_icon):
"添加相应的任务条目到布局,同时将其相应的控件存入字典"
# 1、创建任务条目以及相应的控件字典
item_widget, controls = self._create_task_item(task_name, task_id, status_icon)
# 2、将控件字典存入 相应的 任务条目字典
self.task_controls[task_name] = controls
# 3、将任务条目添加到主布局
self.main_layout.addWidget(item_widget, alignment=Qt.AlignTop)
def _create_task_item(self, task_name, task_id, status_icon):
"""创建单条任务条目, 返回任务条目和控件字典"""
item_widget = QWidget()
item_layout = QVBoxLayout(item_widget)
item_layout.setContentsMargins(9, 6, 9, 8)
item_layout.setSpacing(0)
# 相应的 任务条目的控件字典
controls = {} # {"volume_label": ..., "time_label": ..., ...}
# 水平布局1选择按钮 + 任务名 + 详情按钮
row1_layout = QHBoxLayout()
# 任务选择按钮
select_btn = QPushButton()
select_btn.setFixedSize(14, 14)
select_btn.setCursor(Qt.PointingHandCursor)
select_btn.setStyleSheet(f"""
QPushButton {{
background-image: url({ImagePaths.TASK_INFO_SELECT_BTN1});
border: none;
}}
QPushButton:checked {{
background-image: url({ImagePaths.TASK_INFO_SELECT_BTN2});
}}
""")
select_btn.setCheckable(True)
select_btn.clicked.connect(lambda checked, tn=task_name: self._on_select_btn_clicked(tn, checked))
controls["select_btn"] = select_btn
row1_layout.addWidget(select_btn)
# 任务编号
task_id_label = QLabel(task_id)
task_id_label.setStyleSheet("font-size: 18px; color: #16ffff;padding-left: 6px;")
# 1. 设置鼠标样式为手型,提示可点击
task_id_label.setCursor(Qt.PointingHandCursor)
# 2. 绑定点击事件点击标签时选中对应的select_btn
task_id_label.mousePressEvent = lambda event, tn=task_name: self._on_task_id_clicked(tn)
controls["task_id_label"] = task_id_label
row1_layout.addWidget(task_id_label)
# 详情按钮
detail_btn = QPushButton()
detail_btn.setText("详情")
detail_btn.setFixedSize(46, 26)
detail_btn.setCursor(Qt.PointingHandCursor)
detail_btn.setStyleSheet(f"""
QPushButton {{
background-image: url({ImagePaths.TASK_INFO_DETAIL_BTN1});
border: none;
color: #3bfff8;
font-size: 16px;
}}
QPushButton:hover {{
background-image: url({ImagePaths.TASK_INFO_DETAIL_BTN2});
color: #001c83;
font-size: 16px;
}}
""")
detail_btn.clicked.connect(lambda: self._show_detail_dialog(task_name)) # 详情按钮槽函数
controls["detail_btn"] = detail_btn
row1_layout.addWidget(detail_btn)
item_layout.addLayout(row1_layout)
# 水平布局2方量 + / + 时间 + 状态图标
row2_layout = QHBoxLayout()
# 方量标签
volume_label = QLabel("方量 200")
volume_label.setStyleSheet("color: #a1c1d7; font-size: 14px;padding-left: 6px;")
controls["volume_label"] = volume_label
row2_layout.addWidget(volume_label)
# 分隔标签
sep_label = QLabel("/")
sep_label.setStyleSheet("color: #a1c1d7;")
row2_layout.addWidget(sep_label, alignment=Qt.AlignCenter)
# 时间标签
time_label = QLabel("03:22PM")
time_label.setStyleSheet("color: #a1c1d7; font-size: 14px;")
controls["time_label"] = time_label
row2_layout.addWidget(time_label)
# 状态文本标签
status_text_label = QLabel()
status_text_label.setStyleSheet("color: #16ffff; font-size: 14px;")
controls["status_text_label"] = status_text_label
row2_layout.addWidget(status_text_label)
# 状态图标标签
status_icon_label = QLabel()
status_icon_label.setPixmap(QPixmap(status_icon))
controls["status_icon_label"] = status_icon_label
row2_layout.addWidget(status_icon_label, alignment=Qt.AlignRight)
# 添加水平布局2到item_layout
item_layout.addLayout(row2_layout)
# 分隔线
item_layout.setSpacing(5)
separator = QLabel()
separator.setPixmap(QPixmap(ImagePaths.TASK_INFO_SEPARATOR))
separator.setFixedSize(196, 1)
item_layout.addWidget(separator)
return item_widget, controls # 返回任务条目 以及 相应的控件
def _show_detail_dialog(self, task_name):
"""显示任务详情弹窗"""
# QMessageBox.information(self, "任务详情", f"任务 {task_name} 的详细信息...")
"""
task1 表示第一条任务, 依次类推
"""
# 发送任务详情信号
self.task_details_signal.emit(task_name)
def _on_select_btn_clicked(self, task_name: str, checked: bool):
"""
处理选择按钮点击事件,实现互斥选中
:param task_name: 点击的任务名task1/task2/task3
:param checked: 按钮是否被选中True/False
"""
# 1. 如果是选中操作checked=True
if checked:
# 取消之前选中的任务按钮
if self.current_selected_task and self.current_selected_task != task_name:
prev_select_btn = self.task_controls[self.current_selected_task]["select_btn"]
prev_select_btn.setChecked(False) # 取消选中
# 更新当前选中的任务
self.current_selected_task = task_name
# 通知任务选中按钮更新了选中
self.task_selected_signal.emit(task_name)
else:
# 2. 如果是取消选中操作checked=False
# 重新设为选中状态,阻止取消 (确保该按钮继续为选中状态,保证至少有一个按钮被选中)
current_select_btn = self.task_controls[task_name]["select_btn"]
current_select_btn.setChecked(True)
# 确保选中标记不丢失
self.current_selected_task = task_name
def _on_task_id_clicked(self, task_name: str):
"""
点击任务编号标签时,选中对应的选择按钮(复用互斥逻辑)
:param task_name: 点击的任务名task1/task2/task3
"""
if task_name in self.task_controls:
# 1. 获取对应select_btn
select_btn = self.task_controls[task_name]["select_btn"]
# 2. 模拟点击相应的选择按钮
if not select_btn.isChecked():
select_btn.click()
# --------------------------
# 对外接口:修改任务属性
# 三个任务条目对应的任务名task_name分别为 task1、task2、task3
# --------------------------
def set_task_volume(self, task_name:str, volume: float):
"""修改指定任务的方量, 传入具体的方量值,如: 200.0"""
# 褚工说 管片任务 和 派单任务的方量只有一位小数。 2025-11-8
# 所以这里限制为 保留一位小数的浮点数
current_volume = round(float(volume), 1)
if task_name in self.task_controls:
volume_label = self.task_controls[task_name]["volume_label"]
volume_label.setText(f"方量 {current_volume}")
def set_task_time(self, task_name:str, time_str: str):
"""修改指定任务的时间, 传入对应格式的时间,如: 03:22PM"""
if task_name in self.task_controls:
time_label = self.task_controls[task_name]["time_label"]
time_label.setText(time_str)
def set_task_status(self, task_name:str, status_str: str, icon_path:str):
"""修改指定任务的状态, 比如: 已下发、计划中等"""
ICON_COLOR_MAP = {
ImagePaths.TASK_RECT1: "#16ffff",
ImagePaths.TASK_RECT2: "#ffab11",
ImagePaths.TASK_RECT3: "#54f529",
ImagePaths.TASK_RECT4: "#ff6a5c",
ImagePaths.TASK_RECT5: "#f6f44b"
}
DEFAULT_COLOR = "#000000"
if task_name in self.task_controls:
status_label = self.task_controls[task_name]["status_text_label"] # 状态文本
status_label.setText(status_str)
icon_label = self.task_controls[task_name]["status_icon_label"] # 状态图标
icon_label.setPixmap(QPixmap(icon_path))
# 修改状态文本的颜色
status_text_color = ICON_COLOR_MAP.get(icon_path, DEFAULT_COLOR)
status_label.setStyleSheet(f"QLabel {{ color: {status_text_color}; font-size: 14px;}}")
def set_task_id(self, task_name:str, new_id: str):
"""修改指定任务的编号, 如: SHRB2-3"""
if task_name in self.task_controls:
task_id_label = self.task_controls[task_name]["task_id_label"]
task_id_label.setText(new_id)
def set_task_select_btn_selected(self, task_name:str):
"""设置 任务选择按钮选中 (主要用于刷新计划表单)"""
if task_name in self.task_controls:
task_select_btn = self.task_controls[task_name]["select_btn"]
task_select_btn.click()
def get_task_volume(self, task_name:str):
"""
获取指定任务的方量, 传入任务名,如 task1、task2、task3
return: 返回 float类型一位小数的方量值
"""
if task_name in self.task_controls:
volume_label = self.task_controls[task_name]["volume_label"]
# 提取 volume_label中显示的 "方量 200" 中的数字部分
# 1. 去除前后空格,按空格分割字符串
volume_text = volume_label.text().strip()
parts = volume_text.split()
# 2. 取分割后的数字部分
if len(parts) >= 2:
number_str = parts[1] # 得到 "200"
else:
# 格式异常没有数字部分返回None
return None
# 褚工说任务中显示的方量只有一位小数
try:
volume_value = round(float(number_str), 1)
return volume_value
except ValueError:
return None
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = TaskWidget("管片任务")
# 示例修改task2的方量为300测试用
widget.set_task_volume("task2", 300)
# 示例修改task1的时间为04:50PM测试用
widget.set_task_time("task1", "04:50PM")
widget.show()
sys.exit(app.exec())