139 lines
4.8 KiB
Python
139 lines
4.8 KiB
Python
from PySide6.QtWidgets import QWidget
|
|
from PySide6.QtCore import Qt, QRectF
|
|
from PySide6.QtGui import QPainter, QColor, QPen, QFont, QBrush, QPainterPath
|
|
|
|
class SpeedometerWidget(QWidget):
|
|
def __init__(self, title="SPEED", unit="km/h", max_value=120, parent=None):
|
|
super().__init__(parent)
|
|
self.title = title
|
|
self.unit = unit
|
|
self.max_value = max_value
|
|
self.current_value = 0.0
|
|
self.limit_value = 0.0
|
|
self.atc_code = 0 # ATC CODE 추가
|
|
self.setMinimumSize(120, 120)
|
|
|
|
def set_value(self, value):
|
|
try:
|
|
self.current_value = float(value)
|
|
except ValueError:
|
|
self.current_value = 0.0
|
|
self.update()
|
|
|
|
def set_limit(self, limit):
|
|
try:
|
|
self.limit_value = float(limit)
|
|
except ValueError:
|
|
self.limit_value = 0.0
|
|
self.update()
|
|
|
|
def set_atc_code(self, code):
|
|
"""ATC CODE 설정"""
|
|
try:
|
|
self.atc_code = int(code)
|
|
except (ValueError, TypeError):
|
|
self.atc_code = 0
|
|
self.update()
|
|
|
|
def paintEvent(self, event):
|
|
painter = QPainter(self)
|
|
painter.setRenderHint(QPainter.Antialiasing)
|
|
|
|
width = self.width()
|
|
height = self.height()
|
|
side = min(width, height)
|
|
|
|
# 중앙 정렬
|
|
painter.translate(width / 2, height / 2)
|
|
painter.scale(side / 200.0, side / 200.0)
|
|
|
|
# 배경 (어두운 원)
|
|
painter.setPen(Qt.NoPen)
|
|
painter.setBrush(QColor(30, 30, 30))
|
|
painter.drawEllipse(-100, -100, 200, 200)
|
|
|
|
# 눈금 그리기 (Start: 135도, Span: 270도)
|
|
start_angle = 135 * 16
|
|
span_angle = -270 * 16
|
|
|
|
# 게이지 배경 (회색 아크)
|
|
pen = QPen(QColor(60, 60, 60))
|
|
pen.setWidth(15)
|
|
pen.setCapStyle(Qt.FlatCap)
|
|
painter.setPen(pen)
|
|
painter.drawArc(-80, -80, 160, 160, start_angle, span_angle)
|
|
|
|
# 현재 속도 아크 (녹색/노란색/빨간색)
|
|
if self.current_value > self.limit_value and self.limit_value > 0:
|
|
color = QColor(255, 82, 82) # 초과 시 빨강
|
|
elif self.current_value > 0:
|
|
color = QColor(0, 208, 132) # 평소 녹색
|
|
else:
|
|
color = QColor(60, 60, 60)
|
|
|
|
if self.current_value > 0:
|
|
val_ratio = min(self.current_value / self.max_value, 1.0)
|
|
val_span = int(span_angle * val_ratio)
|
|
|
|
pen.setColor(color)
|
|
painter.setPen(pen)
|
|
painter.drawArc(-80, -80, 160, 160, start_angle, val_span)
|
|
|
|
# 제한 속도 표시 (작은 마커)
|
|
if self.limit_value > 0:
|
|
limit_ratio = min(self.limit_value / self.max_value, 1.0)
|
|
limit_angle = 135 + (270 * limit_ratio)
|
|
|
|
painter.save()
|
|
painter.rotate(limit_angle)
|
|
painter.setPen(Qt.NoPen)
|
|
painter.setBrush(QColor(255, 165, 0)) # 주황색 마커
|
|
painter.drawRect(-2, -95, 4, 10) # 눈금 위치에 마커
|
|
painter.restore()
|
|
|
|
# ATC CODE 바늘 및 동그라미 표시
|
|
if self.atc_code > 0:
|
|
# ATC CODE에 해당하는 각도 계산 (0~max_value 범위)
|
|
atc_ratio = min(self.atc_code / self.max_value, 1.0)
|
|
atc_angle = 135 + (270 * atc_ratio)
|
|
|
|
painter.save()
|
|
painter.rotate(atc_angle)
|
|
|
|
# 빨간 바늘 (외부에서 내부로)
|
|
pen = QPen(QColor(255, 50, 50))
|
|
pen.setWidth(3)
|
|
painter.setPen(pen)
|
|
painter.drawLine(0, -95, 0, -70) # 외부(-95)에서 내부(-70)로
|
|
|
|
# 바늘 외부에 동그라미
|
|
painter.setPen(Qt.NoPen)
|
|
painter.setBrush(QColor(255, 50, 50))
|
|
painter.drawEllipse(-8, -110, 16, 16) # 바늘 외부에 원
|
|
|
|
# 동그라미 안에 ATC CODE 텍스트
|
|
painter.setPen(QColor(255, 255, 255))
|
|
font = QFont("Arial", 8, QFont.Bold)
|
|
painter.setFont(font)
|
|
painter.drawText(QRectF(-8, -110, 16, 16), Qt.AlignCenter, str(self.atc_code))
|
|
|
|
painter.restore()
|
|
|
|
# 텍스트 표시
|
|
painter.setPen(QColor(255, 255, 255))
|
|
|
|
# 현재 값 (큰 글씨)
|
|
font = QFont("Arial", 28, QFont.Bold)
|
|
painter.setFont(font)
|
|
painter.drawText(QRectF(-100, -20, 200, 40), Qt.AlignCenter, f"{self.current_value:.1f}")
|
|
|
|
# 단위 (작은 글씨)
|
|
font.setPointSize(10)
|
|
painter.setFont(font)
|
|
painter.drawText(QRectF(-100, 20, 200, 20), Qt.AlignCenter, self.unit)
|
|
|
|
# 타이틀 (상단)
|
|
font.setPointSize(12)
|
|
painter.setFont(font)
|
|
painter.setPen(QColor(180, 180, 180))
|
|
painter.drawText(QRectF(-100, -70, 200, 20), Qt.AlignCenter, self.title) |