目录
一、实现效果
二、图元、视图、场景简单介绍
1、相互关系
2、头文件
3、实现流程
三、代码实现
1、自定义一个Item(图元)
1.1 新建一个类myItem继承于QGraphicsItem
1.2 myItem头文件(.h)
1.3 重载构造函数
1.4 boundingRect函数以及paint函数实现
1.5 advance函数实现
1.6 完整代码(.cpp)
2、自定义一个view(视图)
2.1 新建一个类WelcomeWin继承于QGraphicsView
2.2 WelcomeWin头文件(.h)
2.3 WelcomeWin完整代码(.cpp)
四、主函数测试
图元碰撞,提示开机成功。
图元:包含在场景中,一个场景可以有多个图元。
视图:相当于一个小窗口,用来观察场景的,视图可以有多个场景。
场景:相当于一块幕布,里面有好多元素(图元)。
#include //图元
#include //视图
#include //场景
大致流程是:新建图元——>新建场景——>场景添加图元——>新建视图——>视图关联场景。
记得勾上QObject,因为之后会用到信号与槽。
自定义Item类主要重写了boundingRect函数、paint函数以及advance函数。boundingRect用于返回一个碰撞大小的矩形框,对之后碰撞检测有影响。paint函数主要用于图元的绘制,实现自定义图元。advance函数用于图元移动。
以及自定义了一个信号(signals):void MyItemcolliding(),主要用于两个图元碰撞到了之后发射该信号,然后图元消失,成功开机。
因为用到信号,所以要添加Q_OBJECT宏,并继承与QObject,不然后期可能会出现报错。
#ifndef MYITEM_H
#define MYITEM_H
#include
#include
#include
class myItem : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
myItem();
myItem(int x,int y,QString file,int pos);
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
int x,y,w,h,role;
QString file;
public slots:
void advance(int phase) override;
signals:
void MyItemcolliding();
};
#endif // MYITEM_H
int x、int y: 图元的位置(坐标)
QString file: 图元所要加载的图片所在的路径
int role: 图元的类型,本例主要用于定义警察和小偷
myItem::myItem(int x, int y, QString file, int role)
{
this->x=x;
this->y=y;
this->role=role;
this->file=file;
this->w=QImage(this->file).width();
this->h=QImage(this->file).height();
this->setPos(this->x,this->y);
}
collidingItems()会返回一个碰撞图元链表,也就是说里面存放的是正在发生碰撞的图元,可以用 isEmpty()函数来判断是否图元发生了碰撞。isEmpty()函数返回值为bool类型,为空返回true,否则返回false。
QRectF myItem::boundingRect() const
{
//qreal penWidth = 1; //不定义画笔宽度了,直接用0取代
return QRectF(0, 0, this->w, this->h);//返回碰撞的矩形框
}
void myItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
//标明该参数没有使用
Q_UNUSED(option)
Q_UNUSED(widget)
if(collidingItems().isEmpty())//没有与其他图形项碰撞
{
//没有碰撞就绘图,碰撞到了图元消失(不绘制)
painter->drawImage(QRectF(0,0,this->w,this->h),QImage(this->file));
}
//可以加个else,图元碰撞到了变成其他图片
}
如果collidingItems()不为空,则碰撞到了,就发送自定义信号。
void myItem::advance(int phase)
{
//如果phase为0,表示将开始移动则返回
if(!phase)
{
return;
}
if(!collidingItems().isEmpty())
{
emit MyItemcolliding();//碰撞后发射信号
}
if(this->role == 1)//警察,移动快
{
moveBy(-5,0);//向左移动5
}
else if(this->role == -1)//小偷,移动慢
{
moveBy(-2,0);//向左移动2
}
}
#include "myitem.h"
#include
myItem::myItem()
{
}
myItem::myItem(int x, int y, QString file, int role)
{
this->x=x;
this->y=y;
this->role=role;
this->file=file;
this->w=QImage(this->file).width();
this->h=QImage(this->file).height();
this->setPos(this->x,this->y);
}
QRectF myItem::boundingRect() const
{
//qreal penWidth = 1; //不定义画笔宽度了,直接用0取代
return QRectF(0, 0, this->w, this->h);
}
void myItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
//标明该参数没有使用
Q_UNUSED(option)
Q_UNUSED(widget)
if(collidingItems().isEmpty())//没有与其他图形项碰撞
{
//没有碰撞就绘图,碰撞到了图元消失(不绘制)
painter->drawImage(QRectF(0,0,this->w,this->h),QImage(this->file));
}
//可以加个else,图元碰撞到了变成其他图片
}
void myItem::advance(int phase)
{
//如果phase为0,表示将开始移动则返回
if(!phase)
{
return;
}
if(!collidingItems().isEmpty())
{
emit MyItemcolliding();//碰撞后发射信号
}
if(this->role == 1)//警察,移动快
{
moveBy(-5,0);//向左移动5
}
else if(this->role == -1)//小偷,移动慢
{
moveBy(-2,0);//向左移动2
}
}
记得勾上QObject。
包括两个自定义图元,一个定时器,一个场景,以及一个槽函数。也要加上Q_OBJECT宏。
#ifndef WELCOMEWIN_H
#define WELCOMEWIN_H
#include
#include
#include
#include
#include "myitem.h"
class WelcomeWin : public QGraphicsView
{
Q_OBJECT
public:
WelcomeWin();
private:
myItem *item1, *item2; //添加两个自定义Item
QTimer *timer; //定时器,用于图元移动
QGraphicsScene *sence; //场景
public slots:
void timerStop(); //槽函数,用于关闭定时器,提示开机成功
};
#endif // WELCOMEWIN_H
#include "welcomewin.h"
#include
WelcomeWin::WelcomeWin()
{
timer=new QTimer;
//新建图元
item1=new myItem(this->width()-240,450,"image/thrief.png",-1);//-1代表小偷
item2=new myItem(this->width()+100,450,"image/police.png",1);//1代表警察
//新建场景
sence=new QGraphicsScene;
sence->setSceneRect(0,0,this->width()+459,this->height()+368);//设置场景位置,可根据自己的背景图调位置
//场景添加图元
sence->addItem(item1);
sence->addItem(item2);
//视图关联场景
this->setScene(sence);
this->setFixedSize(800,550);
this->setWindowTitle("Welcome");
this->setBackgroundBrush(QBrush(QPixmap("image/start-background.jpeg")));//设置视图背景
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//不要水平滑动条
this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//不要垂直滑动条
this->setWindowFlags(Qt::FramelessWindowHint);//设置窗体无边框
this->setWindowIcon(QIcon("image/警徽.png"));
//定时器
connect(timer,SIGNAL(timeout()),sence,SLOT(advance()));//定时器超时会调用图元的advance函数,图元移动
timer->start(30);//每30毫秒超时
connect(item2,SIGNAL(MyItemcolliding()),this,SLOT(timerStop()));//图元碰撞会发送MyItemcolliding()信号,并关联槽
}
//槽函数实现
void WelcomeWin::timerStop()
{
this->timer->stop(); //定时器关闭
QMessageBox msgBox(this); //消息提示框
msgBox.setWindowIcon(QIcon("image/提示.png"));
msgBox.setWindowTitle("Tip");
msgBox.setStyleSheet("QMessageBox QLabel{min-width: 400px;"
" min-height: 100px;font:16pt; font-family:'楷体';}");
msgBox.setText("开机成功");
msgBox.exec();
this->close(); //开机成功,当前窗口关闭
}
测试结果在文章开头。
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
WelcomeWin w;
w.show();
return a.exec();
}
原创不易,转载请标明出处。