Qt 渐变(五):线性渐变和径向渐变生成星空图

1、Qt 渐变(五): DrawShapes Demo

参考《Java极富客户端》中的例子 DrawShapes

仿 DrawShapes的代码:其思路都尽量和原代码接近。

在DrawShapes演示中可以看到基本形状的用法样例。这个演示的截屏图如下显示,这个图中通过在屏幕的不同区域点击鼠标创建 圆环和 星星。

知识点:

线性渐变、径向渐变 、画家路径 以及 随机数

在这里插入图片描述

  1. 定义形状的容器:使用简单的QList对象: QList<QPainterPath> shapes;

  2. 在mousePressEvent事件中,实现在鼠标点击的位置交替地创建大小随机的 星星 和 圆环,依次加入到 shapes 列表中。

  3. 绘制不同形状,遍历这个形状列表并依次填充。
    请注意,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;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值