【Qt】使用QPixmap优化绘图

解决的问题

        在绘制比较复杂的控件时,需要在paintEvent中书写大量的绘图代码。如果代码量巨大,且控件经常刷新,应用程序就会频繁的绘制这一坨大量的绘图代码,非常的浪费计算机资源。例如仪表盘,仪表盘需要绘制背景,边框,刻度,刻度数值,指针等,如果是涉及到渐变色,不规则图形过多的话,代码量就会很大,动辄一二百行去实现。

        绘图优化的原理:将控件绘图部分根据频繁刷新度分离代码,例如仪表盘的背景和刻度,以及刻度数值是不需要频繁更换的,这些内容相较固定。顶多是控件大小发生变化,刻度区间发生变化等等情况时才需要重新绘制。相对来说,仪表盘的数值指针是需要频繁绘制的。

         因此,将不频繁变动的部分在需要时绘制为QPixmap以png格式保存起来,在paintEvent中绘制该部分时,只需要绘制该QPixmap即可,这样可以优化绘图性能。

示例前奏

        

        以绘制上图作为演示。

示例

#ifndef DASHBOARD_H
#define DASHBOARD_H

#include <QWidget>
#include <QPainter>
#include <QPainterPath>
#include <QBitmap>

#define PI 3.14159265

class DashBoard:public QWidget{
    Q_OBJECT
public:
    explicit DashBoard(QWidget* parent=nullptr);
    ~DashBoard();
    inline void setVal(int val){_curVal=val;}
    void setValRange(int minVal,int maxVal);
    void getValRange(int& minVal,int& maxVal);
    void setStartAngle(int angle);
protected:
    void resizeEvent(QResizeEvent* event)override;
    void paintEvent(QPaintEvent* e)override;
private:
    void paintBackground();
    void drawPointer(QPainter& painter);
private:
    QPixmap _pixmap;
    int _minVal=0;
    int _maxVal=90;
    int _curVal=50;
    int _side;//直径
    int _radius;//半径
    int _startAngle=30;
    int _x,_y;//绘图的起点
};

#endif // DASHBOARD_H
#include "dashboard.h"

DashBoard::DashBoard(QWidget* parent):QWidget(parent){}
DashBoard::~DashBoard(){}
void DashBoard::setValRange(int minVal,int maxVal){
    _minVal=minVal;
    _maxVal=maxVal;
    paintBackground();
}
void DashBoard::getValRange(int &minVal,int &maxVal){
    _minVal=minVal;
    _maxVal=maxVal;
}
void DashBoard::setStartAngle(int angle){
    if(angle>=180)return;
    _startAngle=angle;
    paintBackground();
}
void DashBoard::resizeEvent(QResizeEvent* e){
    Q_UNUSED(e);
    _pixmap=QPixmap(width(),height());
    paintBackground();
}
void DashBoard::paintEvent(QPaintEvent* e){
    Q_UNUSED(e);
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing,true);
    painter.drawPixmap(0,0,_pixmap);
    drawPointer(painter);
}
void DashBoard::paintBackground(){
    _pixmap.fill();//清空QPixmap

    int w=width();
    int h=height();

    _side=qMin(w,h);
    _radius=_side/2.0;
    _x=(w<h)?0:(w-h)/2;
    _y=(h<w)?0:(h-w)/2;
    //*******************************************************************************************************绘制背景
    QPainter painter;
    painter.begin(&_pixmap);
    painter.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing,true);

    QPainterPath path1,path2,path3,path4,path5,path6,path7,path8;
    path1.addEllipse(QRectF(-_radius,-_radius,_side,_side));
    path2.addEllipse(QRectF(-_radius*0.9,-_radius*0.9,_side*0.9,_side*0.9));
    path3=path1-path2;
    path4.addEllipse(QRectF(-_radius*0.85,-_radius*0.85,_side*0.85,_side*0.85));
    path5=path2-path4;
    path6.addEllipse(QRectF(-_radius*0.12,-_radius*0.12,_side*0.12,_side*0.12));
    path7.addEllipse(QRectF(-_radius*0.1,-_radius*0.1,_side*0.1,_side*0.1));
    path8=path6-path7;

    QConicalGradient gradient;
    gradient.setCenter(0,0);
    gradient.setAngle(180);
    gradient.setColorAt(0,0x828282);
    gradient.setColorAt(0.125,0xd6d8d7);
    gradient.setColorAt(0.25,0x484745);
    gradient.setColorAt(0.375,0x060608);
    gradient.setColorAt(0.5,0x494846);
    gradient.setColorAt(0.625,0xd9d7d8);
    gradient.setColorAt(0.75,0xb3b5b4);
    gradient.setColorAt(0.875,0xf5f7f6);
    gradient.setColorAt(1,0x828282);


    QConicalGradient gradient1;
    gradient1.setCenter(0,0);
    gradient1.setAngle(180);
    gradient1.setColorAt(0,0x110809);
    gradient1.setColorAt(0.125,0x140c0a);
    gradient1.setColorAt(0.25,0x49403b);
    gradient1.setColorAt(0.375,0x534f4c);
    gradient1.setColorAt(0.5,0x4a423f);
    gradient1.setColorAt(0.625,0x2e2422);
    gradient1.setColorAt(0.75,0xb3b5b4);
    gradient1.setColorAt(0.875,0x000001);
    gradient1.setColorAt(1,0x100a0a);

    painter.save();
    painter.translate(_x+_radius,_y+_radius);
    painter.setPen(Qt::NoPen);
    painter.setBrush(QColor(0x000001));
    painter.drawPath(path1);
    painter.setBrush(gradient1);
    painter.drawPath(path5);
    painter.setBrush(gradient);
    painter.drawPath(path3);
    painter.drawPath(path8);
    painter.restore();

    //*******************************************************************************************************绘制刻度
    double unitAngle=(double)(360-_startAngle*2)/(double)(_maxVal-_minVal);

    QLine line(QPoint(0,_radius*0.7),QPoint(0,_radius*0.8));
    QLine line1(QPoint(0,_radius*0.74),QPoint(0,_radius*0.8));
    QLine line2(QPoint(0,_radius*0.76),QPoint(0,_radius*0.8));

    painter.save();
    painter.translate(_x+_radius,_y+_radius);
    painter.rotate(_startAngle-unitAngle);
    for(int i=0;i<=(_maxVal-_minVal);i++){
        painter.rotate(unitAngle);
        if(i%10==0){
            painter.setPen(QPen(QColor(0xFFFFFF),3.5));
            painter.drawLine(line);
        }else if(i%5==0){
            painter.setPen(QPen(QColor(0xFFFFFF),2));
            painter.drawLine(line1);
        }else{
            painter.setPen(QPen(QColor(0xFFFFFF),1));
            painter.drawLine(line2);
        }
    }
    painter.restore();

    //*******************************************************************************************************绘制刻度数值
    double len=_radius*0.63;
    double len1=_radius*0.68;
    QFont font("微软雅黑");
    font.setPointSize(14);

    QFont font1(font);
    font1.setPointSize(10);

    painter.save();
    painter.translate(_x+_radius,_y+_radius);
    painter.setPen(QPen(QColor(0xFFFFFF)));
    for(int i=0;i<=(_maxVal-_minVal);i++){
        if(i%10==0){
            double nowAngle=(_startAngle+i*unitAngle)*PI/180.0;
            QRectF dialRect(-len*qSin(nowAngle)-15,len*qCos(nowAngle)-15,30,30);
            painter.setFont(font);
            painter.drawText(dialRect,Qt::AlignCenter,QString::number(i+_minVal));
        }else if(i%5==0){
            double nowAngle=(_startAngle+i*unitAngle)*PI/180.0;
            QRectF dialRect(-len1*qSin(nowAngle)-15,len1*qCos(nowAngle)-15,30,30);
            painter.setFont(font1);
            painter.drawText(dialRect,Qt::AlignCenter,QString::number(i+_minVal));
        }
    }
    painter.restore();

    painter.end();

    //保存绘图
    _pixmap.save("dashBoard.png");
}
void DashBoard::drawPointer(QPainter& painter){
    QPointF p1(-0.02*_radius,-0.15*_radius);
    QPointF p2(0,-0.16*_radius);
    QPointF p3(0.02*_radius,-0.15*_radius);
    QPointF p4(0,0.8*_radius);

    QPolygonF polygon;
    polygon<<p1<<p2<<p3<<p4<<p1;

    double nowAngle=_startAngle+(double)(_curVal-_minVal)/(_maxVal-_minVal)*(360-2*_startAngle);

    painter.save();
    painter.translate(_x+_radius,_y+_radius);
    painter.rotate(nowAngle);
    painter.setPen(Qt::NoPen);
    painter.setBrush(QColor(0xdd0615));
    painter.drawPolygon(polygon);
    painter.restore();
}

效果

        简单的绘制了一下,没有完全实现上上图效果。

        可以看到,在编译文件中生成了一个png格式的图片。 

        打开后的效果:

        可以看到打开这个图片后,除了反应数值的指针没有绘制,其他内容都绘制在了png图片中。当然,也可以不保存绘图,将绘制好不用频繁绘制的部分保存在内存中。即注释掉_pixmap.save("dashBoard.png");

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值