MFC代码--定时器实现运动

MFC的作业

  • 设计基于单文档/视图结构的程序。绘制一条直的道路,然后然后设计一个小车(矩形代替,有车号),使其沿道路匀速行走,到终点自动返回,来回行走。道路的宽度、长度由设定菜单完成;还有开始、结束菜单;有高速、中速、低速三个菜单控制小车速度。
  • 简要分析下:主要用到的知识有:单文档界面(SDI)应用程序,利用ClassWizard编制消息处理函数,定时器消息,客户区重绘等等……
  • 实现

修改文档类的定义,添加成员变量:

1
class CCarsDoc : public CDocument { protected: // create from serialization only CCarsDoc(); DECLARE_DYNCREATE(CCarsDoc) // Attributes public: CRect m_rectCar; int speed; // Operations public: // Overrides

在CCarsDoc的成员函数OnNewDocument()中初始化数据:

1
BOOL CCarsDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; m_rectCar=CRect(100,100,180,150); int speed = 1; m_boolNew=true; m_Length=0; m_Width=0; // TODO: add reinitialization code here // (SDI documents will reuse this document) return TRUE; }

再通过资源编辑器中的菜单编辑器完成菜单的编辑,使用ClassWizard生成消息处理函数,并自动添加菜单消息和消息处理函数的映射,在消息处理函数中加入代码:

1
2
void CCarsView::Onstart() { // TODO: Add your command handler code here CCarsDoc *pDoc=GetDocument(); ASSERT_VALID(pDoc); CRect rectClient; GetClientRect(&rectClient); SetTimer(1,100,NULL); } void CCarsView::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default
CCarsDoc *pDoc=GetDocument(); ASSERT_VALID(pDoc); InvalidateRect(pDoc->m_rectCar,TRUE); static int flag = 1; if(pDoc->m_rectCar.right > pDoc->m_Length || pDoc->m_rectCar.left < 50) { flag *= -1; } pDoc->m_rectCar.left += pDoc->speed*flag; pDoc->m_rectCar.right += pDoc->speed*flag; InvalidateRect(pDoc->m_rectCar,FALSE); CView::OnTimer(nIDEvent); } void CCarsView::Onstop() { // TODO: Add your command handler code here KillTimer(1); } void CCarsView::Onhigh() { // TODO: Add your command handler code here CCarsDoc *pDoc=GetDocument(); ASSERT_VALID(pDoc); pDoc->speed=10; } void CCarsView::Onmedium() { // TODO: Add your command handler code here CCarsDoc *pDoc=GetDocument(); ASSERT_VALID(pDoc); pDoc->speed=5; } void CCarsView::Onlow() { // TODO: Add your command handler code here CCarsDoc *pDoc=GetDocument(); ASSERT_VALID(pDoc); pDoc->speed=1; } void CCarsView::OnMenuitem32777() { // TODO: Add your command handler code here CCarsDoc *pDoc=GetDocument(); ASSERT_VALID(pDoc); CCarsDlg dlginput; int nRet = dlginput.DoModal(); if(nRet = IDOK) { pDoc->m_Length=dlginput.m_Length; pDoc->m_Width=dlginput.m_Width; pDoc->m_boolNew=false; Invalidate(); } }

然后在OnDraw()里绘制小车和跑道:

1
void CCarsView::OnDraw(CDC* pDC) { CCarsDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDC->Rectangle(pDoc->m_rectCar); pDC->MoveTo(50,50); pDC->LineTo(pDoc->m_Length,50); pDC->MoveTo(50,50+(pDoc->m_Width)); pDC->LineTo(pDoc->m_Length,50+(pDoc->m_Width)); // TODO: add draw code for native data here }

  • 设计一个具有一定外形和颜色的计数器。开始结束由鼠标控制。
  • 实现:

修改文档类的定义,添加成员变量:

1
class CCountDoc : public CDocument { protected: // create from serialization only CCountDoc(); DECLARE_DYNCREATE(CCountDoc) // Attributes public: int m_iCount; // Operations public: // Overrides..... 省略以下

在成员函数OnNewDocument()中初始化数据:

1
m_iCount = 0;

使用ClassWizaid生成消息处理函数,鼠标左键开始计数,右键停止计数:

1
void CCountView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default SetTimer(1,100,NULL); CView::OnLButtonDown(nFlags, point); } void CCountView::OnRButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default KillTimer(1); CView::OnRButtonDown(nFlags, point); } void CCountView::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default CCountDoc *pDoc=GetDocument(); ASSERT_VALID(pDoc); pDoc->m_iCount++; Invalidate(); CView::OnTimer(nIDEvent); }

对了,绘图的时候要有颜色:

1
void CCountView::OnDraw(CDC* pDC) { CCountDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); CString strDisplay; CPen penBlue; penBlue.CreatePen(PS_SOLID,3,RGB(0,0,255)); strDisplay.Format ("Current number:%d",pDoc->m_iCount); pDC->SetTextColor(RGB(0,255,0)); pDC->SelectObject(&penBlue); pDC->Rectangle(50,50,280,180); pDC->TextOut(100,100,strDisplay); // TODO: add draw code for native data here }

小结

我要检讨一下自己当时小学期的时候没有好好学习MFC,很多东西都不记得了。在编写这两个程序的过程中还遇到了很多问题,比如让小车往返运动的问题,请教了[@Lyeec](http://lyeec.me)。还有,我一定要养成随手写注释的习惯。