文章目录

  • QPainter绘制时【数据类型】和【抗锯齿】对绘制效果的影响【2】
  • 1、概述
  • 2、关键代码
  • 3、源代码

1、概述

  • Qt版本:V5.12.5
  • 本文内容
  1. 使用【浮点数】进行绘制,绘制的圆会更加均匀;
  2. 使用【整形】进行绘制,比浮点数计算快,适用于频繁、大量的重绘,但绘制效果较差;
  3. 开启【抗锯齿】后线条会更加平滑;
  4. 将布局改为使用设计器布局,减少使用代码布局,使关注点更多在绘制图形上;
  5. 将使用定时器更新绘制改为使用滑动条更新,增加可控性,便于观察绘制细节。
  • 整体效果

2、关键代码

  • circlewidget.h
#ifndef CIRCLEWIDGET_H
#define CIRCLEWIDGET_H

#include <QObject>
#include <QWidget>

class CircleWidget : public QWidget
{
    Q_OBJECT
public:
    explicit CircleWidget(QWidget *parent = nullptr);

    void setFloatBased(bool flag);           // 设置是否使用浮点型数据类型来保存绘制图案的数据
    void setAntialiased(bool flag);          // 是否使用抗锯齿渲染
    void setFrame(int value);

signals:

public slots:

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    bool floatBased = false;         // 是否使用浮点类型数绘制
    bool antialiased = false;        // 是否开启抗锯齿
    int frameNo = 0;
};

#endif // CIRCLEWIDGET_H
  • circlewidget.cpp
#include "circlewidget.h"

#include <qdebug.h>
#include <qpainter.h>

CircleWidget::CircleWidget(QWidget *parent) : QWidget(parent)
{

}

/**
 * @brief       设置是否使用浮点型数据类型来保存绘制图案的数据
 * @param flag  true:使用 false:不使用
 */
void CircleWidget::setFloatBased(bool flag)
{
    this->floatBased = flag;
    this->update();
}

/**
 * @brief      是否使用抗锯齿渲染
 * @param flag true:使用  false:不使用
 */
void CircleWidget::setAntialiased(bool flag)
{
    this->antialiased = flag;
    this->update();
}

/**
 * @brief        设置绘制的参数
 * @param value
 */
void CircleWidget::setFrame(int value)
{
    this->frameNo = value;
    this->update();
}

void CircleWidget::paintEvent(QPaintEvent *event)
{
    QWidget::paintEvent(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, antialiased);           // 设置抗锯齿(开启后线条会更加平滑)
    painter.drawRect(QRect(0, 0, this->width() - 1, this->height() - 1)); // 画一个边框
    painter.translate(this->rect().center());                             // 将坐标轴原点移动到中心位置

    for(int diameter = 0; diameter < 256; diameter += 9)                  // 由于QColor透明度通道最大值为255,这里为了方便也设置最大255
    {
        int delta = (diameter / 2) - frameNo;
        int alpha = 255 - (delta * delta) / 4 - diameter;                 // 计算透明度

        if(alpha <= 0) continue;                                          // 如果颜色透明度不为正值则不进行绘制

        painter.setPen(QPen(QColor(0, 127, 127, alpha), 3));              // 设置画笔,颜色透明度渐变
        if(floatBased)
        {
            painter.drawEllipse(QRectF(-diameter / 2.0, -diameter / 2.0, diameter, diameter));   // 使用浮点数进行绘制,绘制的圆会更加均匀
        }
        else
        {
            painter.drawEllipse(QRect(-diameter / 2, -diameter / 2, diameter, diameter));        // 使用整形进行绘制,比浮点数计算快,适用于频繁、大量的重绘,但绘制效果较差
        }
    }
}
  • widget.cpp
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setWindowTitle("QPainter绘制时【数据类型】和【抗锯齿】对效果的影响");

    ui->widget_2->setAntialiased(true);   // 开启抗锯齿
    ui->widget_4->setAntialiased(true);
    ui->widget_3->setFloatBased(true);    // 使用浮点数据类型进行绘制
    ui->widget_4->setFloatBased(true);
}

Widget::~Widget()
{
    delete ui;
}

/**
 * @brief         因为Qt的Demo使用定时器更新参数会一直刷新,不便于观察细节,这里改为通过滑动条设置绘制的参数
 * @param value
 */
void Widget::on_horizontalSlider_valueChanged(int value)
{
    ui->widget->setFrame(value);
    ui->widget_2->setFrame(value);
    ui->widget_3->setFrame(value);
    ui->widget_4->setFrame(value);
}