Qt-自定义控件-区间选择器

原作者:https://www.cnblogs.com/mengxiangdu/p/16870935.html

 

ZRangeSlider.h

 1 #include <QObject>
 2 #include <QWidget>
 3 #include <QPainter>
 4 #include <QMouseEvent>
 5 
 6 struct Range
 7 {
 8     int start;
 9     int end;
10 };
11 
12 class ZRangeSlider : public QWidget
13 {
14     Q_OBJECT
15 
16 public:
17     ZRangeSlider(QWidget* parent = 0);
18     void setLimit(const Range& limit);
19     void setValue(const Range& value);
20     Range value() const;
21 
22 signals:
23     void valueChanged(const Range& value);
24 
25 private:
26     void resizeEvent(QResizeEvent *event) override;
27     void paintEvent(QPaintEvent *event) override;
28     void mousePressEvent(QMouseEvent *event) override;
29     void mouseReleaseEvent(QMouseEvent *event) override;
30     void mouseMoveEvent(QMouseEvent *event) override;
31     QRect toScreenRect(const Range& range, int value);
32     int toValue(const Range& range, const QRect& screen);
33     void updateToolTip();
34     void moveRect(int delta, int minx, int maxx, QRect& rect);
35     int leftLimit() const;
36     int rightLimit() const;
37 
38     enum HitButton
39     {
40         NONE,
41         HIT_MIN,
42         HIT_MAX,
43     };
44 
45 private:
46     const static int radius;
47     const static int lineWidth;
48     int hitTest;
49     QPoint lastPos;
50     Range ivalue;
51     Range limitRange;
52     QRect minr;
53     QRect maxr;
54 };
View Code

ZRangeSlider.cpp

  1 #include "ZRangeSlider.h"
  2 
  3 inline bool operator==(const Range& a, const Range& b)
  4 {
  5     return a.start == b.start && a.end == b.end;
  6 }
  7 
  8 inline bool operator!=(const Range& a, const Range& b)
  9 {
 10     return !(a == b);
 11 }
 12 
 13 /////////////////////////////////////////////////////////////////////////////////////////
 14 
 15 const int ZRangeSlider::radius = 6;
 16 const int ZRangeSlider::lineWidth = 5;
 17 
 18 ZRangeSlider::ZRangeSlider(QWidget* parent) :
 19     QWidget(parent), hitTest(NONE)
 20 {
 21     limitRange = { 0, 0 };
 22     ivalue = { 0, 0 };
 23 }
 24 
 25 inline int ZRangeSlider::leftLimit() const
 26 {
 27     return radius;
 28 }
 29 
 30 inline int ZRangeSlider::rightLimit() const
 31 {
 32     /* 控件右侧多减2像素,要不然绘制圆形时会出界 */
 33     return width() - radius - 2;
 34 }
 35 
 36 #define LIMIT(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
 37 
 38 void ZRangeSlider::setLimit(const Range& limit)
 39 {
 40     Q_ASSERT(limit.end >= limit.start);
 41     limitRange = limit;
 42     Range limited;
 43     limited.start = LIMIT(ivalue.start, limitRange.start, limitRange.end);
 44     limited.end = LIMIT(ivalue.end, limitRange.start, limitRange.end);
 45     minr = toScreenRect(limitRange, limited.start);
 46     maxr = toScreenRect(limitRange, limited.end);
 47     if (limited != ivalue)
 48     {
 49         ivalue = limited;
 50         updateToolTip();
 51         emit valueChanged(ivalue);
 52     }
 53     update();
 54 }
 55 
 56 void ZRangeSlider::setValue(const Range& value)
 57 {
 58     Q_ASSERT(value.end >= value.start);
 59     Range limited;
 60     limited.start = LIMIT(value.start, limitRange.start, limitRange.end);
 61     limited.end = LIMIT(value.end, limitRange.start, limitRange.end);
 62     if (limited != ivalue)
 63     {
 64         minr = toScreenRect(limitRange, limited.start);
 65         maxr = toScreenRect(limitRange, limited.end);
 66         ivalue = limited;
 67         updateToolTip();
 68         emit valueChanged(ivalue);
 69         update();
 70     }
 71 }
 72 
 73 #undef LIMIT
 74 
 75 Range ZRangeSlider::value() const
 76 {
 77     return ivalue;
 78 }
 79 
 80 void ZRangeSlider::updateToolTip()
 81 {
 82     setToolTip(QString(u8"{%1,%2}"). arg(ivalue. start).arg(ivalue. end));
 83 }
 84 
 85 QRect ZRangeSlider::toScreenRect(const Range& range, int value)
 86 {
 87     int ctll = leftLimit();
 88     int ctlr = rightLimit();
 89     int pos = ctll;
 90     if (range.end > range.start)
 91     {
 92         pos += (ctlr - ctll) * (value - range.start) / (range.end - range.start);
 93     }
 94     QRect rect(0, 0, 2 * radius, 2 * radius);
 95     /* 用moveCenter()主要为确保矩形中心在pos上 */
 96     rect.moveCenter(QPoint(pos, height() / 2 - 1));
 97     return rect;
 98 }
 99 
100 int ZRangeSlider::toValue(const Range& range, const QRect& screen)
101 {
102     int ctll = leftLimit();
103     int ctlr = rightLimit();
104     int x = range.start;
105     if (ctlr > ctll)
106     {
107         x += (range.end - range.start) * (screen.center().x() - ctll) / (ctlr - ctll);
108     }
109     return x;
110 }
111 
112 void ZRangeSlider::moveRect(int delta, int minx, int maxx, QRect& rect)
113 {
114     int cx = rect.center().x();
115     if (delta < minx - cx)
116     {
117         delta = minx - cx;
118     }
119     else if (delta > maxx - cx)
120     {
121         delta = maxx - cx;
122     }
123     rect.adjust(delta, 0, delta, 0);
124 }
125 
126 void ZRangeSlider::resizeEvent(QResizeEvent *)
127 {
128     minr = toScreenRect(limitRange, ivalue.start);
129     maxr = toScreenRect(limitRange, ivalue.end);
130 }
131 
132 void ZRangeSlider::paintEvent(QPaintEvent *)
133 {
134     QPainter painter(this);
135     painter.setRenderHint(QPainter::Antialiasing);
136     QLine bkLine(radius, height() / 2, width() - radius, height() / 2);
137     painter.setPen(QPen(QColor(173, 173, 173), lineWidth, Qt::SolidLine, Qt::RoundCap));
138     painter.drawLine(bkLine);
139     QLine valueLine(minr.center().x(), height() / 2, maxr.center().x(), height() / 2);
140     painter.setPen(QPen(QColor(243, 173, 173), lineWidth, Qt::SolidLine, Qt::RoundCap));
141     painter.drawLine(valueLine);
142     painter.setPen(QColor(173, 63, 63));
143     painter.setBrush(QColor(243, 32, 32));
144     painter.drawEllipse(minr);
145     painter.drawEllipse(maxr);
146 }
147 
148 void ZRangeSlider::mousePressEvent(QMouseEvent *event)
149 {
150     QPoint p = event->pos();
151     lastPos = p;
152     if (minr.contains(p))
153     {
154         hitTest |= int(HIT_MIN);
155     }
156     if (maxr.contains(p))
157     {
158         hitTest |= int(HIT_MAX);
159     }
160     if (hitTest == (HIT_MIN | HIT_MAX))
161     {
162         int maxx = maxr.center().x();
163         int minx = minr.center().x();
164         hitTest = (maxx + minx > width() ? HIT_MIN : HIT_MAX);
165     }
166 }
167 
168 void ZRangeSlider::mouseReleaseEvent(QMouseEvent *)
169 {
170     if (hitTest != NONE)
171     {
172         hitTest = NONE;
173         emit valueChanged(ivalue);
174     }
175 }
176 
177 void ZRangeSlider::mouseMoveEvent(QMouseEvent *event)
178 {
179 
180     int delta = event->pos().x() - lastPos.x();
181     switch (hitTest)
182     {
183     case HIT_MIN:
184         moveRect(delta, leftLimit(), maxr.center().x(), minr);
185         ivalue.start = toValue(limitRange, minr);
186         updateToolTip();
187         lastPos = event->pos();
188         update();
189         break;
190     case HIT_MAX:
191         moveRect(delta, minr.center().x(), rightLimit(), maxr);
192         ivalue.end = toValue(limitRange, maxr);
193         updateToolTip();
194         lastPos = event->pos();
195         update();
196         break;
197     default: /* nothing to do. */
198         break;
199     }
200 }
View Code

调用代码:

 1       ZRangeSlider *oMRangeSlider = new ZRangeSlider(this);
 2       oMRangeSlider->move(100, 100);
 3       oMRangeSlider->resize(500, 20);
 4       Range oRange;
 5       oRange.start = 0;
 6       oRange.end = 100;
 7       oMRangeSlider->setLimit(oRange);
 8 
 9       Range oRange2;
10       oRange2.start = 20;
11       oRange2.end = 40;
12       oMRangeSlider->setValue(oRange2);
13 
14       connect(oMRangeSlider, &ZRangeSlider::valueChanged, this, &MainWindow::on_Range);
15 
16 
17 void MainWindow::on_Range(Range aValue)
18 {
19     QString sValue = "%1   %2";
20     sValue = sValue.arg(aValue.start).arg(aValue.end);
21     this->setWindowTitle(sValue);
22 }
View Code

 

posted on 2026-07-22 17:42  疯狂delphi  阅读(0)  评论(0)    收藏  举报

导航