基于QT实现自定义温度计的示例代码
0 引入
QT原生控件没有实现如仪表盘或者温度计的控件,只好自己实现,文章代码部分参考引用的文章。直接上图
图一 带有标尺的温度计、湿度
图二 温度计、湿度
控件最核心的部分:在函数paintEvent绘制部分,如果需要动画效果还需要加一个QPropertyAnimation ,这是最主要的,剩下的细节根据需求增加减少即可。
1、带有标尺的温度/湿度计控件
因为只做数据显示用,所以只需要向控件传数据即可。
主要功能:
1、可设置显示范围;
2、显示过程中加了动画效果;
3、背景色和前景色以及刻度尺颜色可变;
4、刻度尺间距可变,控件大小随着QWidget适应;
1.头文件
代码如下(示例):
protected: void paintEvent(QPaintEvent *); void drawBg(QPainter *painter); void drawProgress(QPainter *painter); void drawRulerTop(QPainter *painter); void drawRulerBottom(QPainter *painter); private: QPropertyAnimation *m_valueAnimation; double minValue; //最小值 double maxValue; //最大值 qreal value; //当前值 int longStep; //长线条等分步长 int shortStep; //短线条等分步长 bool rulerTop; //刻度线在上面 bool isAdd; //是否为增加,默认为的增加 QColor bgColor; //背景颜色 QColor lineColor; //线条颜色 QColor progressColor; //进度颜色 public: qreal getValue() const; void setrulerTop(bool istop); //设定刻度线再上还是在下,默认是在上 void setValue(qreal v); void setRange(int minValue, int maxValue); void startAnimation(); void updateValue(double value); void setBgColor(const QColor &bgColor); //设置背景颜色 void setLineColor(const QColor &lineColor); //设置线条颜色 void setProgressColor(const QColor &progressColor); //设置进度颜色
2.核心代码
绘制部分参考引用2代码,感谢刘典武老师的无私开源,有需要的可去做定制。
代码如下:
void HumidityProgress::startAnimation() { qreal startValue = value; if(isAdd) { m_valueAnimation->setKeyValueAt(0.5, value+0.5); m_valueAnimation->setKeyValueAt(1, value); m_valueAnimation->setStartValue(startValue-0.5); m_valueAnimation->start(); } else{ m_valueAnimation->setKeyValueAt(0.5, value-0.5); m_valueAnimation->setKeyValueAt(1, value); m_valueAnimation->setStartValue(startValue+0.5); m_valueAnimation->start(); } } void HumidityProgress::paintEvent(QPaintEvent *) { //绘制准备工作,启用反锯齿 QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); //按照绘制顺序 drawBg(&painter); drawProgress(&painter); if (rulerTop) { drawRulerTop(&painter); } else { drawRulerBottom(&painter); } } void HumidityProgress::drawBg(QPainter *painter) { painter->save(); painter->setPen(lineColor); painter->setBrush(bgColor); painter->drawRect(rect()); painter->restore(); } void HumidityProgress::drawProgress(QPainter *painter) { painter->save(); painter->setPen(Qt::NoPen); painter->setBrush(progressColor); double length = width(); double increment = length / (maxValue - minValue); double initX = (value - minValue) * increment; QRect rect(0, 0, initX, height()); painter->drawRect(rect); painter->restore(); } void HumidityProgress::drawRulerTop(QPainter *painter) { painter->save(); painter->setPen(lineColor); double initX = 0; //绘制横向标尺上部分底部线 double initTopY = 0; QPointF lineTopLeftPot = QPointF(initX, initTopY); QPointF lineTopRightPot = QPointF(width() - initX, initTopY); painter->drawLine(lineTopLeftPot, lineTopRightPot); //绘制上部分及下部分横向标尺刻度 double length = width(); //计算每一格移动多少 double increment = length / (maxValue - minValue); //长线条短线条长度 int longLineLen = 15; int shortLineLen = 10; //根据范围值绘制刻度值及刻度值 长线条需要移动10像素 短线条需要移动5像素 for (int i = minValue; i <= maxValue; i = i + shortStep) { if (i % longStep == 0) { QPointF topPot = QPointF(initX, initTopY); QPointF bottomPot = QPointF(initX, initTopY + longLineLen); painter->drawLine(topPot, bottomPot); //第一个值和最后一个值不要绘制 if (i == minValue || i == maxValue) { initX += increment * shortStep; continue; } QString strValue = QString("%1").arg((double)i, 0, 'f', 0); double textWidth = fontMetrics().width(strValue); double textHeight = fontMetrics().height(); QPointF textPot = QPointF(initX - textWidth / 2, initTopY + textHeight + longLineLen); painter->drawText(textPot, strValue); } else { if (i % (longStep / 2) == 0) { shortLineLen = 10; } else { shortLineLen = 6; } QPointF topPot = QPointF(initX, initTopY); QPointF bottomPot = QPointF(initX, initTopY + shortLineLen); painter->drawLine(topPot, bottomPot); } initX += increment * shortStep; } painter->restore(); }
该处使用的url网络请求的数据。
2、竖起来的温度/湿度计控件
因为只做数据显示用,所以只需要向控件传数据即可。
控件是好看,但是大小不能改变,所以这里需要自己实现了,源码作者已经放上。
1.头文件
代码如下(示例):
#ifndef THERMOMETREDLG_H #define THERMOMETREDLG_H #include <QWidget> #include <QPropertyAnimation> #include <QPainter> #include <QTimer> class thermometreDlg : public QWidget { Q_OBJECT Q_PROPERTY(qreal value READ getValue WRITE setValue) //声明属性 public: explicit thermometreDlg(QWidget *parent = nullptr); qreal getValue(); void setValue(qreal value); void changeValue(qreal value); protected: void paintEvent(QPaintEvent *e); public slots: void startAnimation(); signals: private: qreal m_value; qreal curValue; int m_width; QRectF m_rect; int maxValue, minValue; qreal m_radius; QPropertyAnimation *m_valueAnimation; void updateRect(); }; #endif // THERMOMETREDLG_H
2.实现
代码如下(示例):
#include "thermometredlg.h" #include <QDebug> thermometreDlg::thermometreDlg(QWidget *parent) : QWidget(parent) { m_width = 20; maxValue = 100; minValue = 0; m_radius = 1.05; m_value = 0; curValue = m_value; QTimer *at = new QTimer(this); at->start(1000); m_valueAnimation = new QPropertyAnimation(this, "value"); m_valueAnimation->setDuration(1000); m_valueAnimation->setEasingCurve(QEasingCurve::OutCubic); m_valueAnimation->setLoopCount(1); connect(at, SIGNAL(timeout()), this, SLOT(startAnimation())); } void thermometreDlg::updateRect() { m_rect.setX(0); m_rect.setY(20 - height()/2); m_rect.setWidth(m_width); m_rect.setHeight(height() - 40 - m_width* m_radius); } void thermometreDlg::setValue(qreal value) { m_value = value; update(); } void thermometreDlg::changeValue(qreal value) { if(value > maxValue) value = maxValue; if(value < minValue) value = minValue; curValue = value; } qreal thermometreDlg::getValue() { return m_value; } void thermometreDlg::paintEvent(QPaintEvent *e) { updateRect(); QPainter painter(this); QPen pen(Qt::black); painter.translate(this->width()/2, this->height()/2); //坐标轴移动到中心点 painter.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing); // 启用反锯齿 painter.save(); //绘制上方的柱状 painter.fillRect(m_rect, QColor(168,200, 225)); //绘制底部的圆 QRectF tmpRect = QRectF(m_rect.bottomLeft(), QPointF(m_width, height()/2- m_width*m_radius)); painter.fillRect(tmpRect, QColor(255, 0, 0)); painter.setPen(Qt::NoPen); painter.setBrush(QColor(255, 0, 0)); painter.drawEllipse(tmpRect.bottomLeft()+QPointF(tmpRect.width()/2, 0),m_width*m_radius, m_width*m_radius); painter.restore(); //绘制刻度以及刻度值 painter.save(); painter.setPen(QColor(Qt::black)); int nYCount = (maxValue - minValue)/10+1; qreal perHeight = (m_rect.height())/nYCount; for (int i=0; i<nYCount; ++i) { QPointF basePoint = m_rect.bottomLeft() - QPointF(0, perHeight/2) - QPointF(0, perHeight*i); //左侧大刻度 painter.drawLine(basePoint, basePoint+QPointF(-10, 0)); for (int j=1; j<10; ++j) { if(i == nYCount -1) continue; painter.drawLine(basePoint-QPointF(0, perHeight/10*j),basePoint-QPointF(5, perHeight/10*j)); } painter.drawText(basePoint+QPointF(-28, 4), QString("%1").arg(minValue+i*10)); //右侧大刻度 basePoint = m_rect.bottomRight() - QPointF(0, perHeight/2) - QPointF(0, perHeight*i); painter.drawLine(basePoint, basePoint+QPointF(10, 0)); for (int j=1; j<10; ++j) { if(i == nYCount -1) continue; painter.drawLine(basePoint-QPointF(0, perHeight/10*j),basePoint-QPointF(-5, perHeight/10*j)); } } painter.restore(); //根据值填充m_rect qreal h = (m_value-minValue)/(maxValue-minValue)*(m_rect.height()-perHeight); if(h<0) h = 0; if(h > m_rect.height()) h = m_rect.height(); painter.fillRect(m_rect.adjusted(0, m_rect.height()-h-perHeight/2-1 , 0, 0), QColor(255, 0, 0)); QWidget::paintEvent(e); } void thermometreDlg::startAnimation() { qreal startValue = getValue(); m_valueAnimation->setKeyValueAt(0, startValue-1); m_valueAnimation->setKeyValueAt(0.5, curValue+1); m_valueAnimation->setKeyValueAt(1, curValue); m_valueAnimation->setStartValue(startValue-2); m_valueAnimation->start(); }
以上就是基于QT实现自定义温度计的示例代码的详细内容,更多关于QT温度计的资料请关注脚本之家其它相关文章!
最新评论