增加系统诊断弹窗
@ -2,6 +2,7 @@
|
||||
from PySide6.QtCore import Qt, QPropertyAnimation, QRect, QParallelAnimationGroup, QEasingCurve
|
||||
from view.widgets.system_center_dialog import SystemCenterDialog
|
||||
from view.widgets.bottom_control_widget import BottomControlWidget
|
||||
from view.widgets.system_diagnostics_dialog import SystemDiagnosticsDialog
|
||||
|
||||
"""
|
||||
控制主界面底部的所有按钮, 包括系统诊断、系统中心等的行为。
|
||||
@ -19,11 +20,19 @@ class BottomControlController:
|
||||
self.system_center_dialog.hide() # 初始隐藏 (必须)
|
||||
self._init_system_center_dialog_hide_animations()
|
||||
|
||||
# 系统诊断弹窗
|
||||
self.system_diagnostics_dialog = SystemDiagnosticsDialog(self.main_window)
|
||||
self.system_diagnostics_dialog.hide()
|
||||
self._init_system_diagnostics_dialog_hide_animations()
|
||||
|
||||
self._bind_dialog_signals()
|
||||
|
||||
def _bind_buttons(self):
|
||||
# 底部系统中心按钮 → 触发弹窗显示/隐藏
|
||||
self.bottom_control_widget.center_btn.clicked.connect(self.toggle_system_center_dialog)
|
||||
|
||||
# 底部系统诊断按钮 → 触发弹窗显示/隐藏
|
||||
self.bottom_control_widget.diagnosis_btn.clicked.connect(self.toggle_system_diagnostics_dialog)
|
||||
|
||||
def _bind_dialog_signals(self):
|
||||
"""绑定弹窗按钮的信号"""
|
||||
@ -53,7 +62,7 @@ class BottomControlController:
|
||||
self.hide_anim_group.finished.connect(self.system_center_dialog.hide)
|
||||
|
||||
def toggle_system_center_dialog(self):
|
||||
"""切换弹窗的显示/隐藏状态"""
|
||||
"""切换系统中心弹窗的显示/隐藏状态"""
|
||||
if self.system_center_dialog.isVisible():
|
||||
# 已显示 → 隐藏
|
||||
# self.system_center_dialog.hide()
|
||||
@ -94,7 +103,7 @@ class BottomControlController:
|
||||
# 设置弹窗位置
|
||||
self.system_center_dialog.move(dialog_x, dialog_y)
|
||||
|
||||
# ------------------- 业务逻辑方法-------------------
|
||||
# ------------------- 系统中心弹窗业务逻辑-------------------
|
||||
def handle_sys_setting(self):
|
||||
"""系统设置按钮的业务逻辑"""
|
||||
# print("执行系统设置逻辑:如打开系统配置窗口、修改参数等")
|
||||
@ -108,4 +117,78 @@ class BottomControlController:
|
||||
|
||||
def handle_user_center(self):
|
||||
"""用户中心按钮的业务逻辑"""
|
||||
# print("执行用户中心逻辑:如切换用户、修改密码等")
|
||||
# print("执行用户中心逻辑:如切换用户、修改密码等")
|
||||
|
||||
# ------------------- 系统诊断弹窗逻辑-------------------
|
||||
def _init_system_diagnostics_dialog_hide_animations(self):
|
||||
"""初始化系统诊断弹窗隐藏动画(与显示动画反向:滑出+淡出)"""
|
||||
# 1. 淡出动画(与显示动画时长一致)
|
||||
self.dia_hide_opacity_anim = QPropertyAnimation(
|
||||
self.system_diagnostics_dialog, b"windowOpacity", self.system_diagnostics_dialog
|
||||
)
|
||||
self.dia_hide_opacity_anim.setDuration(300) # 显示动画为400ms
|
||||
self.dia_hide_opacity_anim.setStartValue(1.0)
|
||||
self.dia_hide_opacity_anim.setEndValue(0.0)
|
||||
|
||||
# 2. 位置动画(从当前位置滑出到下方100px,与显示动画反向)
|
||||
self.dia_hide_pos_anim = QPropertyAnimation(
|
||||
self.system_diagnostics_dialog, b"geometry", self.system_diagnostics_dialog
|
||||
)
|
||||
self.dia_hide_pos_anim.setDuration(300)
|
||||
self.dia_hide_pos_anim.setEasingCurve(QEasingCurve.InQuart) # 滑出曲线与显示反向
|
||||
|
||||
# 3. 组合动画(同时执行滑出和淡出)
|
||||
self.dia_hide_anim_group = QParallelAnimationGroup(self.system_diagnostics_dialog)
|
||||
self.dia_hide_anim_group.addAnimation(self.dia_hide_opacity_anim)
|
||||
self.dia_hide_anim_group.addAnimation(self.dia_hide_pos_anim)
|
||||
# 动画结束后强制隐藏弹窗
|
||||
self.dia_hide_anim_group.finished.connect(self.system_diagnostics_dialog.hide)
|
||||
|
||||
def toggle_system_diagnostics_dialog(self):
|
||||
"""切换系统诊断弹窗的显示/隐藏状态"""
|
||||
if self.system_diagnostics_dialog.isVisible():
|
||||
# 已显示 → 执行隐藏动画
|
||||
self._start_diagnostics_hide_animation()
|
||||
else:
|
||||
# 未显示 → 计算位置并显示(触发显示动画)
|
||||
self._calc_system_diagnostics_dialog_position()
|
||||
self.system_diagnostics_dialog.show()
|
||||
|
||||
def _calc_system_diagnostics_dialog_position(self):
|
||||
"""计算系统诊断弹窗位置(显示在诊断按钮上方,与中心弹窗布局一致)"""
|
||||
btn = self.bottom_control_widget.diagnosis_btn # 诊断按钮
|
||||
bottom_widget = self.bottom_control_widget
|
||||
|
||||
# 计算按钮在主窗口中的绝对位置
|
||||
bottom_pos_rel_main = bottom_widget.pos() # 底部控件相对于主窗口的位置
|
||||
btn_pos_rel_bottom = btn.pos() # 诊断按钮相对于底部控件的位置
|
||||
btn_pos_rel_main = bottom_pos_rel_main + btn_pos_rel_bottom # 诊断按钮在主窗口中的绝对位置
|
||||
|
||||
# 计算弹窗坐标(显示在按钮上方,水平居中对齐)
|
||||
btn_width = btn.width()
|
||||
dialog_size = self.system_diagnostics_dialog.size()
|
||||
# 水平方向:与按钮居中对齐
|
||||
# dialog_x = btn_pos_rel_main.x() + (btn_width - dialog_size.width()) // 2
|
||||
# dialog_x = btn_pos_rel_main.x() + (btn_width - dialog_size.width())
|
||||
dialog_x = btn_pos_rel_main.x() # 与系统诊断按钮的左边平齐
|
||||
# 垂直方向:在按钮上方(与按钮保持10px间距)
|
||||
# dialog_y = btn_pos_rel_main.y() - dialog_size.height() - 10
|
||||
dialog_y = btn_pos_rel_main.y() - dialog_size.height()
|
||||
|
||||
# 设置弹窗位置(动画会基于此位置执行滑入效果)
|
||||
self.system_diagnostics_dialog.move(dialog_x, dialog_y)
|
||||
|
||||
def _start_diagnostics_hide_animation(self):
|
||||
"""启动系统诊断弹窗的隐藏动画(滑出+淡出)"""
|
||||
current_geo = self.system_diagnostics_dialog.geometry() # 当前位置和尺寸
|
||||
# 计算隐藏动画终点(当前位置下方100px,与显示动画起点对应)
|
||||
end_rect = QRect(
|
||||
current_geo.x(),
|
||||
current_geo.y() + 100, # 向下滑出100px
|
||||
current_geo.width(),
|
||||
current_geo.height()
|
||||
)
|
||||
# 设置动画参数并启动
|
||||
self.dia_hide_pos_anim.setStartValue(current_geo)
|
||||
self.dia_hide_pos_anim.setEndValue(end_rect)
|
||||
self.dia_hide_anim_group.start()
|
||||
@ -18,6 +18,7 @@ class MainController:
|
||||
|
||||
def showMainWindow(self):
|
||||
self.main_window.showFullScreen()
|
||||
# self.main_window.show()
|
||||
self.main_window.dispatch_task_widget.set_task_time("task1","15:44 PM")
|
||||
self.main_window.dispatch_task_widget.set_task_time("task2","17:37 PM")
|
||||
self.main_window.segment_task_widget.set_task_time("task1","15:38 PM")
|
||||
|
||||
BIN
images/系统诊断下拉箭头.png
Normal file
|
After Width: | Height: | Size: 172 B |
BIN
images/系统诊断小框.png
Normal file
|
After Width: | Height: | Size: 213 B |
BIN
images/系统诊断弹出背景.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
images/系统诊断毫秒背景.png
Normal file
|
After Width: | Height: | Size: 735 B |
BIN
images/系统诊断状态红.png
Normal file
|
After Width: | Height: | Size: 257 B |
BIN
images/系统诊断状态绿.png
Normal file
|
After Width: | Height: | Size: 251 B |
BIN
images/系统诊断状态黄.png
Normal file
|
After Width: | Height: | Size: 265 B |
@ -92,4 +92,13 @@ class ImagePaths:
|
||||
ROUND_BTN_BG2 = ":/icons/images/圆形按钮背景2.png"
|
||||
|
||||
# 功能:主界面相关
|
||||
MAIN_INTERFACE_BACKGROUND = ":/icons/images/主界面背景.png"
|
||||
MAIN_INTERFACE_BACKGROUND = ":/icons/images/主界面背景.png"
|
||||
|
||||
# 功能: 系统诊断弹窗
|
||||
SYSTEM_DIAGNOSTICS_POPUP_BG = "images/系统诊断弹出背景.png"
|
||||
SYSTEM_DIAGNOSTICS_BOX = "images/系统诊断小框.png"
|
||||
SYSTEM_DIAGNOSTICS_STATUS_GREEN = "images/系统诊断状态绿.png"
|
||||
SYSTEM_DIAGNOSTICS_STATUS_YELLOW = "images/系统诊断状态黄.png"
|
||||
SYSTEM_DIAGNOSTICS_STATUS_RED = "images/系统诊断状态红.png"
|
||||
SYSTEM_DIAGNOSTICS_MS_BG = "images/系统诊断毫秒背景.png"
|
||||
SYSTEM_DIAGNOSTICS_DROPDOWN_ARROW = "images/系统诊断下拉箭头.png"
|
||||
@ -63,7 +63,8 @@ class MainWindow(QWidget):
|
||||
# self.setStyleSheet("background-color: #ffffff;") # #001558
|
||||
|
||||
# Qt.FramelessWindowHint
|
||||
# self.setWindowFlags(Qt.FramelessWindowHint)
|
||||
# 没有顶部的白色边框
|
||||
self.setWindowFlags(Qt.FramelessWindowHint) # 无边框
|
||||
|
||||
# 设置主界面背景图片
|
||||
try:
|
||||
|
||||
@ -60,10 +60,10 @@ class SystemCenterDialog(QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.init_ui()
|
||||
self._init_ui()
|
||||
self.init_animations() # 初始化动画
|
||||
|
||||
def init_ui(self):
|
||||
def _init_ui(self):
|
||||
# 弹窗基础设置
|
||||
self.setWindowTitle("系统中心")
|
||||
self.setWindowFlags(Qt.FramelessWindowHint) # 隐藏默认边框
|
||||
|
||||
385
view/widgets/system_diagnostics_dialog.py
Normal file
@ -0,0 +1,385 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication,
|
||||
QMainWindow,
|
||||
QWidget,
|
||||
QVBoxLayout,
|
||||
QGridLayout,
|
||||
QLabel,
|
||||
QHBoxLayout,
|
||||
QListWidget,
|
||||
QListWidgetItem,
|
||||
QSpacerItem,
|
||||
QSizePolicy,
|
||||
QLineEdit,
|
||||
QDialog,
|
||||
)
|
||||
from PySide6.QtGui import QPixmap, QFont, QColor, QTransform, QPainter
|
||||
from PySide6.QtCore import (
|
||||
Qt,
|
||||
QPoint,
|
||||
QEvent,
|
||||
QPropertyAnimation,
|
||||
QEasingCurve,
|
||||
QRect,
|
||||
QParallelAnimationGroup,
|
||||
)
|
||||
import sys
|
||||
|
||||
from utils.image_paths import ImagePaths
|
||||
|
||||
class CustomDropdown(QWidget):
|
||||
"""自定义下拉框组件"""
|
||||
|
||||
def __init__(self, options, arrow_img_path, parent=None):
|
||||
super().__init__(parent)
|
||||
self.options = options
|
||||
self.arrow_img_path = arrow_img_path
|
||||
self.is_expanded = False
|
||||
|
||||
# 主布局(标签 + 箭头)
|
||||
self.main_layout = QHBoxLayout(self)
|
||||
self.main_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.main_layout.setSpacing(0)
|
||||
self.main_layout.setAlignment(Qt.AlignLeft)
|
||||
self.setFixedSize(63, 19) # 需要根据下拉框需要显示的文字来修改
|
||||
# self.setFixedHeight(19)
|
||||
|
||||
# 1. 结果显示标签(QLabel,无clicked信号)
|
||||
self.result_label = QLabel(options[0])
|
||||
self.result_label.setStyleSheet(
|
||||
"""
|
||||
background-image: url("");
|
||||
color: #16ffff;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
font-size: 18px;
|
||||
"""
|
||||
)
|
||||
# self.result_label.setCursor(Qt.PointingHandCursor) # 手型光标提示可点击
|
||||
self.main_layout.addWidget(
|
||||
self.result_label, alignment=Qt.AlignVCenter | Qt.AlignLeft
|
||||
)
|
||||
|
||||
# 2. 可点击的箭头标签(QLabel)
|
||||
self.arrow_label = QLabel()
|
||||
self.arrow_pixmap = QPixmap(arrow_img_path)
|
||||
self.arrow_label.setStyleSheet("background-image: url(" ");")
|
||||
self.arrow_label.setPixmap(
|
||||
self.arrow_pixmap.scaled(12, 9, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
)
|
||||
self.arrow_label.setCursor(Qt.PointingHandCursor)
|
||||
self.main_layout.addWidget(self.arrow_label, alignment=Qt.AlignTop)
|
||||
|
||||
# 3. 下拉选项列表(默认选中第一个)
|
||||
self.list_widget = QListWidget()
|
||||
self.list_widget.setWindowFlags(Qt.Popup)
|
||||
|
||||
# 设置选项字体
|
||||
font = QFont()
|
||||
font.setPixelSize(16)
|
||||
|
||||
# 添加所有的下拉选项
|
||||
for option in options:
|
||||
item = QListWidgetItem(option)
|
||||
item.setTextAlignment(Qt.AlignLeft)
|
||||
item.setFont(font)
|
||||
self.list_widget.addItem(item)
|
||||
self.list_widget.setCurrentRow(0) # 默认选中第一项
|
||||
self.list_widget.itemClicked.connect(self.select_option)
|
||||
|
||||
# 双保险监听:全局焦点变化 + 事件过滤
|
||||
self.app = QApplication.instance()
|
||||
self.app.focusChanged.connect(self.on_focus_changed)
|
||||
self.list_widget.installEventFilter(self)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""重写鼠标点击事件,实现QLabel点击功能"""
|
||||
# 判断点击是否在result_label或arrow_label区域内
|
||||
# if self.result_label.underMouse() or self.arrow_label.underMouse():
|
||||
# self.toggle_expand()
|
||||
if self.arrow_label.underMouse():
|
||||
self.toggle_expand()
|
||||
super().mousePressEvent(event) # 传递事件,不影响其他组件
|
||||
|
||||
def toggle_expand(self):
|
||||
"""切换下拉框展开/收起 + 箭头旋转"""
|
||||
if self.is_expanded:
|
||||
self.list_widget.hide()
|
||||
# 箭头恢复向下
|
||||
self.arrow_label.setPixmap(
|
||||
self.arrow_pixmap.scaled(
|
||||
12, 9, Qt.KeepAspectRatio, Qt.SmoothTransformation
|
||||
)
|
||||
)
|
||||
else:
|
||||
# 计算下拉框位置(在标签下方对齐)
|
||||
label_pos = self.result_label.mapToGlobal(
|
||||
QPoint(0, self.result_label.height())
|
||||
)
|
||||
self.list_widget.setGeometry(
|
||||
label_pos.x(), label_pos.y(), self.result_label.width() + 10, 80
|
||||
)
|
||||
self.list_widget.show()
|
||||
self.list_widget.setFocus()
|
||||
# 箭头旋转180度(向上)
|
||||
transform = QTransform().rotate(180)
|
||||
rotated_pixmap = self.arrow_pixmap.transformed(
|
||||
transform, Qt.SmoothTransformation
|
||||
)
|
||||
self.arrow_label.setPixmap(rotated_pixmap)
|
||||
self.is_expanded = not self.is_expanded
|
||||
|
||||
def select_option(self, item):
|
||||
"""选择选项后更新标签 + 收起下拉框"""
|
||||
self.result_label.setText(item.text())
|
||||
self.list_widget.hide()
|
||||
self.arrow_label.setPixmap(self.arrow_pixmap)
|
||||
self.is_expanded = False
|
||||
|
||||
def on_focus_changed(self, old_widget, new_widget):
|
||||
"""焦点变化时关闭下拉框"""
|
||||
if self.is_expanded:
|
||||
is_focus_on_self = (
|
||||
new_widget == self
|
||||
or new_widget == self.result_label
|
||||
or new_widget == self.arrow_label
|
||||
or (self.list_widget.isAncestorOf(new_widget) if new_widget else False)
|
||||
)
|
||||
if not is_focus_on_self:
|
||||
self.list_widget.hide()
|
||||
self.arrow_label.setPixmap(self.arrow_pixmap)
|
||||
self.is_expanded = False
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
"""点击外部关闭下拉框"""
|
||||
if obj == self.list_widget and event.type() == QEvent.MouseButtonPress:
|
||||
self.list_widget.hide()
|
||||
self.arrow_label.setPixmap(
|
||||
self.arrow_pixmap.scaled(
|
||||
12, 9, Qt.KeepAspectRatio, Qt.SmoothTransformation
|
||||
)
|
||||
)
|
||||
self.is_expanded = False
|
||||
return True
|
||||
return super().eventFilter(obj, event)
|
||||
|
||||
def setFont(self, font):
|
||||
"""设置字体"""
|
||||
self.result_label.setFont(font)
|
||||
for i in range(self.list_widget.count()):
|
||||
self.list_widget.item(i).setFont(font)
|
||||
|
||||
# 获取当前选中的设备名
|
||||
def get_selected_device(self):
|
||||
return self.result_label.text()
|
||||
|
||||
|
||||
class SystemDiagnosticsDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setAttribute(Qt.WA_TranslucentBackground)
|
||||
self.setWindowOpacity(0.0)
|
||||
self._init_ui()
|
||||
self.init_animations()
|
||||
|
||||
def _init_ui(self):
|
||||
# 无边框模式
|
||||
self.setWindowFlags(Qt.FramelessWindowHint)
|
||||
|
||||
# 加载系统诊断弹窗的背景图片
|
||||
self.bg_pixmap = QPixmap(ImagePaths.SYSTEM_DIAGNOSTICS_POPUP_BG)
|
||||
if self.bg_pixmap.isNull():
|
||||
print("错误: 系统诊断弹窗背景图加载失败!请检查路径是否正确")
|
||||
else:
|
||||
# 窗口尺寸与图片尺寸完全一致
|
||||
self.setFixedSize(self.bg_pixmap.size())
|
||||
|
||||
# 网格布局(8行4列小框)
|
||||
grid_layout = QGridLayout(self)
|
||||
grid_layout.setContentsMargins(24, 28, 20, 24)
|
||||
|
||||
# 图片路径(替换为实际路径)
|
||||
box_image_path = ImagePaths.SYSTEM_DIAGNOSTICS_BOX
|
||||
circle_normal_path = ImagePaths.SYSTEM_DIAGNOSTICS_STATUS_GREEN # 正常状态
|
||||
circle_warning_path = ImagePaths.SYSTEM_DIAGNOSTICS_STATUS_YELLOW # 警告状态
|
||||
circle_error_path = ImagePaths.SYSTEM_DIAGNOSTICS_STATUS_RED # 异常状态
|
||||
ms_box_path = ImagePaths.SYSTEM_DIAGNOSTICS_MS_BG
|
||||
dropdown_arrow_path = ImagePaths.SYSTEM_DIAGNOSTICS_DROPDOWN_ARROW
|
||||
|
||||
# 字体设置
|
||||
ms_font = QFont()
|
||||
ms_font.setPixelSize(14)
|
||||
ms_color = QColor("#14abea")
|
||||
|
||||
# 生成小框
|
||||
for row in range(8):
|
||||
for col in range(4):
|
||||
box_container = QWidget()
|
||||
box_container.setObjectName(f"box_{row}_{col}")
|
||||
box_container.setStyleSheet(
|
||||
f"""
|
||||
background-image: url("{box_image_path}");
|
||||
background-repeat: no-repeat;
|
||||
"""
|
||||
)
|
||||
box_layout = QHBoxLayout(box_container)
|
||||
box_layout.setSpacing(0)
|
||||
|
||||
# ========== 状态圆圈(支持状态切换) ==========
|
||||
circle_label = QLabel()
|
||||
circle_label.status = "normal"
|
||||
circle_label.pixmaps = {
|
||||
"normal": QPixmap(circle_normal_path),
|
||||
"warning": QPixmap(circle_warning_path),
|
||||
"error": QPixmap(circle_error_path),
|
||||
}
|
||||
circle_label.setPixmap(circle_label.pixmaps["normal"])
|
||||
circle_label.setStyleSheet("background: none;")
|
||||
|
||||
# ========== 自定义下拉框(支持获取设备名) ==========
|
||||
led_dropdown = CustomDropdown(
|
||||
options=["LED1", "LED2", "LED3"], arrow_img_path=dropdown_arrow_path
|
||||
)
|
||||
|
||||
# ========== 秒数输入框(获取毫秒值) ==========
|
||||
ms_container = QWidget()
|
||||
ms_layout = QHBoxLayout(ms_container)
|
||||
ms_layout.setContentsMargins(6, 0, 0, 0)
|
||||
ms_edit = QLineEdit("5ms")
|
||||
ms_edit.setFont(ms_font)
|
||||
ms_edit.setStyleSheet(
|
||||
f"""
|
||||
background: none;
|
||||
color: {ms_color.name()};
|
||||
border: none;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
"""
|
||||
)
|
||||
ms_container.setStyleSheet(
|
||||
f"""
|
||||
background-image: url("{ms_box_path}");
|
||||
background-repeat: no-repeat;
|
||||
"""
|
||||
)
|
||||
ms_layout.addWidget(ms_edit)
|
||||
|
||||
# 保存组件引用 (动态增加)
|
||||
box_container.circle = circle_label
|
||||
box_container.dropdown = led_dropdown
|
||||
box_container.ms_edit = ms_edit
|
||||
|
||||
# 间距调整
|
||||
spacer1 = QSpacerItem(5, 1, QSizePolicy.Fixed, QSizePolicy.Minimum)
|
||||
spacer2 = QSpacerItem(5, 1, QSizePolicy.Fixed, QSizePolicy.Minimum)
|
||||
spacer3 = QSpacerItem(8, 1, QSizePolicy.Fixed, QSizePolicy.Minimum)
|
||||
# box_layout.addItem(spacer1)
|
||||
box_layout.addWidget(circle_label)
|
||||
box_layout.addItem(spacer2)
|
||||
box_layout.addWidget(led_dropdown)
|
||||
# box_layout.addItem(spacer3)
|
||||
box_layout.addWidget(ms_container)
|
||||
|
||||
grid_layout.addWidget(box_container, row, col)
|
||||
|
||||
def init_animations(self):
|
||||
"""初始化显示动画:从下方滑入 + 淡入"""
|
||||
# 1. 透明度动画(从0→1,与系统中心一致但时长不同)
|
||||
self.opacity_anim = QPropertyAnimation(self, b"windowOpacity")
|
||||
self.opacity_anim.setDuration(400)
|
||||
self.opacity_anim.setStartValue(0.0)
|
||||
self.opacity_anim.setEndValue(1.0)
|
||||
self.opacity_anim.setEasingCurve(QEasingCurve.OutCubic) # 缓动曲线不同
|
||||
|
||||
# 2. 位置动画(从下方100px滑入目标位置,核心差异点)
|
||||
self.pos_anim = QPropertyAnimation(self, b"geometry")
|
||||
self.pos_anim.setDuration(400)
|
||||
self.pos_anim.setEasingCurve(QEasingCurve.OutQuart) # 滑入效果更自然
|
||||
|
||||
# 3. 组合动画(同时执行滑入和淡入)
|
||||
self.anim_group = QParallelAnimationGroup(self)
|
||||
self.anim_group.addAnimation(self.opacity_anim)
|
||||
self.anim_group.addAnimation(self.pos_anim)
|
||||
|
||||
def showEvent(self, event):
|
||||
super().showEvent(event) # 先调用父类方法
|
||||
|
||||
# 动态计算动画起点(在当前位置下方100px,保持宽度和高度不变)
|
||||
current_geometry = self.geometry() # 当前位置和尺寸(需提前用move设置)
|
||||
# 起点:y坐标增加100px(从下方滑入),x和尺寸不变
|
||||
start_rect = QRect(
|
||||
current_geometry.x(),
|
||||
current_geometry.y() + 100, # 下方100px
|
||||
current_geometry.width(),
|
||||
current_geometry.height()
|
||||
)
|
||||
# 设置动画起点和终点
|
||||
self.pos_anim.setStartValue(start_rect)
|
||||
self.pos_anim.setEndValue(current_geometry) # 终点:目标位置
|
||||
|
||||
# 启动动画
|
||||
self.anim_group.start()
|
||||
|
||||
def paintEvent(self, event):
|
||||
"""重写绘制事件,手动在透明背景上绘制图片"""
|
||||
if not self.bg_pixmap.isNull():
|
||||
painter = QPainter(self)
|
||||
# 绘制背景图(完全覆盖窗口,无间隙)
|
||||
painter.drawPixmap(self.rect(), self.bg_pixmap)
|
||||
# 必须调用父类方法,确保子控件正常绘制
|
||||
super().paintEvent(event)
|
||||
|
||||
"""
|
||||
注意: row表示行号、col表示列号。都是从 0开始, 比如: 0行0列
|
||||
"""
|
||||
|
||||
# ========== 对外接口:设置设备状态 ==========
|
||||
def set_circle_status(self, row, col, status):
|
||||
"""设置指定行列的状态(绿-黄-红) (normal/warning/error)"""
|
||||
box = self.findChild(QWidget, f"box_{row}_{col}")
|
||||
if box and hasattr(box, "circle"):
|
||||
box.circle.setPixmap(box.circle.pixmaps[status])
|
||||
box.circle.status = status
|
||||
|
||||
# ========== 对外接口:获取选中的设备名 ==========
|
||||
def get_selected_device(self, row, col):
|
||||
"""获取指定行列的选中设备名"""
|
||||
box = self.findChild(QWidget, f"box_{row}_{col}")
|
||||
if box and hasattr(box, "dropdown"):
|
||||
return box.dropdown.get_selected_device()
|
||||
return None
|
||||
|
||||
# ========== 对外接口:获取毫秒值 ==========
|
||||
def get_ms_value(self, row, col):
|
||||
"""获取指定行列的毫秒值(如“5ms”)"""
|
||||
box = self.findChild(QWidget, f"box_{row}_{col}")
|
||||
if box and hasattr(box, "ms_edit"):
|
||||
# return box.ms_edit.text()
|
||||
text = box.ms_edit.text().strip()
|
||||
# 用正则提取数字(支持整数/小数,如"5"、"3.8"、"10.2ms")
|
||||
import re
|
||||
|
||||
number_match = re.search(r"(\d+(?:\.\d+)?)", text)
|
||||
if number_match:
|
||||
return number_match.group(1)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
dialog = SystemDiagnosticsDialog()
|
||||
dialog.show()
|
||||
|
||||
# 1. 设置0行0列的状态为“警告”状态
|
||||
dialog.set_circle_status(0, 0, "warning")
|
||||
|
||||
# 2. 获取1行2列的选中设备名
|
||||
device = dialog.get_selected_device(1, 2)
|
||||
print(f"选中设备:{device}")
|
||||
|
||||
# 3. 获取3行1列的毫秒值
|
||||
ms = dialog.get_ms_value(3, 1)
|
||||
print(f"毫秒值:{ms}")
|
||||
sys.exit(app.exec())
|
||||