基于QT实现自定义温度计的示例代码

 更新时间:2023年11月07日 14:00:41   作者:疯狂的挖掘机  
QT原生控件没有实现如仪表盘或者温度计的控件,只好自己实现,所以本文为大家介绍了如何利用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温度计的资料请关注脚本之家其它相关文章!

相关文章

  • C语言实现猜拳游戏

    C语言实现猜拳游戏

    这篇文章主要为大家详细介绍了C语言实现猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • 基于C++ map中key使用指针问题的详解

    基于C++ map中key使用指针问题的详解

    本篇文章是对C++ map中key使用指针的问题进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言实现的循环单链表功能示例

    C语言实现的循环单链表功能示例

    这篇文章主要介绍了C语言实现的循环单链表功能,结合实例形式分析了基于C语言实现的循环单链表定义、创建、添加、删除、打印、排序等相关操作技巧,需要的朋友可以参考下
    2018-04-04
  • 老生常谈C++ 中的继承

    老生常谈C++ 中的继承

    这篇文章主要介绍了C++ 中的继承,本文通过实例代码给大家介绍的非常详细对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • C语言实现Floyd算法

    C语言实现Floyd算法

    这篇文章主要为大家详细介绍了C语言实现Floyd算法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • C++设计模式之模板方法模式

    C++设计模式之模板方法模式

    这篇文章主要介绍了C++设计模式之模板方法模式,本文讲解了什么是模板方法模式、模板方法模式的UML类图、模板方法模式的使用场合等内容,需要的朋友可以参考下
    2014-10-10
  • C++中rapidjson将map转为json的方法

    C++中rapidjson将map转为json的方法

    今天小编就为大家分享一篇关于C++中rapidjson将map转为json的方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • C++中用指向数组的指针作函数参数

    C++中用指向数组的指针作函数参数

    多维数组名作为函数参数传递:在二维数组中,数组名a是指向首行a[0]的指针,也就是说a=&a[0]; a[0]是指向首元素a[0][0]的指针,也就是说a[0]=&a[0][0]
    2013-10-10
  • C++中gSOAP的使用详解

    C++中gSOAP的使用详解

    这篇文章主要介绍了C++中gSOAP的使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-11-11
  • 深入解析C中的数值与真假

    深入解析C中的数值与真假

    本篇文章是对C中数值与真假进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论