《QT实用小工具·四十五》可以在界面上游泳的小鱼

news2024/10/7 12:29:14

1、概述
源码放在文章末尾

该项目实现了灵动的小鱼,可以在界面上跟随鼠标点击自由的游泳,项目demo演示如下所示:
在这里插入图片描述

项目部分代码如下所示:

#include "magicfish.h"
#include <QtMath>
#include <QPainter>
#include <QPainterPath>
#include <QVariantAnimation>

MagicFish::MagicFish(QQuickPaintedItem *parent)
    : QQuickPaintedItem(parent),
      m_fishRadius(30),
      m_finLen(30 * 1.3),
      m_bodyHeight(30 * 3.2),
      m_headAlpha(200),
      m_bodyAlpha(225),
      M_finAlpha(120),
      m_mainAngle(0.0),
      m_curValue(0),
      m_wave(1.0),
      m_startFin(false),
      m_paintPoint(false)
{
    m_animation = new QVariantAnimation(this);
    m_animation->setDuration(180 * 1000);
    m_animation->setStartValue(0);
    m_animation->setEndValue(54000);
    m_animation->setLoopCount(-1);
    connect(m_animation, &QVariantAnimation::valueChanged, this, [this](const QVariant &value)
    {
        m_curValue = value.toInt();
        update();
    });

    connect(this, &QQuickItem::widthChanged, this, &MagicFish::resize);
    connect(this, &QQuickItem::heightChanged, this, &MagicFish::resize);

    m_animation->start();
}

void MagicFish::paint(QPainter *painter)
{
    painter->setRenderHint(QPainter::Antialiasing);
    QPointF middle_pos = QPointF(width() / 2, height() / 2);
    m_headPos = calcPoint(middle_pos, m_bodyHeight / 2.0, m_mainAngle);
    paintMyPoint(painter, m_headPos);
    paintMyPoint(painter, middle_pos);
    painter->setPen(Qt::NoPen);
    painter->setBrush(QBrush(QColor(20, 203, 232, 50)));
    painter->setBrush(QBrush(QColor(244, 92, 71, m_headAlpha)));
    painter->drawEllipse(m_headPos, m_fishRadius, m_fishRadius);

    qreal angle = m_mainAngle + qSin(qDegreesToRadians(m_curValue * 1.2 * m_wave)) * 2;
    QPointF end_pos = calcPoint(m_headPos, m_bodyHeight, angle - 180);
    QPointF pos1 = calcPoint(m_headPos, m_fishRadius, angle - 80);
    QPointF pos2 = calcPoint(end_pos, m_fishRadius * 0.7, angle - 90);
    QPointF pos3 = calcPoint(end_pos, m_fishRadius * 0.7, angle + 90);
    QPointF pos4 = calcPoint(m_headPos, m_fishRadius, angle + 80);

    QPointF central_left = calcPoint(m_headPos, m_bodyHeight * 0.56, angle - 130);
    QPointF central_right = calcPoint(m_headPos, m_bodyHeight * 0.56, angle + 130);
    QPainterPath path;
    path.moveTo(pos1);
    path.quadTo(central_left, pos2);
    path.lineTo(pos3);
    path.quadTo(central_right, pos4);
    path.lineTo(pos1);

    painter->setBrush(QBrush(QColor(244, 92, 71, m_bodyAlpha)));
    painter->drawPath(path);

    paintMyBody(painter, end_pos, m_fishRadius * 0.7, 0.6, angle);
    QPointF left_fin_pos = calcPoint(m_headPos, m_fishRadius * 0.9, angle + 110);
    paintMyFishFins(painter, left_fin_pos, true, angle);
    QPointF right_fin_pos = calcPoint(m_headPos, m_fishRadius * 0.9, angle - 110);
    paintMyFishFins(painter, right_fin_pos, false, angle);
}

void MagicFish::resize()
{
    m_fishRadius = qMin(width(), height()) / 10.0;
    m_finLen = m_fishRadius * 1.3;
    m_bodyHeight = m_fishRadius * 3.2;
}

QPointF MagicFish::calcPoint(const QPointF &pos, qreal length, qreal angle)
{
    qreal delta_x = qCos(qDegreesToRadians(angle)) * length;
    qreal delta_y = qSin(qDegreesToRadians(angle - 180)) * length;
    return QPointF(pos + QPointF(delta_x, delta_y));
}

void MagicFish::paintMyPoint(QPainter *painter, const QPointF pos)
{
    if(m_paintPoint)
    {
        painter->save();
        painter->setPen(QPen(Qt::black, 3));
        painter->setBrush(QBrush(Qt::black));
        painter->drawPoint(pos);
        painter->restore();
    }
}

void MagicFish::paintMyFishFins(QPainter *painter, const QPointF &pos, bool is_left, qreal father_angle)
{
    qreal contral_angle = 115;
    qreal fin_angle = m_startFin ? qSin(qDegreesToRadians(m_curValue * 16.1 * m_wave)) * 12.0 : 2;
    QPainterPath path;
    path.moveTo(pos);
    QPointF end_pos = calcPoint(pos, m_finLen, is_left ? father_angle + fin_angle + 180 :
                                                           father_angle - fin_angle - 180);
    QPointF control_pos = calcPoint(pos, m_finLen * 1.8, is_left ?
                                    father_angle + contral_angle + fin_angle :
                                    father_angle - contral_angle - fin_angle);

    path.quadTo(control_pos, end_pos);
    path.lineTo(pos);

    painter->save();
    painter->setBrush(QBrush(QColor(244, 92, 71, M_finAlpha)));
    painter->drawPath(path);
    painter->restore();
}

void MagicFish::paintMyBody(QPainter *painter, const QPointF &pos, qreal seg_r, qreal MP, qreal father_angle)
{
    qreal angle = father_angle + qCos(qDegreesToRadians(m_curValue * 1.5 * m_wave)) * 15;
    qreal length = seg_r * (MP + 1);
    QPointF end_pos = calcPoint(pos, length, angle - 180);

    QPointF pos1 = calcPoint(pos, seg_r, angle - 90);
    QPointF pos2 = calcPoint(end_pos, seg_r * MP, angle - 90);
    QPointF pos3 = calcPoint(end_pos, seg_r * MP, angle + 90);
    QPointF pos4 = calcPoint(pos, seg_r, angle + 90);

    painter->save();
    painter->setBrush(QBrush(QColor(244, 92, 71, m_headAlpha)));
    painter->drawEllipse(pos, seg_r, seg_r);
    painter->drawEllipse(end_pos, seg_r * MP, seg_r * MP);

    QPainterPath path;
    path.moveTo(pos1);
    path.lineTo(pos2);
    path.lineTo(pos3);
    path.lineTo(pos4);
    painter->drawPath(path);
    painter->restore();
    paintMyBody2(painter, end_pos, seg_r * 0.6, 0.4, angle);
}

void MagicFish::paintMyBody2(QPainter *painter, const QPointF &pos, qreal seg_r, qreal MP, qreal father_angle)
{
    qreal angle = father_angle + qSin(qDegreesToRadians(m_curValue * 1.5 * m_wave)) * 35;
    qreal length = seg_r * (MP + 2.7);
    QPointF end_pos = calcPoint(pos, length, angle - 180);

    QPointF pos1 = calcPoint(pos, seg_r, angle - 90);
    QPointF pos2 = calcPoint(end_pos, seg_r * MP, angle - 90);
    QPointF pos3 = calcPoint(end_pos, seg_r * MP, angle + 90);
    QPointF pos4 = calcPoint(pos, seg_r, angle + 90);
    paintMyTail(painter, pos, length, seg_r, angle);

    painter->save();
    painter->setBrush(QBrush(QColor(244, 92, 71, m_headAlpha)));
    painter->drawEllipse(end_pos, seg_r * MP, seg_r * MP);

    QPainterPath path;
    path.moveTo(pos1);
    path.lineTo(pos2);
    path.lineTo(pos3);
    path.lineTo(pos4);
    painter->drawPath(path);
    painter->restore();
}

void MagicFish::paintMyTail(QPainter *painter, const QPointF &pos, qreal length, qreal max_w, qreal angle)
{
    qreal w = qAbs(qSin(qDegreesToRadians(m_curValue * 1.7 * m_wave)) * max_w + m_fishRadius / 5.0 * 3.0);
    QPointF end_point1 = calcPoint(pos, length, angle - 180);
    QPointF end_point2 = calcPoint(pos, length - 10, angle - 180);

    QPointF pos1 = calcPoint(end_point1, w, angle - 90);
    QPointF pos2 = calcPoint(end_point1, w, angle + 90);
    QPointF pos3 = calcPoint(end_point2, w - m_fishRadius / 1.5, angle - 90);
    QPointF pos4 = calcPoint(end_point2, w - m_fishRadius / 1.5, angle + 90);

    QPainterPath path;
    path.moveTo(pos);
    path.lineTo(pos3);
    path.lineTo(pos4);
    path.lineTo(pos);
    painter->save();
    painter->setBrush(QBrush(QColor(244, 92, 71,     m_headAlpha)));
    painter->drawPath(path);

    path.closeSubpath();
    path.moveTo(pos);
    path.lineTo(pos1);
    path.lineTo(pos2);
    path.lineTo(pos);
    painter->drawPath(path);
    painter->restore();
}

void MagicFish::setWave(qreal value)
{
    m_wave = value;
}

qreal MagicFish::getFishR() const
{
    return m_fishRadius;
}

qreal MagicFish::getAngle()
{
    return m_mainAngle;
}

QRectF MagicFish::geometry() const
{
    return QRectF(x(), y(), width(), height());
}

QPointF MagicFish::getHeadPos() const
{
    return m_headPos;
}

void MagicFish::setCurrentAngle(qreal angle)
{
    m_mainAngle = angle;
    update();
}

void MagicFish::setFinAnimation(bool start)
{
    m_startFin = start;
}

void MagicFish::setFishR(int value)
{
    m_fishRadius = value;
    m_finLen = value * 1.3;
    m_bodyHeight = value * 3.2;
    update();
}

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1632315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么设置 idea terminal 窗口的编码格式

1 修改Terminal 窗口为 Git bash 窗口 打开 settings 设置界面&#xff0c;选择 Tools 中的 Terminal (File -> settings -> Tools -> Terminal) 修改 Shell path 为你的 Git bash 安装路径&#xff0c;我的在 C:\my_software\java\Git\bin\bash.exe 2 解决中文显示…

【UE5】数字人基础

这里主要记录一下自己在实现数字人得过程中涉及导XSens惯性动捕&#xff0c;视频动捕&#xff0c;LiveLinkFace表捕&#xff0c;GRoom物理头发等。 一、导入骨骼网格体 骨骼网格体即模型要在模型雕刻阶段就要雕刻好表捕所需的表情体(blendshape)&#xff0c;后面表捕的效果直…

干货满满,Apollo7周年大会的心得体会

在云计算、人工智能、大数据等技术的助力下&#xff0c;自动驾驶已成为现代科技的一个标志性领域。 Apollo是一个开放、完整、安全的自动驾驶平台&#xff0c;助力开发者快速搭建自动驾驶系统。 Apollo开放平台自诞生以来&#xff0c;就扮演着这一领域的引领者角色。而今&…

Zynq 7000 系列之启动模式—Quad-SPI启动

Quad-SPI启动是一种高效的闪存启动方式&#xff0c;它利用Quad-SPI接口的高速数据传输能力来加速启动过程。Quad-SPI&#xff08;四路串行外设接口&#xff09;是一种改进的SPI&#xff08;串行外设接口&#xff09;协议&#xff0c;通过使用四条数据线而不是传统的单条数据线&…

Typora配置PicGo图床,将图片文件上传到gitee厂库,获取图片链接显示在md文件中

Typora配置PicGo图床&#xff0c;将图片文件上传到gitee厂库&#xff0c;获取图片链接显示在md文件中 创建Gitee创库和配置私人令牌 名字、路径、描述自己随便添&#xff0c;但是必须开源&#xff0c;链接才能可以访问&#xff1a; 进入偏好设置 > 图像 > 选择PicGo-Cor…

基于java+springboot+vue实现的物流管理系统(文末源码+Lw)208

摘 要 社会发展日新月异&#xff0c;用计算机应用实现数据管理功能已经算是很完善的了&#xff0c;但是随着移动互联网的到来&#xff0c;处理信息不再受制于地理位置的限制&#xff0c;处理信息及时高效&#xff0c;备受人们的喜爱。本次开发一套物流管理系统有管理员和用户…

Windows使用bat远程操作Linux并执行命令

背景&#xff1a;让客户可以简单在Windows中能自己执行 Linux中的脚本&#xff0c;傻瓜式操作&#xff01; 方法&#xff1a;做一个简单的bat脚本&#xff01;能远程连接到Linux&#xff0c;并执行Linux命令&#xff01;客户双击就能使用&#xff01; 1、原先上网查询到使用P…

大厂常见算法50题-替换空格

专栏持续更新50道算法题&#xff0c;都是大厂高频算法题&#xff0c;建议关注, 一起巧‘背’算法! 文章目录 题目解法一 String类replace方法解法二 遍历替换总结 题目 解法一 String类replace方法 String类自带的replace&#xff0c;方法传入两个char类型的参数&#xff0c;分…

Pixelmator Pro for Mac:简洁而强大的图像编辑软件

Pixelmator Pro for Mac是一款专为Mac用户设计的图像编辑软件&#xff0c;它集简洁的操作界面与强大的功能于一身&#xff0c;为用户提供了卓越的图像编辑体验。 Pixelmator Pro for Mac v3.5.9中文激活版下载 该软件支持多种文件格式&#xff0c;包括常见的JPEG、PNG、TIFF等&…

Gromacs——教程学习(6)

谈谈怎么判断分子动力学模拟是否达到了平衡 在计算RMSD之前必须先通过最小二乘法将各帧结构相对于参考结构进行最大程度叠合&#xff0c;从而消除体系的整体运动而令RMSD只体现生物分子内部结构的变化&#xff0c;这称为align或者least squares fit。 需要注意的是&#xff0…

Rundeck(四)安全配置

自动化运维工具rundeck GitHub - rundeck 是java开发的开源自动化服务&#xff0c;具有 Web 控制台、命令行工具和 WebAPI。它使您可以轻松地跨一组节点运行自动化任务&#xff0c;适合运维自动化管理、自动发布管理、运维数据分析等 网站&#xff1a;https://www.rundeck.co…

【golang-ent】go-zero框架 整合 ent orm框架实现一对一 一对多 多种姿势查询方式

一、ent的 O2O 问题 官方文档如下: https://entgo.io/zh/docs/schema-edges#o2o-same-type 1、ent O2O问题 官方提供了三种 one2one的方式,可以看到他全部使用了 mysql的 foregionKey 的方式进行关联,虽然举例了单表和双表的不同使用方式,但是我们实际使用mysql中是不创建…

flutter笔记-webrtc使用1:依赖本地包socket.io-client

文章目录 1. 示例工程2. yaml 修改3. 使用4. socketio 关于自定义服务器自定义签名的问题封装成async和await方式 本文开始介绍webrtc的使用&#xff0c;阅读本文的前提是假设你已经使用过webrtc&#xff0c;了解webrtc的交互机制&#xff0c;不了解的可以看之前的文章&#xf…

【Python】全面掌握 Collections Deque:队列与栈的高效实现及动态内存管理指南

文章目录 第一章&#xff1a;deque 的定义和特性1. 什么是双端队列&#xff08;deque&#xff09;2. deque 与普通列表&#xff08;list&#xff09;的性能差异 第二章&#xff1a;构造函数1. 如何创建一个 deque2. 可选参数 maxlen 的作用和使用场景 第三章&#xff1a;添加和…

信息泄露后担心被恶意点了网贷怎么办?

在当今信息时代&#xff0c;个人信息泄露已成为一个普遍现象&#xff0c;而泄露的信息可能被不法分子用于进行恶意行为&#xff0c;如恶意申贷。一旦被恶意申贷&#xff0c;可能会导致信用受损、法律责任等一系列问题。那么&#xff0c;信息泄露后担心被恶意申贷了怎么办呢?本…

金三银四面试题(二十三):装饰器模式知多少?

什么是装饰器模式 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许动态地向对象添加新的行为&#xff0c;而无需修改原始对象的结构。通过将对象包装在一个或多个装饰器对象中&#xff0c;装饰器模式可以增强原始对象的功能。 装…

Swift - 枚举

文章目录 Swift - 枚举1. 枚举的基本用法2. 关联值&#xff08;Associated Values&#xff09;3. 关联值举例4. 原始值5. 隐式原始值&#xff08;Implicitly Assigned Raw Values&#xff09;6. 递归枚举&#xff08;Recursive Enumeration&#xff09;7. MemoryLayout Swift -…

ESP32-C3第二路串口(非调试)串口打通(2)

接前一篇文章&#xff1a;ESP32-C3第二路串口&#xff08;非调试&#xff09;串口打通&#xff08;1&#xff09; 本文内容参考&#xff1a; ESP32爬坑之旅②——初识FreeRTOS_esp32 xtaskcreate-CSDN博客 特此致谢&#xff01; 上一回讲解了ESP32-C3系列芯片UART引脚复用的细…

安卓常用组件(启停活动页面、活动之间传递信息、收发应用广播、操作后台服务)

启停活动页面 Activity的启动和结束 页面跳转可以使用startActivity接口&#xff0c;具体格式为startActivity(new Intent(this, 目标页面.class));。 关闭一个页面可以直接调用finish();方法即可退出页面。 Activity的生命周期 页面在安卓有个新的名字叫活动&#xff0c;因…

指导网友完成一起Linux服务器系统文件删除导致不能启动情况下的数据恢复案例

昨日有网友在微信群发起救助&#xff0c;Linux系统不能启动&#xff0c;使用救援U盘也无法恢复&#xff0c;协助他进行了数据恢复&#xff0c;本文记录了处置过程。 图片为网友提供&#xff0c;照得歪歪扭扭的&#xff0c;将就着看看吧。 一、问题现象 1、报错信息 Linux服…