美文网首页Qt自定义控件大全
Qt编写自定义控件5-柱状温度计

Qt编写自定义控件5-柱状温度计

作者: feiyangqingyun | 来源:发表于2019-04-23 09:04 被阅读1次

    前言

    柱状温度计控件,可能是很多人练手控件之一,基本上都是垂直方向展示,底部一个水银柱,中间刻度尺,刻度尺可以在左侧右侧或者两侧都有,自适应分辨率改动,有时候为了美观效果,可能还会整个定时器来实现动画效果,开启动画效果的缺点就是CPU占用会比较高,前阵子有个好友(贾文涛-涛哥)向我推荐了一个opengl绘制的开源东西,QNanoPainter,东西是个好东西,我个人的理解是直接封装了opengl绘制的qpainter,可以使得绘制全部走GPU,这样就可以大大减轻CPU的负担,非常方便,我自己试了下,方法和绘制逻辑和qpainter有点不一样,暂时没有将所有控件改成QNanoPainter版本,以后看情况吧。

    实现的功能

    • 1:可设置精确度(小数点后几位)和间距
    • 2:可设置背景色/柱状颜色/线条颜色
    • 3:可设置长线条步长及短线条步长
    • 4:可启用动画及动画步长
    • 5:可设置范围值
    • 6:支持负数刻度值
    • 7:支持任意窗体大小缩放
    • 8:可设置柱状条位置 左侧 居中 右侧
    • 9:可设置刻度尺位置 无 左侧 右侧 两侧
    • 10:可设置用户设定目标值

    效果图

    rulertemp.gif

    头文件代码

    #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();
    }
    
    

    控件介绍

    1. 超过130个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
    2. 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
    3. 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.12的任何Qt版本,支持mingw、msvc、gcc等编译器,不乱码,可直接集成到Qt Creator中,和自带的控件一样使用,大部分效果只要设置几个属性即可,极为方便。
    4. 每个控件都有一个对应的单独的包含该控件源码的DEMO,方便参考使用。同时还提供一个所有控件使用的集成的DEMO。
    5. 每个控件的源代码都有详细中文注释,都按照统一设计规范编写,方便学习自定义控件的编写。
    6. 每个控件默认配色和demo对应的配色都非常精美。
    7. 超过120个可见控件,6个不可见控件。
    8. 部分控件提供多种样式风格选择,多种指示器样式选择。
    9. 所有控件自适应窗体拉伸变化。
    10. 集成自定义控件属性设计器,支持拖曳设计,所见即所得,支持导入导出xml格式。
    11. 自带activex控件demo,所有控件可以直接运行在ie浏览器中。
    12. 集成fontawesome图形字体+阿里巴巴iconfont收藏的几百个图形字体,享受图形字体带来的乐趣。
    13. 所有控件最后生成一个dll动态库文件,可以直接集成到qtcreator中拖曳设计使用。

    SDK下载

    1_property1.png 1_property2.png

    相关文章

      网友评论

        本文标题:Qt编写自定义控件5-柱状温度计

        本文链接:https://www.haomeiwen.com/subject/qudmgqtx.html