Qt实现的雷达扫描效果(QPainter)

【写在前面】

        本篇实际上是接上一篇的。

        本来上一篇中在 QML 中使用 Canvas 实现了类似的效果,但是,不仅性能非常差,而且在我的电脑上偶尔还会崩溃,很烦,所以决定使用 QPainter 来实现这种雷达扫描的效果。

        之前也提到过的在 QML 中使用 QPainter 的方法,因此这篇讲效果实现过程。


【正文开始】

        首先,还是上效果图:

        之前说过,继承 QQuickPaintedItem 通过 QPainter 在 C++ 中实现绘图,

        scanneritem.h:

#ifndef SCANNERITEM_H
#define SCANNERITEM_H

#include <QQuickPaintedItem>

struct Point
{
    QPoint point;
    int alpha;

    Point(const QPoint &p, int a) : point(p) , alpha(a) { }
};

class ScannerItem : public QQuickPaintedItem
{
    Q_OBJECT

public:
    ScannerItem(QQuickItem *parent = nullptr);
    ~ScannerItem();

    Q_INVOKABLE void start();

protected:
    virtual void paint(QPainter *painter);

private:
    bool m_drawable = false;
    int m_angle = 0;
    QList<Point> m_points;
    QTimer *m_updateTimer;
};

#endif // SCANNERITEM_H

        这里的 Point 结构主要用来存储上图中的五个随机点的位置 ( QPoint ) 和透明度 ( alpha ),然后 ScannerItem 继承 QQuickPaintedItem 并实现 virtual void paint(QPainter *painter)。

        接着来看其实现,scanneritem.cpp:

#include "scanneritem.h"

#include <QQuickWindow>
#include <QPainter>
#include <QTimer>
#include <QtMath>

ScannerItem::ScannerItem(QQuickItem *parent)
    : QQuickPaintedItem (parent)
{
    qsrand(uint (time(nullptr)));
    m_updateTimer = new QTimer(this);
    m_updateTimer->setInterval(16);
    connect(m_updateTimer, &QTimer::timeout, this, [this](){ update(); });

    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, [this]
    {
        m_points.clear();
        for(int i = 0; i < 5; ++i)
        {
            int alpha = qrand() % 100 + 40;
            int px = qrand() % int(width());
            int py = qrand() % int(height());
            m_points.append(Point(QPoint(px, py), alpha));
        }
    });
    timer->start(1400);
}

ScannerItem::~ScannerItem()
{

}

void ScannerItem::start()
{
    m_drawable = true;
    m_angle = 0;
    m_updateTimer->start();
}

void ScannerItem::paint(QPainter *painter)
{
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setPen(QPen(qRgba(120, 110, 250, 250)));

    //格子
    for(int i = 0; i < width(); i += 20)
        painter->drawLine(i + 0.5, 0, i + 0.5, height());
    for(int j = 0; j < height(); j += 20)
        painter->drawLine(0, j + 0.5, width(), j + 0.5);

    int min = int(qMin(width(), height()));
    QPoint center(int(width() / 2), int(height() / 2));
    painter->drawEllipse(center, min / 2, min / 2);
    painter->drawEllipse(center, min / 3, min / 3);
    painter->drawEllipse(center, min / 6, min / 6);

    if (m_drawable)
    {
        int diff = int(qAbs(width() - height()) / 2);
        QConicalGradient gradient(width() / 2, height() / 2, m_angle + 180);
        gradient.setColorAt(0.1, QColor(15, 45, 188, 200));
        gradient.setColorAt(0.7, QColor(15, 45, 188, 0));
        painter->setBrush(gradient);
        painter->setPen(QPen(Qt::NoPen));
        if (width() > height())
            painter->drawPie(diff, 0, min, min, m_angle * 16, 60 * 16);
        else painter->drawPie(0, diff, min, min, m_angle * 16, 60 * 16);

        for(int i = 0; i < 5; ++i)
        {
            painter->setBrush(QBrush(QColor(15, 45, 188, m_points.at(i).alpha)));
            painter->drawEllipse(m_points.at(i).point, 7, 7);
        }
        m_angle -= 2;
    }
}

        ★ 构造函数中先初始化随机数种子,然后这里有两个定时器,m_updateTimer 是控制 paint 更新的,间隔为16ms(60FPS),而 timer 是控制五个随机点的,1400ms 更换一次。

        ​★ 而 start() 函数开始 update,重置扫描扇形的角度,并且设置 drawable 为 true,这里 start() 使用 Q_INVOKABLE 修饰,即可在 QML 中调用。

        ★ 然后是 paint():

        1、使用 drawLine() 绘制网格。

        2、使用 drawEllipse() 绘制三个圆,半径以宽高中较小的来度量。

        3、使用 drawable: bool 控制扫描扇形是否绘制。

        4、使用 drawPie() 绘制扇形,并且使用锥形渐变进行填充,这里需要注意的是使用 painter->setPen(QPen(Qt::NoPen)) 去掉扇形的外框线。

        5、使用 drawEllipse() 绘制五个随机的圆点。

        ★ 将 ScannerItem 注册进 qml 中即可:

    qmlRegisterType<ScannerItem>("an.item", 1, 0, "ScannerItem");

        ★ 最后,导入 qml 并使用:

    .
    .
    .
import an.item 1.0
    .
    .
    .
ScannerItem
{
    id: scanner
    clip: true
    anchors.fill: parent
}
    .
    .
    .

【结语】

        本篇几乎可以看做是上一篇的c++实现 ( 上一篇使用 qml Canvas),当然效果有一些变化,不过性能却好了太多,所以还是觉得以后不用 Canvas 了〒▽〒。。

        至于为什么不用 opengl (这也太大材小用了吧)。。

        最后,资源地址(hhh赚点积分):QtQuick制作的文件传输器-C++文档类资源-CSDN下载

        也可以访问项目地址(多多star呀..⭐_⭐):https://github.com/mengps/FileTransfer

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦起丶

您的鼓励和支持是我创作最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值