1、Qt 渐变(五): DrawShapes Demo
参考《Java极富客户端》中的例子 DrawShapes
仿 DrawShapes的代码:其思路都尽量和原代码接近。
在DrawShapes演示中可以看到基本形状的用法样例。这个演示的截屏图如下显示,这个图中通过在屏幕的不同区域点击鼠标创建 圆环和 星星。
知识点:
线性渐变、径向渐变 、画家路径 以及 随机数
-
定义形状的容器:使用简单的QList对象:
QList<QPainterPath> shapes;
-
在mousePressEvent事件中,实现在鼠标点击的位置交替地创建大小随机的 星星 和 圆环,依次加入到 shapes 列表中。
-
绘制不同形状,遍历这个形状列表并依次填充。
请注意,paintEvent() 中的大部分代码实际上与渐变有关。我们使用了两个QLinearGradient, 一个从窗口的顶部向下经 过大部分路线,另外一个经过剩余的路线。这样就为我们产生一个虚拟的夜空/地面的外观。 最后,我们对每个形状使用QRadialGradient,中心为白色,外部的边界为黑色。这些形状的真实渲染在这个循环最后的fillPath(shape,g);调用中发生。
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPainterPath>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private:
QPainterPath generateDonut(qreal x, qreal y,qreal innerRadius, qreal outerRadius);
QPainterPath generateStar(qreal x, qreal y,
qreal innerRadius, qreal outerRadius,
int pointsCount);
QList<QPainterPath> shapes;
bool getStar;
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include <QPainter>
#include <QMouseEvent>
#include <QRandomGenerator>
#include <QtMath>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(500,500);
qDebug() << size();
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing);
QLinearGradient background = QLinearGradient(0,0,0,width());
background.setColorAt(0,QColor(Qt::gray).darker(175));
background.setColorAt(1,QColor(Qt::gray).lighter(110));
// painter.setBrush(background);
painter.fillRect(0, 0, width(), 4*height()/5,background);
// Paint a gradient for the ground
background = QLinearGradient(0,4*height()/5,0, height());
background.setColorAt(0,Qt::black);
background.setColorAt(1,QColor(Qt::gray).darker(175));
painter.fillRect(0, 4*height()/5, width(), height()/5,background);
for (int i = 0; i < shapes.count(); ++i) {
QPainterPath shape = shapes.at(i);
QRectF rect = shape.boundingRect();
QPointF center = rect.center();
qreal radius = rect.width()/2;
QRadialGradient g(center,radius);
g.setColorAt(0.1,Qt::white);
g.setColorAt(0.9,Qt::black);
painter.fillPath(shape,g);
}
}
void Widget::mousePressEvent(QMouseEvent *me)
{
int centerX = me->x();
int centerY = me->y();
double innerSize = 1 + (25 * QRandomGenerator::global()->generateDouble());
double outerSize = innerSize + 10 + (15 * QRandomGenerator::global()->generateDouble());
QPainterPath newShape;
if (getStar) {
int numPoints = (int)(8 * QRandomGenerator::global()->generateDouble() + 5);
newShape = generateStar(centerX - outerSize,
centerY - outerSize,
innerSize, outerSize, numPoints);
} else {
newShape = generateDonut(centerX - outerSize/2,
centerY - outerSize/2,
innerSize, outerSize);
}
getStar = !getStar;
shapes<<newShape;
update();
}
QPainterPath Widget::generateDonut(qreal x, qreal y, qreal innerRadius, qreal outerRadius)
{
QPainterPath a1;
a1.addEllipse(x ,y,outerRadius,outerRadius);
qreal innerOffset = (outerRadius - innerRadius)/2;
QPainterPath a2;
a2.addEllipse(x+innerOffset,y+innerOffset,innerRadius,innerRadius);
return a1-a2;
}
QPainterPath Widget::generateStar(qreal x, qreal y, qreal innerRadius, qreal outerRadius, int pointsCount)
{
QPainterPath path;
double outerAngleIncrement = 2 * M_PI / pointsCount;
double outerAngle = 0.0;
double innerAngle = outerAngleIncrement / 2.0;
x += outerRadius;
y += outerRadius;
float x1 = (float) (qCos(outerAngle) * outerRadius + x);
float y1 = (float) (qSin(outerAngle) * outerRadius + y);
float x2 = (float) (qCos(innerAngle) * innerRadius + x);
float y2 = (float) (qSin(innerAngle) * innerRadius + y);
path.moveTo(x1, y1);
path.lineTo(x2, y2);
outerAngle += outerAngleIncrement;
innerAngle += outerAngleIncrement;
for (int i = 1; i < pointsCount; i++) {
x1 = (float) (qCos(outerAngle) * outerRadius + x);
y1 = (float) (qSin(outerAngle) * outerRadius + y);
path.lineTo(x1, y1);
x2 = (float) (qCos(innerAngle) * innerRadius + x);
y2 = (float) (qSin(innerAngle) * innerRadius + y);
path.lineTo(x2, y2);
outerAngle += outerAngleIncrement;
innerAngle += outerAngleIncrement;
}
path.closeSubpath();
return path;
}