前言
简单了解了QPainter
之后当然是要找两个例子练练手啦。
正文
先看效果图
在绘制之前我们要先构思好自己要绘制的对象可以分成几部分,比如我要绘制时钟的话,我可以分成:外边框(圆环或者圆),圆形背景,刻度,时间数字,秒针,分针,时针,中心点;
当然也可以不分这么细,或者分的更细,留下接口以实现更多的效果。
绘制外边框
ClockPainter::ClockPainter(QWidget *parent): QWidget(parent), ui(new Ui::ClockPainter)
{ui->setupUi(this);// 外半径outRadius = 108;// 内半径inRadius = 100;crownColorStart = QColor(255,0,0);crownColorEnd = QColor(64,156,250);
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);
}void ClockPainter::drawCrown(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 渐变QLinearGradient gradient(-outRadius, -outRadius, outRadius, outRadius);gradient.setColorAt(0, crownColorStart);gradient.setColorAt(1, crownColorEnd);painter->setBrush(gradient);painter->drawEllipse(-outRadius, -outRadius, outRadius<<1, outRadius<<1);painter->restore();
}
效果
绘制背景
ClockPainter::ClockPainter(QWidget *parent): QWidget(parent), ui(new Ui::ClockPainter)
{ui->setupUi(this);// 外半径outRadius = 108;// 内半径inRadius = 100;crownColorStart = QColor(255,0,0);crownColorEnd = QColor(64,156,250);
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);
}void ClockPainter::drawBg(QPainter *painter)
{painter->save();painter->setBrush(Qt::black);painter->drawEllipse(-inRadius, -inRadius, inRadius<<1, inRadius<<1);painter->restore();
}
效果
绘制刻度
void ClockPainter::drawScale(QPainter *painter)
{painter->save();QPen pen;pen.setColor(Qt::white);for (int i = 0; i < 60; ++i) {// 长的和短的粗细不一样if (i % 5 == 0) {pen.setWidth(2);pen.setCapStyle(Qt::RoundCap);painter->setPen(pen);painter->drawLine(inRadius - 8, 0, inRadius, 0);} else {pen.setWidth(1);painter->setPen(pen);painter->drawLine(inRadius - 4, 0, inRadius, 0);}painter->rotate(6);}painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);
}
效果
绘制时间数字
QRectF ClockPainter::textRectF(qreal radius, int pointSize, qreal angle)
{// 用于计算每个数字所在的矩形QRectF rectF;rectF.setX(radius*qCos(angle*M_PI/180.0) - pointSize*2);rectF.setY(radius*qSin(angle*M_PI/180.0) - pointSize/2.0);rectF.setWidth(pointSize*4);rectF.setHeight(pointSize*1.5);return rectF;
}void ClockPainter::drawScaleNum(QPainter *painter)
{painter->save();// 获取当前字体QFont font = painter->font();// 设置粗体font.setBold(true);painter->setFont(font);int pointSize = font.pointSize();painter->setPen(Qt::white);int nHour = 0;for (int i = 0; i < 12; ++i) {nHour = i + 3;if (nHour > 12)nHour -= 12;painter->drawText(textRectF(inRadius*0.8, pointSize, i * 30), Qt::AlignCenter, QString::number(nHour));}painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);
}
效果
绘制中心点
void ClockPainter::drawCenterDot(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);QLinearGradient gradient(-10, -10, 10, 10);gradient.setColorAt(0, Qt::gray);gradient.setColorAt(0.2,Qt::black);gradient.setColorAt(1, Qt::gray);painter->setBrush(gradient);painter->drawEllipse(-5,-5,10,10);painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawCenterDot(&painter);}
效果
绘制秒针
void ClockPainter::drawSec(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-3,-2)<<QPoint(70,-1)<<QPoint(70,1)<<QPoint(-3,2);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawSec(&painter);drawCenterDot(&painter);}
效果
绘制分针
void ClockPainter::drawMin(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-6,-3)<<QPoint(63,-2)<<QPoint(63,2)<<QPoint(-6,3);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawMin(&painter);drawSec(&painter);drawCenterDot(&painter);}
效果
绘制时针
void ClockPainter::drawHour(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-6,-4)<<QPoint(50,-3)<<QPoint(50,3)<<QPoint(-6,4);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawHour(&painter);drawMin(&painter);drawSec(&painter);drawCenterDot(&painter);}
效果
其实从话指针就很容易看出来,只要会画一个,其余的就改动一点,代码重复性极高
添加定时器使得指针动起来
ClockPainter::ClockPainter(QWidget *parent): QWidget(parent), ui(new Ui::ClockPainter)
{ui->setupUi(this);// 外半径outRadius = 108;// 内半径inRadius = 100;crownColorStart = QColor(255,0,0);crownColorEnd = QColor(64,156,250);// 初始化时间QTime time = QTime::currentTime();hour = time.hour();min = time.minute();sec = time.second();// 初始化定时器timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &ClockPainter::updateTime);// 设置时间间隔为1stimer->start(1000);}
void ClockPainter::updateTime()
{QTime time = QTime::currentTime();hour = time.hour();// 12小时制if (hour > 12) {hour -= 12;}min = time.minute();sec = time.second();// 更新图像update();
}
//关键是要在相应的绘制指针的函数中调用rotate函数,使得绘制的图像旋转
效果
总体代码
这里我定义了指针的颜色,但是我并没有使用,是想留一个接口进行下一步开发。
头文件
#ifndef CLOCKPAINTER_H
#define CLOCKPAINTER_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class ClockPainter; }
QT_END_NAMESPACEclass ClockPainter : public QWidget
{Q_OBJECTpublic:ClockPainter(QWidget *parent = nullptr);~ClockPainter();protected:void paintEvent(QPaintEvent *);// 画外边框void drawCrown(QPainter *painter);// 画背景void drawBg(QPainter *painter);// 画刻度void drawScale(QPainter *painter);// 画刻度上的数字void drawScaleNum(QPainter *painter);// 时针void drawHour(QPainter *painter);// 分针void drawMin(QPainter *painter);// 秒针void drawSec(QPainter *painter);// 画中心点void drawCenterDot(QPainter *painter);// 处理数字位置QRectF textRectF(qreal radius, int pointSize, qreal angle);private slots:void updateTime();
private:Ui::ClockPainter* ui;// 外边框半径int outRadius;// 内边框半径int inRadius;// 外边框渐变开始颜色QColor crownColorStart;// 外边框渐变结束颜色QColor crownColorEnd;// 背景色QColor background;// 时钟指针颜色QColor pointerHourColor;// 分钟指针颜色QColor pointerMinColor;// 秒钟指针颜色QColor pointerSecColor;// 定时器绘制QTimer *timer;// 时分秒int hour, min, sec;
};#endif // CLOCKPAINTER_H
源文件
#include "clockpainter.h"
#include "ui_clockpainter.h"
#include "qpainter.h"
#include "qpen.h"
#include "qcolor.h"
#include "qpolygon.h"
#include "qfont.h"
#include "qtimer.h"
#include "qmath.h"
#include "qrect.h"
#include "qtransform.h"
#include <QTime>
#include <QLinearGradient>
#include "qdebug.h"ClockPainter::ClockPainter(QWidget *parent): QWidget(parent), ui(new Ui::ClockPainter)
{ui->setupUi(this);// 外半径outRadius = 108;// 内半径inRadius = 100;crownColorStart = QColor(255,0,0);crownColorEnd = QColor(64,156,250);// 初始化时间QTime time = QTime::currentTime();hour = time.hour();min = time.minute();sec = time.second();// 初始化定时器timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &ClockPainter::updateTime);// 设置时间间隔为1stimer->start(1000);}ClockPainter::~ClockPainter()
{delete ui;
}void ClockPainter::paintEvent(QPaintEvent *)
{QPainter painter(this);// 设置图形和文本抗锯齿painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);// 将绘制点移动到窗口中心painter.translate(width() / 2, height() / 2);drawCrown(&painter);drawBg(&painter);drawScale(&painter);drawScaleNum(&painter);drawHour(&painter);drawMin(&painter);drawSec(&painter);drawCenterDot(&painter);}void ClockPainter::drawCrown(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 渐变QLinearGradient gradient(-outRadius, -outRadius, outRadius, outRadius);gradient.setColorAt(0, crownColorStart);gradient.setColorAt(1, crownColorEnd);painter->setBrush(gradient);painter->drawEllipse(-outRadius, -outRadius, outRadius<<1, outRadius<<1);painter->restore();
}void ClockPainter::drawBg(QPainter *painter)
{painter->save();painter->setBrush(Qt::black);painter->drawEllipse(-inRadius, -inRadius, inRadius<<1, inRadius<<1);painter->restore();
}void ClockPainter::drawScale(QPainter *painter)
{painter->save();QPen pen;pen.setColor(Qt::white);for (int i = 0; i < 60; ++i) {// 长的和短的粗细不一样if (i % 5 == 0) {pen.setWidth(2);pen.setCapStyle(Qt::RoundCap);painter->setPen(pen);painter->drawLine(inRadius - 8, 0, inRadius, 0);} else {pen.setWidth(1);painter->setPen(pen);painter->drawLine(inRadius - 4, 0, inRadius, 0);}painter->rotate(6);}painter->restore();
}void ClockPainter::drawScaleNum(QPainter *painter)
{painter->save();// 获取当前字体QFont font = painter->font();// 设置粗体font.setBold(true);painter->setFont(font);int pointSize = font.pointSize();painter->setPen(Qt::white);int nHour = 0;for (int i = 0; i < 12; ++i) {nHour = i + 3;if (nHour > 12)nHour -= 12;painter->drawText(textRectF(inRadius*0.8, pointSize, i * 30), Qt::AlignCenter, QString::number(nHour));}painter->restore();
}void ClockPainter::drawHour(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-6,-4)<<QPoint(50,-3)<<QPoint(50,3)<<QPoint(-6,4);// 旋转,角度需要减去90,因为不减的话,是从12开始计算角度painter->rotate(30.0 * ((hour + min / 60.0)) - 90);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::drawMin(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-6,-3)<<QPoint(63,-2)<<QPoint(63,2)<<QPoint(-6,3);// 旋转,角度需要减去90,因为不减的话,是从12开始计算角度painter->rotate(6.0 * (min + sec / 60.0) - 90);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::drawSec(QPainter *painter)
{painter->save();// 接下来的绘制不用笔,如果没有填充的话将什么效果都没有painter->setPen(Qt::NoPen);// 画一个四边形,两头大,两头小painter->setBrush(Qt::gray);QPolygon polygon;polygon<<QPoint(-3,-2)<<QPoint(70,-1)<<QPoint(70,1)<<QPoint(-3,2);// 旋转,角度需要减去90,因为不减的话,是从12开始计算角度painter->rotate(6.0 * sec - 90);painter->drawPolygon(polygon);painter->restore();
}void ClockPainter::drawCenterDot(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);QLinearGradient gradient(-10, -10, 10, 10);gradient.setColorAt(0, Qt::gray);gradient.setColorAt(0.2,Qt::black);gradient.setColorAt(1, Qt::gray);painter->setBrush(gradient);painter->drawEllipse(-5,-5,10,10);painter->restore();
}QRectF ClockPainter::textRectF(qreal radius, int pointSize, qreal angle)
{// 用于计算每个数字所在的矩形QRectF rectF;rectF.setX(radius*qCos(angle*M_PI/180.0) - pointSize*2);rectF.setY(radius*qSin(angle*M_PI/180.0) - pointSize/2.0);rectF.setWidth(pointSize*4);rectF.setHeight(pointSize*1.5);return rectF;
}void ClockPainter::updateTime()
{QTime time = QTime::currentTime();hour = time.hour();// 12小时制if (hour > 12) {hour -= 12;}min = time.minute();sec = time.second();// 更新图像update();
}