Files
Feeding_control_system/view/widgets/arrow_combo_box.py

177 lines
6.0 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.

# -*- coding: utf-8 -*-
"""
ArrowComboBox - 带动态箭头的下拉框组件
展开时箭头向上,收起时箭头向下
"""
import os
import re
import tempfile
from PySide6.QtWidgets import QComboBox
from PySide6.QtGui import QPixmap, QPainter, QTransform, QPolygonF
from PySide6.QtCore import Qt, Signal, QTimer, QPointF
from utils.image_paths import ImagePaths
class ArrowComboBox(QComboBox):
"""带动态箭头的下拉框,展开时箭头向上,收起时箭头向下
Signals:
popupShown: 下拉列表展开时发出
popupHidden: 下拉列表收起时发出
arrowDirectionChanged: 箭头方向改变时发出 (is_up: bool)
"""
# 信号定义
popupShown = Signal() # 下拉列表展开
popupHidden = Signal() # 下拉列表收起
arrowDirectionChanged = Signal(bool) # 箭头方向改变 (True=向上, False=向下)
# 类缓存
_arrow_down_path = None # 向下箭头图片路径
_arrow_up_path = None # 向上箭头图片路径
_initialized = False # 是否已初始化
@classmethod
def init_arrow_resources(cls, arrow_image_path: str = None, arrow_size: tuple = (14, 8)):
"""初始化箭头资源(类方法,只需调用一次)
Args:
arrow_image_path: 自定义箭头图片路径,默认使用 ImagePaths.SYSTEM_DIAGNOSTICS_DROPDOWN_ARROW
arrow_size: 箭头尺寸 (width, height),默认 (14, 8)
"""
if cls._initialized:
return
arrow_width, arrow_height = arrow_size
# 加载原始箭头图片
if arrow_image_path is None:
arrow_image_path = ImagePaths.SYSTEM_DIAGNOSTICS_DROPDOWN_ARROW
original = QPixmap(arrow_image_path)
if original.isNull():
# 如果加载失败,创建默认箭头
original = QPixmap(arrow_width, arrow_height)
original.fill(Qt.transparent)
painter = QPainter(original)
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.white)
points = [
QPointF(1, 1),
QPointF(arrow_width - 1, 1),
QPointF(arrow_width / 2, arrow_height - 1)
]
painter.drawPolygon(QPolygonF(points))
painter.end()
down_pixmap = original.scaled(arrow_width, arrow_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
# 垂直翻转得到向上箭头
transform = QTransform()
transform.scale(1, -1)
up_pixmap = down_pixmap.transformed(transform)
# 保存到临时文件
temp_dir = tempfile.gettempdir()
cls._arrow_down_path = os.path.join(temp_dir, "arrow_down.png").replace("\\", "/")
cls._arrow_up_path = os.path.join(temp_dir, "arrow_up.png").replace("\\", "/")
down_pixmap.save(cls._arrow_down_path, "PNG")
up_pixmap.save(cls._arrow_up_path, "PNG")
cls._initialized = True
@classmethod
def get_arrow_paths(cls):
"""获取箭头图片路径
Returns:
tuple: (向下箭头路径, 向上箭头路径)
"""
return cls._arrow_down_path, cls._arrow_up_path
def __init__(self, parent=None):
super().__init__(parent)
ArrowComboBox.init_arrow_resources()
self._is_open = False
self._updating_style = False
self._arrow_size = (14, 8) # 默认箭头尺寸
# 延迟初始化箭头(等待样式设置后)
QTimer.singleShot(0, self._update_arrow_style)
@property
def isPopupOpen(self) -> bool:
"""返回下拉列表是否打开"""
return self._is_open
@property
def arrowDirection(self) -> str:
"""返回当前箭头方向 ('up''down')"""
return 'up' if self._is_open else 'down'
def setArrowSize(self, width: int, height: int):
"""设置箭头尺寸
Args:
width: 箭头宽度
height: 箭头高度
"""
self._arrow_size = (width, height)
self._update_arrow_style()
def setArrowDirection(self, is_up: bool):
"""手动设置箭头方向
Args:
is_up: True 为向上False 为向下
"""
if self._is_open != is_up:
self._is_open = is_up
self._update_arrow_style()
self.arrowDirectionChanged.emit(is_up)
def showPopup(self):
"""展开下拉列表时切换为向上箭头"""
super().showPopup()
self._is_open = True
self._update_arrow_style()
self.popupShown.emit()
self.arrowDirectionChanged.emit(True)
def hidePopup(self):
"""收起下拉列表时切换为向下箭头"""
super().hidePopup()
self._is_open = False
self._update_arrow_style()
self.popupHidden.emit()
self.arrowDirectionChanged.emit(False)
def togglePopup(self):
"""切换下拉列表的展开/收起状态"""
if self._is_open:
self.hidePopup()
else:
self.showPopup()
def refreshArrowStyle(self):
"""刷新箭头样式(外部调用)"""
self._update_arrow_style()
def _update_arrow_style(self):
"""更新箭头样式(内部方法)"""
if self._updating_style:
return
self._updating_style = True
try:
arrow_path = self._arrow_up_path if self._is_open else self._arrow_down_path
arrow_width, arrow_height = self._arrow_size
style = self.styleSheet()
# 移除旧的箭头样式
style = re.sub(r'QComboBox::down-arrow\s*\{[^}]*\}', '', style)
style += f"""QComboBox::down-arrow {{ image: url({arrow_path}); width: {arrow_width}px; height: {arrow_height}px; }}"""
super().setStyleSheet(style)
finally:
self._updating_style = False