前言
上次发了个纯 painter 绘制的老鼠, 那个就是 qt 目录下的 demo, 改的, 只是比 demo 中的老鼠稍微胖一点, 估计人到中年都发福吧. 这次来一个魔法小鱼, 这条鱼可以变换颜色, 尾巴还会摇动, 可以设定旋转的角度以及尾巴摆动的幅度等, 原理是参考网上一个安卓大神写的(绘制原理 https://www.jianshu.com/p/3dd3d1524851 ).
其实在 Qt 学习过程中, 如果越到问题找不到相关文章和答案, 可以试着将关键字改成安卓试试, 你会发现另外一篇天地, 大量的资源和文章介绍等, 就比如安卓中用的 java 的 painter, 就几乎和 Qt 中的一样, 估计填写编程语言都很类似, 连方法名字几乎都是一样, 设置参数, 具有很多通用性, 作为一名程序员, 最重要的是理解思路和原理, 甚至学习的方法, 这些掌握了, 任何语言都不是问题.
实现的功能
魔幻鱼控件 作者: feiyangqingyun(QQ:517216493) 2018-7-15
- #ifndef MAGICFISH_H
- #define MAGICFISH_H
- /**
- * 魔幻鱼控件 作者: feiyangqingyun(QQ:517216493) 2018-7-15
- * 本控件来源于网络(原作者: tyroneli(http://www.qtcn.org/bbs/read-htm-tid-65412.html))
- * 绘制原理 https://www.jianshu.com/p/3dd3d1524851
- * 1: 可设置鱼头 + 鱼身 + 鱼鳍 + 鱼尾的颜色
- * 2: 可设置鱼头 + 鱼身 + 鱼鳍 + 鱼尾的比例
- * 3: 可设置基准颜色, 作为所有统一颜色
- * 4: 可设置鱼鳍是否摆动
- * 5: 可设置鱼的停留位置旋转角度
- */
- #include <QWidget>
- #ifdef quc
- #if (QT_VERSION <QT_VERSION_CHECK(5,7,0))
- #include <QtDesigner/QDesignerExportWidget>
- #else
- #include <QtUiPlugin/QDesignerExportWidget>
- #endif
- class QDESIGNER_WIDGET_EXPORT MagicFish : public QWidget
- #else
- class MagicFish : public QWidget
- #endif
- {
- Q_OBJECT
- Q_PROPERTY(QColor headColor READ getHeadColor WRITE setHeadColor)
- Q_PROPERTY(QColor bodyColor READ getBodyColor WRITE setBodyColor)
- Q_PROPERTY(QColor finColor READ getFinColor WRITE setFinColor)
- Q_PROPERTY(QColor tailColor READ getTailColor WRITE setTailColor)
- Q_PROPERTY(QColor baseColor READ getBaseColor WRITE setBaseColor)
- Q_PROPERTY(bool finMove READ getFinMove WRITE setFinMove)
- Q_PROPERTY(int speed READ getSpeed WRITE setSpeed)
- Q_PROPERTY(double wave READ getWave WRITE setWave)
- Q_PROPERTY(double currentAngle READ getCurrentAngle WRITE setCurrentAngle)
- public:
- explicit MagicFish(QWidget *parent = 0);
- ~MagicFish();
- protected:
- void resizeEvent(QResizeEvent *);
- void paintEvent(QPaintEvent *);
- void drawHead(QPainter *painter);
- void drawBody(QPainter *painter, const QPointF &pos, double angle);
- void drawFin(QPainter *painter, const QPointF &pos, bool left, double angle);
- void drawTail(QPainter *painter, const QPointF &pos, double angle);
- void drawTail1(QPainter *painter, const QPointF &pos, double angle);
- void drawTail2(QPainter *painter, const QPointF &pos, double angle);
- private:
- // 计算坐标点
- QPointF calcPoint(const QPointF &pos, double len, double angle);
- double qDegreesToRadians(double degrees);
- double qRadiansToDegrees(double radians);
- private:
- QColor headColor; // 鱼头颜色
- QColor bodyColor; // 鱼身颜色
- QColor finColor; // 鱼鳍颜色
- QColor tailColor; // 鱼尾颜色
- QColor baseColor; // 基准颜色
- bool finMove; // 鱼鳍是否摆动
- int speed; // 游动的速度即尾巴摆动的频率
- double wave; // 晃动的幅度
- double currentAngle; // 旋转的角度
- int currentValue; // 游动的位置
- double headLen; // 鱼头尺寸
- double bodyLen; // 鱼身尺寸
- double finLen; // 鱼鳍尺寸
- double tailLen; // 鱼尾尺寸
- QPointF headPos; // 鱼头坐标
- QTimer *timer; // 定时器处理游动
- public:
- QColor getHeadColor() const;
- QColor getBodyColor() const;
- QColor getFinColor() const;
- QColor getTailColor() const;
- QColor getBaseColor() const;
- bool getFinMove() const;
- int getSpeed() const;
- double getWave() const;
- double getCurrentAngle() const;
- double getHeadLen() const;
- QPointF getHeadPos() const;
- QSize sizeHint() const;
- QSize minimumSizeHint() const;
- private slots:
- void updateValue();
- public slots:
- // 设置鱼头颜色
- void setHeadColor(const QColor &headColor);
- // 设置鱼身颜色
- void setBodyColor(const QColor &bodyColor);
- // 设置鱼鳍颜色
- void setFinColor(const QColor &finColor);
- // 设置鱼尾颜色
- void setTailColor(const QColor &tailColor);
- // 设置基准颜色
- void setBaseColor(const QColor &baseColor);
- // 设置鱼鳍是否摆动
- void setFinMove(bool finMove);
- // 设置游动的速度
- void setSpeed(int speed);
- // 设置滑动的幅度
- void setWave(double wave);
- // 设置当前旋转的角度
- void setCurrentAngle(double currentAngle);
- void setCurrentAngle(int currentAngle);
- // 设置头部的长度
- void setHeadLen(int headLen);
- };
- #endif // MAGICFISH_H
- #pragma execution_character_set("utf-8")
- #include "magicfish.h"
- #include "qpainter.h"
- #include "qmath.h"
- #include "qtimer.h"
- #include "qdebug.h"
- MagicFish::MagicFish(QWidget *parent) : QWidget(parent)
- {
- headColor = QColor(244, 92, 71, 200);
- bodyColor = QColor(244, 92, 71, 220);
- finColor = QColor(244, 92, 71, 150);
- tailColor = QColor(244, 92, 71, 180);
- baseColor = QColor(244, 92, 71);
- finMove = false;
- speed = 30;
- wave = 1.0;
- currentAngle = 0.0;
- currentValue = 0;
- headLen = 10;
- finLen = headLen * 1.8;
- bodyLen = headLen * 5.2;
- tailLen = headLen * 0.8;
- timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), this, SLOT(updateValue()));
- timer->start(100);
- }
- MagicFish::~MagicFish()
- {
- if (timer->isActive()) {
- timer->stop();
- }
- }
- void MagicFish::resizeEvent(QResizeEvent *)
- {
- headLen = qMin(width(), height()) / 10.0;
- bodyLen = headLen * 5.2;
- finLen = headLen * 1.8;
- tailLen = headLen * 0.8;
- }
- void MagicFish::paintEvent(QPaintEvent *)
- {
- // 绘制准备工作, 启用反锯齿
- QPainter painter(this);
- painter.setRenderHint(QPainter::Antialiasing);
- QPointF middlePos = QPointF(width() / 2, height() / 2);
- headPos = calcPoint(middlePos, bodyLen / 1.5, currentAngle);
- double angle = currentAngle + qSin(qDegreesToRadians(currentValue * 1.2 * wave)) * 2;
- QPointF pos = calcPoint(headPos, bodyLen, angle - 180);
- // 绘制头部
- drawHead(&painter);
- // 绘制鱼身
- drawBody(&painter, pos, angle);
- // 绘制左侧鱼鳍
- QPointF leftPos = calcPoint(headPos, headLen * 0.9, angle + 110);
- drawFin(&painter, leftPos, true, angle);
- // 绘制右侧鱼鳍
- QPointF rightPos = calcPoint(headPos, headLen * 0.9, angle - 110);
- drawFin(&painter, rightPos, false, angle);
- // 绘制鱼尾
- drawTail(&painter, pos, angle);
- }
- void MagicFish::drawHead(QPainter *painter)
- {
- painter->save();
- painter->setPen(Qt::NoPen);
- painter->setBrush(headColor);
- // 鱼头关节圆
- painter->drawEllipse(headPos, headLen, headLen);
- painter->restore();
- }
- void MagicFish::drawBody(QPainter *painter, const QPointF &pos, double angle)
- {
- // 计算身体部分四个点
- QPointF pos1 = calcPoint(headPos, headLen, angle - 80);
- QPointF pos2 = calcPoint(pos, headLen * 0.8, angle - 90);
- QPointF pos3 = calcPoint(pos, headLen * 0.8, angle + 90);
- QPointF pos4 = calcPoint(headPos, headLen, angle + 80);
- QPointF leftPos = calcPoint(headPos, bodyLen * 0.56, angle - 130);
- QPointF rightPos = calcPoint(headPos, bodyLen * 0.56, angle + 130);
- // 计算绘制路径
- QPainterPath path;
- path.moveTo(pos1);
- path.quadTo(leftPos, pos2);
- path.lineTo(pos3);
- path.quadTo(rightPos, pos4);
- path.lineTo(pos1);
- painter->save();
- painter->setPen(Qt::NoPen);
- painter->setBrush(bodyColor);
- painter->drawPath(path);
- painter->restore();
- }
- void MagicFish::drawFin(QPainter *painter, const QPointF &pos, bool left, double angle)
- {
- double controlAngle = 115;
- double finAngle = finMove ? qSin(qDegreesToRadians(currentValue * 16.1 * wave)) * 12.0 : 2;
- QPointF endPos = calcPoint(pos, finLen, left ? angle + finAngle + 180 : angle - finAngle - 180);
- QPointF controlPos = calcPoint(pos, finLen * 1.8, left ? angle + controlAngle + finAngle : angle - controlAngle - finAngle);
- // 计算鱼鳍的路径
- QPainterPath path;
- path.moveTo(pos);
- path.quadTo(controlPos, endPos);
- path.lineTo(pos);
- painter->save();
- painter->setPen(Qt::NoPen);
- painter->setBrush(finColor);
- painter->drawPath(path);
- painter->restore();
- }
- void MagicFish::drawTail(QPainter *painter, const QPointF &pos, double angle)
- {
- double flag = 0.6;
- double length = tailLen * (flag + 1);
- double tailAngle = angle + qCos(qDegreesToRadians(currentValue * 1.5 * wave)) * 15;
- QPointF endPos = calcPoint(pos, length, tailAngle - 180);
- QPointF pos1 = calcPoint(pos, tailLen, tailAngle - 90);
- QPointF pos2 = calcPoint(endPos, tailLen * flag, tailAngle - 90);
- QPointF pos3 = calcPoint(endPos, tailLen * flag, tailAngle + 90);
- QPointF pos4 = calcPoint(pos, tailLen, tailAngle + 90);
- QPainterPath path;
- path.moveTo(pos1);
- path.lineTo(pos2);
- path.lineTo(pos3);
- path.lineTo(pos4);
- painter->save();
- painter->setPen(Qt::NoPen);
- painter->setBrush(tailColor);
- // 鱼尾关节大圆
- painter->drawEllipse(pos, tailLen, tailLen);
- // 鱼尾关节小圆
- painter->drawEllipse(endPos, tailLen * flag, tailLen * flag);
- // 鱼尾肉部分路径
- painter->drawPath(path);
- painter->restore();
- // 绘制鱼尾关节
- drawTail1(painter, endPos, tailAngle);
- }
- void MagicFish::drawTail1(QPainter *painter, const QPointF &pos, double angle)
- {
- double len = tailLen * 0.6;
- double flag = 0.4;
- double length = len * (flag + 2.7);
- double tailAngle = angle + qSin(qDegreesToRadians(currentValue * 1.7 * wave)) * 35;
- QPointF endPos = calcPoint(pos, length, tailAngle - 180);
- QPointF pos1 = calcPoint(pos, len, tailAngle - 90);
- QPointF pos2 = calcPoint(endPos, len * flag, tailAngle - 90);
- QPointF pos3 = calcPoint(endPos, len * flag, tailAngle + 90);
- QPointF pos4 = calcPoint(pos, len, tailAngle + 90);
- QPainterPath path;
- path.moveTo(pos1);
- path.lineTo(pos2);
- path.lineTo(pos3);
- path.lineTo(pos4);
- painter->save();
- painter->setPen(Qt::NoPen);
- painter->setBrush(tailColor);
- painter->drawPath(path);
- painter->restore();
- // 绘制鱼尾鱼鳍
- drawTail2(painter, pos, tailAngle);
- }
- void MagicFish::drawTail2(QPainter *painter, const QPointF &pos, double angle)
- {
- double len = tailLen * 0.6;
- double flag = 0.4;
- double length = len * (flag + 2.7);
- double tailWidth = qAbs(qSin(qDegreesToRadians(currentValue * 1.9 * wave)) * len + headLen / 5.0 * 3.0);
- QPointF endPos1 = calcPoint(pos, length, angle - 180);
- QPointF endPos2 = calcPoint(pos, length - 10, angle - 180);
- QPointF pos1 = calcPoint(endPos1, tailWidth, angle - 90);
- QPointF pos2 = calcPoint(endPos1, tailWidth, angle + 90);
- QPointF pos3 = calcPoint(endPos2, tailWidth - headLen / 1.5, angle - 90);
- QPointF pos4 = calcPoint(endPos2, tailWidth - headLen / 1.5, angle + 90);
- QPainterPath path1;
- path1.moveTo(pos);
- path1.lineTo(pos3);
- path1.lineTo(pos4);
- path1.lineTo(pos);
- QPainterPath path2;
- path2.moveTo(pos);
- path2.lineTo(pos1);
- path2.lineTo(pos2);
- path2.lineTo(pos);
- painter->save();
- painter->setPen(Qt::NoPen);
- painter->setBrush(tailColor);
- painter->drawPath(path1);
- painter->drawPath(path2);
- painter->restore();
- }
- QPointF MagicFish::calcPoint(const QPointF &pos, double len, double angle)
- {
- double x = qCos(qDegreesToRadians(angle)) * len;
- double y = qSin(qDegreesToRadians(angle - 180)) * len;
- return QPointF(pos + QPointF(x, y));
- }
- double MagicFish::qDegreesToRadians(double degrees)
- {
- return degrees * double(M_PI / 180);
- }
- double MagicFish::qRadiansToDegrees(double radians)
- {
- return radians * double(180 / M_PI);
- }
- void MagicFish::updateValue()
- {
- // 值会一直递增, 需要判断是否越界
- if (currentValue>= (INT_MAX - speed)) {
- currentValue = 0;
- }
- currentValue = (currentValue + speed) % 54000;
- update();
- }
- QColor MagicFish::getHeadColor() const
- {
- return this->headColor;
- }
- QColor MagicFish::getBodyColor() const
- {
- return this->bodyColor;
- }
- QColor MagicFish::getFinColor() const
- {
- return this->finColor;
- }
- QColor MagicFish::getTailColor() const
- {
- return this->tailColor;
- }
- QColor MagicFish::getBaseColor() const
- {
- return this->baseColor;
- }
- bool MagicFish::getFinMove() const
- {
- return this->finMove;
- }
- int MagicFish::getSpeed() const
- {
- return this->speed;
- }
- double MagicFish::getWave() const
- {
- return this->wave;
- }
- double MagicFish::getCurrentAngle() const
- {
- return this->currentAngle;
- }
- double MagicFish::getHeadLen() const
- {
- return this->headLen;
- }
- QPointF MagicFish::getHeadPos() const
- {
- return this->headPos;
- }
- QSize MagicFish::sizeHint() const
- {
- return QSize(200, 200);
- }
- QSize MagicFish::minimumSizeHint() const
- {
- return QSize(20, 20);
- }
- void MagicFish::setHeadColor(const QColor &headColor)
- {
- if (this->headColor != headColor) {
- this->headColor = headColor;
- update();
- }
- }
- void MagicFish::setBodyColor(const QColor &bodyColor)
- {
- if (this->bodyColor != bodyColor) {
- this->bodyColor = bodyColor;
- update();
- }
- }
- void MagicFish::setFinColor(const QColor &finColor)
- {
- if (this->finColor != finColor) {
- this->finColor = finColor;
- update();
- }
- }
- void MagicFish::setTailColor(const QColor &tailColor)
- {
- if (this->tailColor != tailColor) {
- this->tailColor = tailColor;
- update();
- }
- }
- void MagicFish::setBaseColor(const QColor &baseColor)
- {
- if (this->baseColor != baseColor) {
- this->baseColor = baseColor;
- // 根据基准颜色设置其他颜色
- this->baseColor.setAlpha(200);
- headColor = this->baseColor;
- this->baseColor.setAlpha(220);
- bodyColor = this->baseColor;
- this->baseColor.setAlpha(150);
- finColor = this->baseColor;
- this->baseColor.setAlpha(180);
- tailColor = this->baseColor;
- update();
- }
- }
- void MagicFish::setFinMove(bool finMove)
- {
- if (this->finMove != finMove) {
- this->finMove = finMove;
- update();
- }
- }
- void MagicFish::setSpeed(int speed)
- {
- if (this->speed != speed) {
- this->speed = speed;
- update();
- }
- }
- void MagicFish::setWave(double wave)
- {
- if (this->wave != wave) {
- this->wave = wave;
- update();
- }
- }
- void MagicFish::setCurrentAngle(double currentAngle)
- {
- if (this->currentAngle != currentAngle) {
- this->currentAngle = currentAngle;
- update();
- }
- }
- void MagicFish::setCurrentAngle(int currentAngle)
- {
- setCurrentAngle((double)currentAngle);
- }
- void MagicFish::setHeadLen(int headLen)
- {
- if (this->headLen != headLen) {
- this->headLen = headLen;
- this->finLen = headLen * 1.8;
- this->bodyLen = headLen * 5.2;
- this->tailLen = headLen * 0.8;
- update();
- }
- }
来源: http://www.bubuko.com/infodetail-3053070.html