相随与欢
大一下-面向对象课程设计-彩色泡泡机题目详解
与欢行
一、题目与需求分析:
基于Qt框架的GUI设计与实现
需求:
1、绘制泡泡(颜色、大小等配置信息随机产生)
2、点击游戏区域即可产生泡泡。
3、泡泡会向上漂浮离开(速度随机)。
二、具体实现:
A、泡泡绘制类Bubble的设计
bubble.h
#ifndef BUBBLE_H
#define BUBBLE_H
//本类为泡泡的实现类
//采用面向对象思想设计泡泡类并通过具体算法设计将其实现
//2021/6/17 行
//For 欢
//不辞青山,相随与共
#include <QWidget>
#include<QMouseEvent> //鼠标事件类头文件
#include<QPainter> //绘图工具头文件
#include<QPaintEvent> //绘图事件头文件
#include<QPropertyAnimation> //属性动画头文件 property:属性
#include<QDebug> //调试输出信息库
#include <QTime> //随机数强依赖库
QT_BEGIN_NAMESPACE
namespace Ui { class Bubble; }
QT_END_NAMESPACE
class Bubble : public QWidget
{
Q_OBJECT
public:
Bubble(int newR,int newX,int newY,QWidget *parent = nullptr); //参数分别为:
~Bubble();
void setColor(QColor color); //颜色设置接口
void paintEvent(QPaintEvent *event); //绘制事件 泡泡的主要绘制算法实现在此
void own_show();
private:
Ui::Bubble *ui;
QPropertyAnimation *BubbleAnimation; //数据成员 指针 对象 属性动画类 对象指针 泡泡的漂浮动画
int x; //泡泡的X坐标 鼠标点击位置的横坐标 event->pos().x()
int y; //泡泡的Y坐标
int radius; //半径 通过随机数产生 //泡泡的半径
QColor m_bubbleColor; //泡泡的颜色 随机设置RGB通道值
};
#endif // BUBBLE_H
bubble.cpp
#include "bubble.h"
#include "ui_bubble.h"
//通过参数列表进行初始化
//常数据成员必须通过参数列表进行初始化
Bubble::Bubble(int newR,int newX,int newY,QWidget *parent) //构造函数 构造泡泡图形
: QWidget(parent)
, ui(new Ui::Bubble)
,x(newX)
,y(newY)
,radius(newR)
{
ui->setupUi(this); //自带的 初始化UI
//通过调整窗体属性
//this即当前的对象自身 而当前这个对象本质上是一个widget 是一个页面 通过进行相关参数的调节 将其变为泡泡‘
//setFixedSize() 设置窗口固定大小
this->setFixedSize(QSize(80, 80)); //设置固定的大小 泡泡的最大值
//setWindowFlags 设置窗口属性
//Qt::FramelessWindowHint无边框化,移动,大小调整
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); //设置窗口标志 不带标题栏边框
//setAttribute 设置窗体属性 Qt::WA_TranslucentBackground使其透明
this->setAttribute(Qt::WA_TranslucentBackground); //使窗体透明
// 控件显示完关闭后自动删除;
//this->setAttribute(Qt::WA_DeleteOnClose); //用于设置各种窗口小部件(widget)的属性。
//参数解释:动画作用的对象 动画涉及更改的属性 pos:position 位置
this->BubbleAnimation = new QPropertyAnimation(this, "pos"); //初始化动画成员
}
Bubble::~Bubble() //析构函数
{
delete ui;
}
void Bubble::setColor(QColor color) //颜色更改成员函数
{
this->m_bubbleColor=color; //QColor为颜色对象 可以通过RGB/HSV 规则值进行设置
}
//绘制泡泡的图案 画画函数
void Bubble::paintEvent(QPaintEvent *event) //绘图事件函数 在构造本类对象时自动调用 用于图形的绘制
{
//画画需要工具(笔和画刷) 笔用于勾勒线条 画刷用于上色 同时还要知道画布是什么
//QPainter 画笔名(绘图位置)
QPainter painter(this); //Qpainter是一个绘图工具 相当于画笔/画刷
painter.setRenderHint(QPainter::Antialiasing); //这一句是固定用法 用于图形反走样、抗锯齿 百度查到的
//void QPainter::setPen ( const QPen & pen )
//设置新的绘图工具画笔。
//pen定义了如何绘制线和轮廓,并且它也定义了文本颜色。
painter.setPen(QPen(m_bubbleColor,10)); //设置画笔 如果是NoPen的话 绘制出来的图案没有边框(界) 勾勒
//void QPainter::setBrush ( BrushStyle style )
//设置绘图工具的画刷为黑色和特定的style。
//painter.setBrush(QBrush(m_bubbleColor)); //设置画刷 为画刷设置颜色 用于给泡泡上色 色彩通过随机的RGB通道值实现
//联想笔画 写一个字是不是需要笔画和顺序
//QPainterPath 类(绘图路径)提供了一个容器,用于绘图操作,可以创建和重用图形形状。
QPainterPath bubblePath; //泡泡绘制路径
//path.drawEllipse(x, y, r, r);
//Ellipse 椭圆(圆)
bubblePath.addEllipse(QPoint(40, 40), radius, radius); //将一个圆形添加到绘图路径中
painter.drawPath(bubblePath); //绘制图形路径
}
//自己的show方法
void Bubble::own_show()
{
QWidget::show();
QTime time;
time= QTime::currentTime();
qsrand(time.msec()+time.second()*1000);
int v = 2000+qrand() % 3000; //随机速度
int exc_x = 200+qrand() % 700; //随机速度
int control = qrand() % 2; //控制模式
this->BubbleAnimation->setDuration(v); //设置动画持续时长 参数为一个整形数据 时长随机 时长相当于速度
this->BubbleAnimation->setStartValue(QPoint(x, y));
if(control==0)
{
qDebug()<<"模式0向上漂浮";
this->BubbleAnimation->setEndValue(QPoint(x+exc_x, -1000)); //设置结束位置 两点确定一线嘛
}
else if(control==1)
{
qDebug()<<"模式1向下漂浮";
this->BubbleAnimation->setEndValue(QPoint(x-exc_x, 2000)); //设置结束位置 两点确定一线嘛
}
//设置动画的初始值 由于是一个属性动画 更改的是pos(位置)属性 所以初始值应该是位置(坐标) QPoint
// this->BubbleAnimation->setEndValue(QPoint(x+200, -500)); //设置结束位置 两点确定一线嘛
BubbleAnimation->setEasingCurve(QEasingCurve::InOutQuad); //这个属性保留了动画的缓和曲线 文档看到的
this->BubbleAnimation->start(); //动画开始
}
B、游戏界面game类的设计与实现
game.h
#ifndef GAME_H
#define GAME_H
#include <QWidget>
#include<QMouseEvent>
#include"bubble.h"
namespace Ui {
class Game;
}
class Game : public QWidget
{
Q_OBJECT
public:
explicit Game(QWidget *parent = nullptr);
~Game();
void mousePressEvent(QMouseEvent *event); //鼠标事件
private:
Ui::Game *ui;
};
#endif // GAME_H
game.cpp
#include "game.h"
#include "ui_game.h"
Game::Game(QWidget *parent) :
QWidget(parent),
ui(new Ui::Game)
{
ui->setupUi(this);
}
Game::~Game()
{
delete ui;
}
void Game::mousePressEvent(QMouseEvent *event)
{
QPoint Pos = event->pos(); //显示鼠标点击的位置 以坐标形式呈现
qDebug() << "当前鼠标的位置:" << Pos; //输出鼠标所点击位置的坐标
//产生一堆随机数
QTime time;
time= QTime::currentTime();
qsrand(time.msec()+time.second()*1000);
int newR = 20+qrand() % 20; //产生40以内的随机数
int R = qrand() % 255; //产生255以内的随机数
int G = qrand() % 255; //产生255以内的随机数
int B = qrand() % 255; //产生255以内的随机数
//泡泡信息写入日志文件
QFile file;
file.setFileName("C:/Users/Administrator/Desktop/欢欢_彩色泡泡机/泡泡信息.txt");
QString colorInfo="颜色:RGB:("+QString::number(R)+","+QString::number(G)+","+QString::number(B)+")";
QString posInfo="坐标:("+QString::number(Pos.x())+QString::number(Pos.y())+")";
if(file.open(QIODevice::WriteOnly |QIODevice::Text | QIODevice::Append))
{
QTextStream stream(&file);
stream<<colorInfo<<endl;
stream<<posInfo<<endl;
stream<<endl;
file.close();
}
Bubble* paopao = new Bubble(newR,Pos.x(),Pos.y()); //动态申请一个泡泡对象
paopao->move(this->mapToGlobal(Pos)); //将泡泡移动到点击的位置
//paopao->move(Pos);
paopao->setColor(QColor(R,G,B)); //RGB数值设置颜色 同样采用随机数机制
paopao->own_show(); //展示 调用动画
}
三、核心功能具体实现解析
1、如何绘制泡泡?
首先,Qt中有一个绘图事件方法
virtual void QWidget::paintEvent ( QPaintEvent * )
该接口(方法)主要用于各种图形的绘制
a、paintEvent会在何时调用?
paintEvent函数执行:
1、在构建窗体的时候执行
2、在窗体update的时候执行
3、系统认为窗口需要重新绘制的时候执行
b、具体绘制实现
在bubble类中创建成员函数
void paintEvent(QPaintEvent *event); //绘制事件 泡泡的主要绘制算法实现在此
在源文件bubble.cpp中对其实现进行定义:
//绘制泡泡的图案 画画函数
void Bubble::paintEvent(QPaintEvent *event) //绘图事件函数 在构造本类对象时自动调用 用于图形的绘制
{
//画画需要工具(笔和画刷) 笔用于勾勒线条 画刷用于上色 同时还要知道画布是什么
//QPainter 画笔名(绘图位置)
QPainter painter(this); //Qpainter是一个绘图工具 相当于画笔/画刷
painter.setRenderHint(QPainter::Antialiasing); //这一句是固定用法 用于图形反走样、抗锯齿 百度查到的
//void QPainter::setPen ( const QPen & pen )
//设置新的绘图工具画笔。
//pen定义了如何绘制线和轮廓,并且它也定义了文本颜色。
painter.setPen(QPen(m_bubbleColor,10)); //设置画笔 如果是NoPen的话 绘制出来的图案没有边框(界) 勾勒
//void QPainter::setBrush ( BrushStyle style )
//设置绘图工具的画刷为黑色和特定的style。
//painter.setBrush(QBrush(m_bubbleColor)); //设置画刷 为画刷设置颜色 用于给泡泡上色 色彩通过随机的RGB通道值实现
//联想笔画 写一个字是不是需要笔画和顺序
//QPainterPath 类(绘图路径)提供了一个容器,用于绘图操作,可以创建和重用图形形状。
QPainterPath bubblePath; //泡泡绘制路径
//path.drawEllipse(x, y, r, r);
//Ellipse 椭圆(圆)
bubblePath.addEllipse(QPoint(40, 40), radius, radius); //将一个圆形添加到绘图路径中
painter.drawPath(bubblePath); //绘制图形路径
}
c、绘画工具QPainter
画笔:
QPainter 可以创建画笔 画笔可以设置颜色以及粗细大小等等属性
画笔主要用于勾勒
创建方法:
//QPainter 工具名(画布位置)
QPainter p(this);
painter.setPen(QPen(m_bubbleColor,10));
通过setPen成员函数设置画笔的颜色以及粗细
画刷:
QPainter也可以设置画刷 画刷也有对应的颜色等属性
画刷主要用于图案核心区域的上色
//void QPainter::setBrush ( BrushStyle style )
//设置绘图工具的画刷为黑色和特定的style。
//painter.setBrush(QBrush(Color));
d、绘图路径QPainterPath
QPainterPath相当于我们的笔画
QPainterPath 类(绘图路径)提供了一个容器,用于绘图操作,可以创建和重用图形形状。
path.addEllipse(x,y,r,r) 将一个圆形路径添加到绘图路径中 参数依次为圆心的x,y坐标以及半径
e、下笔draw
painter.drawPath(bubblePath); //绘制图形路径
让画笔按照规定的路径去进行绘制图形
2、背景图片如何绘制?
也是通过paintEvent进行绘制
具体实现:
void login::paintEvent(QPaintEvent *)
{
//绘制背景图片
QPainter p(this);
p.drawPixmap(0,0,width(),height(),QPixmap(":/files/snow.png"));
p.end();
}
QPixmap将背景图片读出
3、疑问:Bubble类的本质是什么?
可以看到Bubble类的本质是一个QWidget,是一个窗体。
而窗体除了其内部图形外还包含窗体边框、窗体标题、以及一些未绘图区域,这就需要我们去进行处理。
4、如何让Bubble窗体只包含泡泡?
通过前面的分析,我们知道Bubble类对象的本质仍是一个窗体,那么我们就需要去除其边框,并让其除泡泡外其余部分均为透明。
未处理前:
观察Bubble的构造函数:
Bubble::Bubble(int newR,int newX,int newY,QWidget *parent) //构造函数 构造泡泡图形
: QWidget(parent)
, ui(new Ui::Bubble)
,x(newX)
,y(newY)
,radius(newR)
{
ui->setupUi(this); //自带的 初始化UI
//通过调整窗体属性
//this即当前的对象自身 而当前这个对象本质上是一个widget 是一个页面 通过进行相关参数的调节 将其变为泡泡‘
//setFixedSize() 设置窗口固定大小
this->setFixedSize(QSize(80, 80)); //设置固定的大小 泡泡的最大值
//setWindowFlags 设置窗口属性
//Qt::FramelessWindowHint无边框化,移动,大小调整
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); //设置窗口标志 不带标题栏边框
//setAttribute 设置窗体属性 Qt::WA_TranslucentBackground使其透明
this->setAttribute(Qt::WA_TranslucentBackground); //使窗体透明
// 控件显示完关闭后自动删除;
//this->setAttribute(Qt::WA_DeleteOnClose); //用于设置各种窗口小部件(widget)的属性。
//参数解释:动画作用的对象 动画涉及更改的属性 pos:position 位置
this->BubbleAnimation = new QPropertyAnimation(this, "pos"); //初始化动画成员
}
1、去除窗体边框标题栏
通过设置窗体属性(标志)
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); //设置窗口标志 不带标题栏边框
2、让窗体大小与泡泡一致
//setFixedSize() 设置窗口固定大小
this->setFixedSize(QSize(80, 80)); //设置固定的大小 泡泡的最大值
3、让除泡泡外其余部分透明
//setAttribute 设置窗体属性 Qt::WA_TranslucentBackground使其透明
this->setAttribute(Qt::WA_TranslucentBackground); //使窗体透明
处理后:
5、如何让泡泡进行漂浮
漂浮的本质是什么:无非就是位置的改变
通过Qt中的属性动画类 QPropertyAnimation //属性动画头文件 property:属性
Qt中的动画类关系如下:
将其定义在泡泡的展示函数 own_show()里
//自己的show方法
void Bubble::own_show()
{
QWidget::show();
QTime time;
time= QTime::currentTime();
qsrand(time.msec()+time.second()*1000);
int v = 2000+qrand() % 3000; //随机速度
int exc_x = 200+qrand() % 700; //随机速度
int control = qrand() % 2; //控制模式
this->BubbleAnimation->setDuration(v); //设置动画持续时长 参数为一个整形数据 时长随机 时长相当于速度
this->BubbleAnimation->setStartValue(QPoint(x, y));
if(control==0)
{
qDebug()<<"模式0向上漂浮";
this->BubbleAnimation->setEndValue(QPoint(x+exc_x, -1000)); //设置结束位置 两点确定一线嘛
}
else if(control==1)
{
qDebug()<<"模式1向下漂浮";
this->BubbleAnimation->setEndValue(QPoint(x-exc_x, 2000)); //设置结束位置 两点确定一线嘛
}
//设置动画的初始值 由于是一个属性动画 更改的是pos(位置)属性 所以初始值应该是位置(坐标) QPoint
// this->BubbleAnimation->setEndValue(QPoint(x+200, -500)); //设置结束位置 两点确定一线嘛
BubbleAnimation->setEasingCurve(QEasingCurve::InOutQuad); //这个属性保留了动画的缓和曲线 文档看到的
this->BubbleAnimation->start(); //动画开始
}
动画的初始化
将初始化放在bubble的构造函数中
this->BubbleAnimation = new QPropertyAnimation(this, "pos"); //初始化动画成员
参数为 动画作用的对象,需要变动的属性
1、设置动画时长
this->BubbleAnimation->setDuration(v);
2、设置开始位置
this->BubbleAnimation->setStartValue(QPoint(x, y));
3、设置结束位置
this->BubbleAnimation->setEndValue(QPoint(x, y));
4、开始动画
this->BubbleAnimation->start(); //动画开始
这个属性保留了动画的缓和曲线 文档看到的
this->BubbleAnimation->start(); //动画开始
}
#### 动画的初始化
将初始化放在bubble的构造函数中
```c++
this->BubbleAnimation = new QPropertyAnimation(this, "pos"); //初始化动画成员
参数为 动画作用的对象,需要变动的属性
1、设置动画时长
this->BubbleAnimation->setDuration(v);
2、设置开始位置
this->BubbleAnimation->setStartValue(QPoint(x, y));
3、设置结束位置
this->BubbleAnimation->setEndValue(QPoint(x, y));
4、开始动画
this->BubbleAnimation->start(); //动画开始
刘易行 李欢欢