| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  | #include "rangeslider.h"
 | 
					
						
							|  |  |  | #include <QPainter>
 | 
					
						
							|  |  |  | #include <QMouseEvent>
 | 
					
						
							|  |  |  | #include <QDebug>
 | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  | RangeSlider::RangeSlider(int style_,QWidget *parent) | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  |     : QWidget(parent) { | 
					
						
							|  |  |  |     setMinimumSize(20, 240); | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  |     style = style_; | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-06 16:31:13 +08:00
										 |  |  | void RangeSlider::setRange(float min, float max) { | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  |     m_min = min; | 
					
						
							|  |  |  |     m_max = max; | 
					
						
							|  |  |  |     m_lower = qBound(m_min, m_lower, m_max); | 
					
						
							|  |  |  |     m_upper = qBound(m_lower, m_upper, m_max); | 
					
						
							|  |  |  |     update(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RangeSlider::setSliderWidth(int width) { | 
					
						
							|  |  |  |     sliderWidth = width; | 
					
						
							|  |  |  |     update();  // 更新界面
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float RangeSlider::lowerValue() const { return m_lower; } | 
					
						
							|  |  |  | float RangeSlider::upperValue() const { return m_upper; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float RangeSlider::valueToY(float value) const { | 
					
						
							|  |  |  |     double ratio = (value - m_min) / double(m_max - m_min); | 
					
						
							|  |  |  |     return height() - handleRadius - ratio * (height() - 2 * handleRadius); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float RangeSlider::yToValue(float y) const { | 
					
						
							|  |  |  |    double ratio = (height() - handleRadius - y) / double(height() - 2 * handleRadius); | 
					
						
							|  |  |  |    ratio = qBound(0.0, ratio, 1.0); | 
					
						
							|  |  |  |    float rawValue = m_min + ratio * (m_max - m_min); | 
					
						
							|  |  |  |    float steppedValue = qRound(rawValue * 10) / 10.0f; | 
					
						
							|  |  |  |    return qBound(m_min, steppedValue, m_max); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RangeSlider::HandleType RangeSlider::handleHitTest(float y) const { | 
					
						
							|  |  |  |     int yLower = valueToY(m_lower); | 
					
						
							|  |  |  |     int yUpper = valueToY(m_upper); | 
					
						
							|  |  |  |     if (qAbs(y - yLower) <= handleRadius + 2) return LowerHandle; | 
					
						
							|  |  |  |     if (qAbs(y - yUpper) <= handleRadius + 2) return UpperHandle; | 
					
						
							|  |  |  |     return NoHandle; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RangeSlider::mousePressEvent(QMouseEvent *event) { | 
					
						
							|  |  |  |     currentHandle = handleHitTest(event->pos().y()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RangeSlider::mouseMoveEvent(QMouseEvent *event) { | 
					
						
							|  |  |  |     if (currentHandle == NoHandle) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     float val = yToValue(event->pos().y()); | 
					
						
							|  |  |  |     if (currentHandle == LowerHandle) { | 
					
						
							|  |  |  |         m_lower = qBound(m_min, val, m_upper); | 
					
						
							|  |  |  |     } else if (currentHandle == UpperHandle) { | 
					
						
							|  |  |  |         m_upper = qBound(m_lower, val, m_max); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     update(); | 
					
						
							|  |  |  |     emit rangeChanged(m_lower, m_upper); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RangeSlider::mouseReleaseEvent(QMouseEvent *) { | 
					
						
							|  |  |  |     currentHandle = NoHandle; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RangeSlider::paintEvent(QPaintEvent *) { | 
					
						
							|  |  |  |     QPainter p(this); | 
					
						
							|  |  |  |     p.setRenderHint(QPainter::Antialiasing); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int x = width() / 2; | 
					
						
							|  |  |  |     int yLower = valueToY(m_lower); | 
					
						
							|  |  |  |     int yUpper = valueToY(m_upper); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Draw Temperature-style background (gradient)
 | 
					
						
							|  |  |  |     drawTemperatureStyle(&p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Draw selected range (green)
 | 
					
						
							|  |  |  |     // Draw selected range (green)
 | 
					
						
							|  |  |  |     p.setPen(Qt::NoPen); | 
					
						
							|  |  |  |     p.setBrush(Qt::green); | 
					
						
							|  |  |  |     p.drawRect(x - sliderWidth / 2, yUpper, sliderWidth, yLower - yUpper); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  |     // Draw simple black handles (lines)
 | 
					
						
							|  |  |  |     p.setPen(QPen(Qt::black, 2)); | 
					
						
							|  |  |  |     p.drawLine(x - sliderWidth / 2, yLower, x + sliderWidth, yLower); | 
					
						
							|  |  |  |     p.drawLine(x - sliderWidth / 2, yUpper, x + sliderWidth, yUpper); | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Draw ticks
 | 
					
						
							|  |  |  |     drawTicks(&p); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void RangeSlider::setLowerValue(float val) { | 
					
						
							|  |  |  |     m_lower = qBound(m_min, val, m_upper); | 
					
						
							|  |  |  |     update(); | 
					
						
							|  |  |  |     emit rangeChanged(m_lower, m_upper); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RangeSlider::setUpperValue(float val) { | 
					
						
							|  |  |  |     m_upper = qBound(m_lower, val, m_max); | 
					
						
							|  |  |  |     update(); | 
					
						
							|  |  |  |     emit rangeChanged(m_lower, m_upper); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void RangeSlider::drawTemperatureStyle(QPainter *p) { | 
					
						
							|  |  |  |     int x = width() / 2; | 
					
						
							|  |  |  |     int yTop = handleRadius; | 
					
						
							|  |  |  |     int yBottom = height() - handleRadius; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Draw border (black)
 | 
					
						
							|  |  |  |     p->setPen(Qt::black); | 
					
						
							|  |  |  |     p->setBrush(Qt::NoBrush); | 
					
						
							|  |  |  |     p->drawRect(x - sliderWidth / 2, yTop, sliderWidth, yBottom - yTop); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Draw yellow outside the range
 | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  |     if(style != 0){ | 
					
						
							|  |  |  |         p->setBrush(Qt::red); | 
					
						
							|  |  |  |         p->drawRect(x - sliderWidth / 2, yTop, sliderWidth, valueToY(m_lower) - yTop);  // Above lower range
 | 
					
						
							|  |  |  |         p->drawRect(x - sliderWidth / 2, valueToY(m_upper), sliderWidth, yBottom - valueToY(m_upper));  // Below upper range
 | 
					
						
							|  |  |  |     }else{ | 
					
						
							|  |  |  |         p->setBrush(Qt::yellow); | 
					
						
							|  |  |  |         p->drawRect(x - sliderWidth / 2, yTop, sliderWidth, valueToY(m_lower) - yTop);  // Above lower range
 | 
					
						
							|  |  |  |         p->drawRect(x - sliderWidth / 2, valueToY(m_upper), sliderWidth, yBottom - valueToY(m_upper));  // Below upper range
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Draw green inside the range
 | 
					
						
							|  |  |  |     p->setBrush(Qt::green); | 
					
						
							|  |  |  |     p->drawRect(x - sliderWidth / 2, valueToY(m_upper), sliderWidth, valueToY(m_lower) - valueToY(m_upper));  // Green area
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  | int RangeSlider::niceStep(int range, int maxLabels) { | 
					
						
							|  |  |  |     double rawStep = static_cast<double>(range) / maxLabels; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 取一个"好看"的步长
 | 
					
						
							|  |  |  |     double magnitude = pow(10, floor(log10(rawStep)));     // 10 的整数次幂
 | 
					
						
							|  |  |  |     double residual = rawStep / magnitude; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     double niceResidual; | 
					
						
							|  |  |  |     if (residual < 1.5) | 
					
						
							|  |  |  |         niceResidual = 1; | 
					
						
							|  |  |  |     else if (residual < 3) | 
					
						
							|  |  |  |         niceResidual = 2; | 
					
						
							|  |  |  |     else if (residual < 7) | 
					
						
							|  |  |  |         niceResidual = 5; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         niceResidual = 10; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return static_cast<int>(niceResidual * magnitude); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  | void RangeSlider::drawTicks(QPainter *p) { | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  |     int range = m_max - m_min; | 
					
						
							|  |  |  |     int labelStep = niceStep(range, 10); | 
					
						
							|  |  |  |     int minorStep = qMax(1, labelStep / 5); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  |     int x = width() / 2 + handleRadius + 4; | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  |     p->setFont(QFont("Arial", 8)); | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  |     for (int val = m_min; val <= m_max; val += minorStep) { | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  |         int y = valueToY(val); | 
					
						
							| 
									
										
										
										
											2025-04-19 16:25:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (val % labelStep == 0) { | 
					
						
							|  |  |  |             p->setPen(QPen(Qt::black, 1.5));  // 主刻度
 | 
					
						
							|  |  |  |             p->drawLine(x, y, x + 6, y); | 
					
						
							|  |  |  |             p->drawText(x + 10, y + 4, QString::number(val)); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             p->setPen(QPen(Qt::gray, 1));     // 次刻度
 | 
					
						
							|  |  |  |             p->drawLine(x, y, x + 3, y); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-04-17 14:06:21 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | } |