柱狀溫度計控件,多是不少人練手控件之一,基本上都是垂直方向展現,底部一個水銀柱,中間刻度尺,刻度尺能夠在左側右側或者兩側都有,自適應分辨率改動,有時候爲了美觀效果,可能還會整個定時器來實現動畫效果,開啓動畫效果的缺點就是CPU佔用會比較高,前陣子有個好友(賈文濤-濤哥)向我推薦了一個opengl繪製的開源東西,QNanoPainter,東西是個好東西,我我的的理解是直接封裝了opengl繪製的qpainter,可使得繪製所有走GPU,這樣就能夠大大減輕CPU的負擔,很是方便,我本身試了下,方法和繪製邏輯和qpainter有點不同,暫時沒有將全部控件改爲QNanoPainter版本,之後看狀況吧。c++
#ifndef RULERTEMP_H #define RULERTEMP_H /** * 柱狀溫度計控件 做者:feiyangqingyun(QQ:517216493) 2016-11-4 * 1:可設置精確度(小數點後幾位)和間距 * 2:可設置背景色/柱狀顏色/線條顏色 * 3:可設置長線條步長及短線條步長 * 4:可啓用動畫及動畫步長 * 5:可設置範圍值 * 6:支持負數刻度值 * 7:支持任意窗體大小縮放 * 8:可設置柱狀條位置 左側 居中 右側 * 9:可設置刻度尺位置 無 左側 右側 兩側 * 10:可設置用戶設定目標值 */ #include <QWidget> #ifdef quc #if (QT_VERSION < QT_VERSION_CHECK(5,7,0)) #include <QtDesigner/QDesignerExportWidget> #else #include <QtUiPlugin/QDesignerExportWidget> #endif class QDESIGNER_WIDGET_EXPORT RulerTemp : public QWidget #else class RulerTemp : public QWidget #endif { Q_OBJECT Q_ENUMS(BarPosition) Q_ENUMS(TickPosition) Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue) Q_PROPERTY(double maxValue READ getMaxValue WRITE setMaxValue) Q_PROPERTY(double value READ getValue WRITE setValue) Q_PROPERTY(int precision READ getPrecision WRITE setPrecision) Q_PROPERTY(int longStep READ getLongStep WRITE setLongStep) Q_PROPERTY(int shortStep READ getShortStep WRITE setShortStep) Q_PROPERTY(int space READ getSpace WRITE setSpace) Q_PROPERTY(bool animation READ getAnimation WRITE setAnimation) Q_PROPERTY(double animationStep READ getAnimationStep WRITE setAnimationStep) Q_PROPERTY(bool showUserValue READ getShowUserValue WRITE setShowUserValue) Q_PROPERTY(double userValue READ getUserValue WRITE setUserValue) Q_PROPERTY(QColor userValueColor READ getUserValueColor WRITE setUserValueColor) Q_PROPERTY(QColor bgColorStart READ getBgColorStart WRITE setBgColorStart) Q_PROPERTY(QColor bgColorEnd READ getBgColorEnd WRITE setBgColorEnd) Q_PROPERTY(QColor lineColor READ getLineColor WRITE setLineColor) Q_PROPERTY(QColor barBgColor READ getBarBgColor WRITE setBarBgColor) Q_PROPERTY(QColor barColor READ getBarColor WRITE setBarColor) Q_PROPERTY(BarPosition barPosition READ getBarPosition WRITE setBarPosition) Q_PROPERTY(TickPosition tickPosition READ getTickPosition WRITE setTickPosition) public: enum BarPosition { BarPosition_Left = 0, //左側顯示 BarPosition_Right = 1, //右側顯示 BarPosition_Center = 2 //居中顯示 }; enum TickPosition { TickPosition_Null = 0, //不顯示 TickPosition_Left = 1, //左側顯示 TickPosition_Right = 2, //右側顯示 TickPosition_Both = 3 //兩側顯示 }; explicit RulerTemp(QWidget *parent = 0); ~RulerTemp(); protected: void resizeEvent(QResizeEvent *); void paintEvent(QPaintEvent *); void drawBg(QPainter *painter); void drawBarBg(QPainter *painter); void drawRuler(QPainter *painter, int type); void drawBar(QPainter *painter); void drawValue(QPainter *painter); private: double minValue; //最小值 double maxValue; //最大值 double value; //目標值 int precision; //精確度,小數點後幾位 int longStep; //長線條等分步長 int shortStep; //短線條等分步長 int space; //間距 bool animation; //是否啓用動畫顯示 double animationStep; //動畫顯示時步長 bool showUserValue; //顯示用戶設定值 double userValue; //用戶設定值 QColor userValueColor; //用戶設定值顏色 QColor bgColorStart; //背景漸變開始顏色 QColor bgColorEnd; //背景漸變結束顏色 QColor lineColor; //線條顏色 QColor barBgColor; //柱狀背景色 QColor barColor; //柱狀顏色 BarPosition barPosition; //柱狀條位置 TickPosition tickPosition; //刻度尺位置 int barWidth; //水銀柱寬度 int barHeight; //水銀柱高度 int radius; //水銀柱底部圓半徑 int targetX; //目標X座標 QRectF barRect; //柱狀區域 QRectF circleRect; //底部圓區域 bool reverse; //是否倒退 double currentValue; //當前值 QTimer *timer; //定時器繪製動畫 private slots: void updateValue(); public: double getMinValue() const; double getMaxValue() const; double getValue() const; int getPrecision() const; int getLongStep() const; int getShortStep() const; int getSpace() const; bool getAnimation() const; double getAnimationStep() const; bool getShowUserValue() const; double getUserValue() const; QColor getUserValueColor() const; QColor getBgColorStart() const; QColor getBgColorEnd() const; QColor getLineColor() const; QColor getBarBgColor() const; QColor getBarColor() const; BarPosition getBarPosition() const; TickPosition getTickPosition() const; QSize sizeHint() const; QSize minimumSizeHint() const; public Q_SLOTS: //設置最大最小值-範圍值 void setRange(double minValue, double maxValue); void setRange(int minValue, int maxValue); //設置最大最小值 void setMinValue(double minValue); void setMaxValue(double maxValue); //設置目標值 void setValue(double value); void setValue(int value); //設置精確度 void setPrecision(int precision); //設置線條等分步長 void setLongStep(int longStep); void setShortStep(int shortStep); //設置間距 void setSpace(int space); //設置是否啓用動畫顯示 void setAnimation(bool animation); //設置動畫顯示的步長 void setAnimationStep(double animationStep); //設置是否顯示用戶設定值 void setShowUserValue(bool showUserValue); //設置用戶值 void setUserValue(double userValue); void setUserValue(int userValue); //設置用戶設定值顏色 void setUserValueColor(const QColor &userValueColor); //設置背景顏色 void setBgColorStart(const QColor &bgColorStart); void setBgColorEnd(const QColor &bgColorEnd); //設置線條顏色 void setLineColor(const QColor &lineColor); //設置柱狀顏色 void setBarBgColor(const QColor &barBgColor); void setBarColor(const QColor &barColor); //設置柱狀條位置 void setBarPosition(const BarPosition &barPosition); //設置刻度尺位置 void setTickPosition(const TickPosition &tickPosition); Q_SIGNALS: void valueChanged(double value); }; #endif // RULERTEMP_H
void RulerTemp::paintEvent(QPaintEvent *) { //繪製準備工做,啓用反鋸齒 QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); //繪製背景 drawBg(&painter); //繪製標尺及刻度尺 if (tickPosition == TickPosition_Left) { drawRuler(&painter, 0); } else if (tickPosition == TickPosition_Right) { drawRuler(&painter, 1); } else if (tickPosition == TickPosition_Both) { drawRuler(&painter, 0); drawRuler(&painter, 1); } //繪製水銀柱背景,包含水銀柱底部圓 drawBarBg(&painter); //繪製當前水銀柱,包含水銀柱底部圓 drawBar(&painter); //繪製當前值 drawValue(&painter); } void RulerTemp::drawBg(QPainter *painter) { painter->save(); painter->setPen(Qt::NoPen); QLinearGradient bgGradient(QPointF(0, 0), QPointF(0, height())); bgGradient.setColorAt(0.0, bgColorStart); bgGradient.setColorAt(1.0, bgColorEnd); painter->setBrush(bgGradient); painter->drawRect(rect()); painter->restore(); } void RulerTemp::drawBarBg(QPainter *painter) { painter->save(); painter->setPen(Qt::NoPen); painter->setBrush(barBgColor); int barX = targetX - barWidth / 2; int barY = space; QRectF barRect(barX, barY, barWidth, barHeight); int circleX = targetX - radius; //偏移 2 個像素,使得看起來邊緣完整 int circleY = height() - radius * 2 - 2; int circleWidth = radius * 2; QRectF circleRect(circleX, circleY, circleWidth, circleWidth); QPainterPath path; path.addRect(barRect); path.addEllipse(circleRect); path.setFillRule(Qt::WindingFill); painter->drawPath(path); painter->restore(); } void RulerTemp::drawRuler(QPainter *painter, int type) { painter->save(); painter->setPen(lineColor); int barPercent = barWidth / 8; if (barPercent < 2) { barPercent = 2; } //繪製縱向標尺刻度 double length = height() - 2 * space - 2 * radius; //計算每一格移動多少 double increment = length / (maxValue - minValue); //長線條短線條長度 int longLineLen = 10; int shortLineLen = 7; //繪製縱向標尺線 偏移 5 像素 int offset = barWidth / 2 + 5; //左側刻度尺須要從新計算 if (type == 0) { offset = -offset; longLineLen = -longLineLen; shortLineLen = -shortLineLen; } double initX = targetX + offset; double initY = space + barPercent; QPointF topPot(initX, initY); QPointF bottomPot(initX, height() - 2 * radius - 5); painter->drawLine(topPot, bottomPot); //根據範圍值繪製刻度值及刻度值 for (int i = maxValue; i >= minValue; i = i - shortStep) { if (i % longStep == 0) { //繪製長線條 QPointF leftPot(initX + longLineLen, initY); QPointF rightPot(initX, initY); painter->drawLine(leftPot, rightPot); //繪製文字 QString strValue = QString("%1").arg((double)i, 0, 'f', precision); double fontHeight = painter->fontMetrics().height(); if (type == 0) { QRect textRect(initX - 45, initY - fontHeight / 3, 30, 15); painter->drawText(textRect, Qt::AlignRight, strValue); } else if (type == 1) { QRect textRect(initX + longLineLen + 5, initY - fontHeight / 3, 30, 15); painter->drawText(textRect, Qt::AlignLeft, strValue); } } else { //繪製短線條 QPointF leftPot(initX + shortLineLen, initY); QPointF rightPot(initX, initY); painter->drawLine(leftPot, rightPot); } initY += increment * shortStep; } painter->restore(); } void RulerTemp::drawBar(QPainter *painter) { painter->save(); painter->setPen(Qt::NoPen); painter->setBrush(barColor); //計算在背景寬度的基礎上縮小的百分比, 至少爲 2 int barPercent = barWidth / 8; int circlePercent = radius / 6; if (barPercent < 2) { barPercent = 2; } if (circlePercent < 2) { circlePercent = 2; } //標尺刻度高度 double length = height() - 2 * space - 2 * radius; //計算每一格移動多少 double increment = length / (maxValue - minValue); //計算標尺的高度 int rulerHeight = height() - 1 * space - 2 * radius; int barX = targetX - barWidth / 2; int barY = rulerHeight - (currentValue - minValue) * increment; barRect = QRectF(barX + barPercent, barY + barPercent, barWidth - barPercent * 2, barHeight + radius - barY); int circleX = targetX - radius; //偏移 2 個像素,使得看起來邊緣完整 int circleY = height() - radius * 2 - 2; int circleWidth = radius * 2 - circlePercent * 2; circleRect = QRectF(circleX + circlePercent, circleY + circlePercent, circleWidth, circleWidth); QPainterPath path; path.addRect(barRect); path.addEllipse(circleRect); path.setFillRule(Qt::WindingFill); painter->drawPath(path); //繪製用戶設定值三角號 if (showUserValue) { if (tickPosition == TickPosition_Left || tickPosition == TickPosition_Both) { QPolygon pts; int offset = 15; double initX = targetX - (barWidth / 2 + 5); double initY = rulerHeight - (userValue - minValue) * increment; pts.append(QPoint(initX, initY)); pts.append(QPoint(initX - offset, initY - offset / 2)); pts.append(QPoint(initX - offset, initY + offset / 2)); painter->setBrush(userValueColor); painter->drawPolygon(pts); } if (tickPosition == TickPosition_Right || tickPosition == TickPosition_Both) { QPolygon pts; int offset = 15; double initX = targetX + (barWidth / 2 + 5); double initY = rulerHeight - (userValue - minValue) * increment; pts.append(QPoint(initX, initY)); pts.append(QPoint(initX + offset, initY - offset / 2)); pts.append(QPoint(initX + offset, initY + offset / 2)); painter->setBrush(userValueColor); painter->drawPolygon(pts); } } painter->restore(); } void RulerTemp::drawValue(QPainter *painter) { painter->save(); QFont font; font.setPixelSize(circleRect.width() * 0.55); painter->setFont(font); painter->setPen(Qt::white); painter->drawText(circleRect, Qt::AlignCenter, QString("%1").arg(currentValue)); painter->restore(); }