接昨天的图片移动:
在实训的时候飞机移动有两种,一种是玩家控制的战机,由键盘来控制;一种是敌机,控制方式是定时器,Qt里面也有定时器这种东西,所以试着实现了一下。
在昨天的基础上加了一个cat类,闲话休絮,先把代码贴上,慢慢解释。
首先是cat.h
1 #ifndef CAT_H 2 #define CAT_H 3 4 #include <QtGui> 5 6 class Cat : public QWidget 7 { 8 Q_OBJECT 9 public: 10 explicit Cat(QWidget *parent = 0); 11 ~Cat(); 12 protected: 13 void paintEvent (QPaintEvent *event); 14 void mousePressEvent(QMouseEvent *event); 15 16 private: 17 QPixmap *catImg; 18 QRect *catImgRect; 19 QTimer *catTimer; 20 protected: 21 int shrinkMultiple; 22 int speed; 23 bool stop; 24 signals: 25 void clicked(); 26 public slots: 27 void mousePressEventSlot(); 28 29 void run(); 30 }; 31 32 #endif // CAT_H
1 private: 2 QPixmap *catImg; 3 QRect *catImgRect; 4 5 protected: 6 int shrinkMultiple; 7 int speed; 8
这几个和上一节完全一样,不解释了,加了几个变量,信号槽:
1、QTimer *catTimer; 就是传说中的定时器,用信号槽的方式来使用
connect(catTimer,SIGNAL(timeout()),this,SLOT(run()));
catTimer->start(20);
解释:timeout是Qt自己的信号,比如这个例子,start是说让catTimer定时器开始工作,时间是20毫秒,当20毫秒过后,Qt会发出timeout信号,将run这个槽的函数加入到某个队列里面(队列具体的名字和作用我忘了),来依次处理。
2、bool stop; 因为我想要让运动的图片暂停,所以加了这么一个变量
3、两个槽
1 public slots: 2 void mousePressEventSlot(); 3 4 void run();
具体用法在cpp文件中解释
1 #include "cat.h" 2 3 Cat::Cat(QWidget *parent) : 4 QWidget(parent),shrinkMultiple(2), 5 speed(10),stop(true) 6 { 7 catImg = new QPixmap(":/img/little_cat.jpg"); 8 int width = catImg->width ()/shrinkMultiple; 9 int height = catImg->height ()/shrinkMultiple; 10 catImgRect = new QRect(10,10,width,height); 11 12 catTimer = new QTimer(this); 13 14 connect( this, SIGNAL( clicked() ), this, SLOT( mousePressEventSlot() ) ); 15 connect( catTimer,SIGNAL(timeout()),this,SLOT(run())); 16 17 } 18 void Cat::paintEvent (QPaintEvent *event) 19 { 20 QPainter painter(this); 21 22 painter.drawPixmap(*catImgRect,*catImg); 23 } 24 void Cat::mousePressEvent(QMouseEvent *event) 25 { 26 if (catImgRect->contains (event->x(),event->y())) 27 { 28 stop = !stop; 29 emit clicked(); 30 } 31 } 32 void Cat::run() 33 { 34 int width = catImgRect->width (); 35 catImgRect->setX (catImgRect->x ()+10); 36 catImgRect->setWidth (width); 37 repaint (); 38 } 39 void Cat::mousePressEventSlot () 40 { 41 if(!stop) 42 { 43 catTimer->start (20); 44 } 45 else 46 { 47 catTimer->stop (); 48 } 49 50 } 51 Cat::~Cat() 52 { 53 delete catImg; 54 delete catImgRect; 55 delete catTimer; 56 }
首先看构造函数
1 Cat::Cat(QWidget *parent) : 2 QWidget(parent),shrinkMultiple(2), 3 speed(10),stop(true) 4 { 5 catImg = new QPixmap(":/img/little_cat.jpg"); 6 int width = catImg->width ()/shrinkMultiple; 7 int height = catImg->height ()/shrinkMultiple; 8 catImgRect = new QRect(10,10,width,height); 9 10 catTimer = new QTimer(this); 11 12 connect( this, SIGNAL( clicked() ), this, SLOT( mousePressEventSlot() ) ); 13 connect( catTimer,SIGNAL(timeout()),this,SLOT(run())); 14 15 }
到new定时器之前的东西就不讲了,和昨天画猫的地方一样。
1 catTimer = new QTimer(this); 2 3 connect( this, SIGNAL( clicked() ), this, SLOT( mousePressEventSlot() ) ); 4 connect( catTimer,SIGNAL(timeout()),this,SLOT(run()));
这里,链接了两个信号槽,我打算的是点击图片,猫开始跑,再点击,猫停止,这么着跑跑停停的。
很自然,链接clicked和mousePressEventSlot,点击信号对应鼠标按下事件的槽嘛;
为什么要用catTimer链接run呢,这是为了让图片能够一直运动,图片是根据catImgRect这个矩形信息来绘制的,如果让图片运动,很自然的就像让图片没秒往某几个方向移动几个像素,如果没用定时器的话,咱们可能用一个while循环来实现,有定时器就不用这么麻烦了。
首先看mousePressEvent,相较更低的Event函数,因为有事件的时候肯定会先找事件的函数来处理
1 void Cat::mousePressEvent(QMouseEvent *event) 2 { 3 if (catImgRect->contains (event->x(),event->y())) 4 { 5 stop = !stop; 6 emit clicked(); 7 } 8 }
当鼠标按下的时候,如果按键的坐标点在catImgRect这个矩形中,说明鼠标点到我们的猫仔图片了,那么原来的运动状态就转换为相反的值,原来动变成停,停变成动,然后才发出图片被点中了的clicked信号。
当信号发出时,由于下面这行的存在,所以会出发触发mousePressEventSlot这个函数
1 connect( this, SIGNAL( clicked() ), this, SLOT( mousePressEventSlot() ) );
mousePressEventSlot这个函数和run函数合在一起是为了控制图片运动或者停止的,run函数是说每次向右移动10个像素,并且重绘,而因为下面这个信号槽的存在,run和catTmer定时器链接在了一起,当定时器启动的时候,处理run函数,停止的话就不动了呗。因此,我在mousePressEventSlot这个槽里面处理了定时器的启动与停止。
1 connect( catTimer,SIGNAL(timeout()),this,SLOT(run()));
下面是run和mousePressEventSlot
1 void Cat::run() 2 { 3 int width = catImgRect->width (); 4 catImgRect->setX (catImgRect->x ()+10); 5 catImgRect->setWidth (width); 6 repaint (); 7 } 8 void Cat::mousePressEventSlot () 9 { 10 if(!stop) 11 { 12 catTimer->start (20); 13 } 14 else 15 { 16 catTimer->stop (); 17 } 18 19 }
定时器为什么选择20毫秒的,开始的时候我用的是50,结果又停滞感,就是西卡一卡的,定时器的时间间隔越兄啊,图片运动越流畅,越没有停顿感。道理很简单,你想啊,如果一个图片每1秒移动然后重新画一下图肯定比每10秒移动重画图片要流畅,没有一卡一卡的感觉。
最后上截图,运动的截图,比较蛋疼,就随便截截图吧,实际上是点击,猫运动,在点击,猫停止,如此反复。
ps:因为是在昨天的工程里做的,原来的键盘猫还有。
开始的时候
点击运动后
pps:为什么要做这两篇Qt移动图片呢?原因是我们下学期要学设计模式这个东西,老师很英明的选择了《head first设计模式》这本书,确实是好书,之前我读过,里面使用java,依然是命令行的模式,我突然想能不能用图形的给实现一下,看了里面第一张的策略模式,里面是鸭子的飞行,刚好可以放在这当猫的run,我就想利用图片的上下左右移动当做duck不同的飞行动作,恩,就是这样。
ppps:玩Qt什么的,只想说一句话,一切为了python