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 };
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 }
调用代码:
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 }
作者:疯狂Delphi
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
欢迎关注我,一起进步!扫描下方二维码即可加我
浙公网安备 33010602011771号