QT绘图:旋转的圆形头像

酷狗手机版播放音乐的时候在播放按钮上面会显示一个旋转的歌手圆形头像,现用qt绘制窗口来实现这一功能。

1、首先是画圆,因为不知道窗口大小,要根据窗口的宽高大小来确定。

    QPainter painter(this);
    painter.setPen(Qt::NoPen);
    painter.setRenderHint(QPainter::Antialiasing, true);
    QPoint centerPoint = rect().center();

    painter.save();
    painter.translate(centerPoint);
    int radius = (std::min(width(),height()) - 10 * 2 ) / 2;
    painter.setPen(Qt::red);
    painter.drawEllipse(QPoint(0, 0), radius, radius);
    painter.restore();

取宽高中的小者减去20除以2作为半径,即圆形离边框10像素。

将绘制的原点移到窗口中心点,以绘制的原点为圆心画圆:

2、绘制图片,如下图,图片的位置是圆的外接矩形。

    QRect rect = QRect(-radius, -radius,
                       radius*2, radius*2);
    painter.drawPixmap(rect,QPixmap(":/img.jpg"));

然而绘制出来的是矩形的,我们希望只在圆形范围内绘制。设置如下:

    QRegion maskedRegion(rect, QRegion::Ellipse);
    painter.setClipRegion(maskedRegion);

将绘制范围限制在此参数矩形的内切圆范围内。

效果:

3、让图片转起来

添加一个定时器和一个全局变量:角度

    QTimer timer;
    double angle{0.0};

每次刷新增加一度旋转角度。人眼的帧率是24帧,超过24帧则很难分辨,故设置刷新频率为40毫秒,每秒刷新25次,看起来就不会有卡段现象。

    connect(&timer,&QTimer::timeout,[this]
    {
        angle += 1.0;
        if(angle == 360)
            angle = 0.0;
        update();
    });
    timer.start(40);

设置绘制坐标的旋转角度:

    painter.rotate(angle);

这个旋转是将绘制坐标旋转一定的角度,旋转的中心是当前绘制的原点(0,0):

但是绘制是仍相对于坐标绘制,就有了绘制的内容旋转的效果。

录制的gif是有损的,实际效果比这好些。

观察到播放音乐时头像周围有个圆形进度条绕着转的,播放一首歌进度条转一圈,实现起来很简单:

    painter.drawArc(rect.adjusted(-3,-3,3,3),0,static_cast<int>(angle * 16));

 最终效果:

完整代码:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
protected:
    void paintEvent(QPaintEvent *event);
private:
    Ui::Widget *ui;
    QTimer timer;
    double angle{0.0};
};
#endif // WIDGET_H

#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(&timer,&QTimer::timeout,[this]
    {
        angle += 1.0;
        if(angle == 360)
            angle = 0.0;
        update();
    });
    timer.start(40);
}

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

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setPen(Qt::NoPen);

    painter.setRenderHint(QPainter::Antialiasing, true);
    QPoint centerPoint = rect().center();

    painter.save();
    painter.translate(centerPoint);
    int radius = (std::min(width(),height()) - 10 * 2 ) / 2;
    QPen pen;
    pen.setColor(Qt::red);
    pen.setWidth(5);
    painter.setPen(pen);
    painter.drawEllipse(QPoint(0, 0), radius, radius);

    QRect rect = QRect(-radius, -radius,
                       radius*2, radius*2);

    pen.setColor(Qt::blue);
    painter.setPen(pen);

    painter.drawArc(rect.adjusted(-3,-3,3,3),0,static_cast<int>(angle * 16));

    QRegion maskedRegion(rect, QRegion::Ellipse);
    painter.setClipRegion(maskedRegion);
    painter.rotate(angle);

    painter.drawPixmap(rect,QPixmap(":/img.jpg"));
    painter.restore();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值