演练:向 MFC 项目添加动画
本演练介绍如何将基本动画对象添加到 Visual C++、Microsoft 基础类库 (MFC) 项目。
演练演示了如何完成这些任务:
创建 MFC 应用程序。
添加菜单,然后添加用于启动和停止动画的命令。
创建启动和停止命令的处理程序。
将动画对象添加到项目。
使动画对象在窗口内居中。
验证结果。
注意
以下说明中的某些 Visual Studio 用户界面元素在计算机上出现的名称或位置可能会不同。 这些元素取决于你所使用的 Visual Studio 版本和你所使用的设置。 有关详细信息,请参阅个性化设置 IDE。
先决条件
若要完成本演练,您必须具有 Visual Studio。
创建 MFC 应用程序
使用 MFC 应用程序向导创建 MFC 应用程序。 有关如何为 Visual Studio 版本打开向导的说明,请参阅演练:使用新的 MFC Shell 控件。
在“名称”框中,键入“MFCAnimationWalkthrough”。 单击“确定”。
在“MFC 应用程序向导”对话框中,验证“应用程序类型”是否为“多个文档”,“项目样式”是否为“Visual Studio”,以及是否已选择“文档/视图体系结构支持”选项。 单击“完成” 。
添加菜单,然后添加用于启动和停止动画的命令
在“视图”菜单上,指向“其他窗口”,然后单击“资源视图”。
在“资源视图”中导航到“菜单”文件夹并将其打开。 通过双击“IDR_MFCAnimationWalkthroughTYPE”资源将其打开以进行修改。
在菜单栏上的“请在此处键入”框中,键入 A&nimation 以创建“Animation”菜单。
在“Animation”下的“请在此处键入”框中,键入“Start &Forward”以创建“Start Forward”命令。
在“Start Forward”下的“请在此处键入”框中,键入“Start &Backward”。
在“Start Backward”下的“请在此处键入”框中,键入 S&top 以创建“Stop”命令。
保存并关闭 MFCAnimationWalkthrough.rc。
在解决方案资源管理器中双击 MainFrm.cpp,将其打开以进行修改。 在
CMainFrame::OnCreate
方法中,找到对lstBasicCommands.AddTail
有多个调用的节。 添加以下代码(紧接在该节后)。lstBasicCommands.AddTail(ID_ANIMATION_STARTFORWARD); lstBasicCommands.AddTail(ID_ANIMATION_STARTBACKWARD); lstBasicCommands.AddTail(ID_ANIMATION_STOP);
保存文件并将其关闭。
创建启动和停止命令的处理程序
在“项目”菜单上,单击“类向导”。
在“MFC 类向导”中的“类名”下选择“CMFCAnimationWalkthroughView”。
在“命令”选项卡的“对象 ID”框中选择“ID_ANIMATION_STARTFORWARD”,然后在“消息”框中选择“命令”。 单击“添加处理程序”。
在“添加成员函数”对话框中,单击“确定”。
在“对象 ID”框中选择“ID_ANIMATION_STARTBACKWARD”,然后在“消息”框中选择“命令”。 单击“添加处理程序”。
在“添加成员函数”对话框中,单击“确定”。
在“对象 ID”框中选择“ID_ANIMATION_STOP”,然后在“消息”框中选择“命令”。 单击“添加处理程序”,然后单击“确定”。
在“添加成员函数”对话框中,单击“确定”。
在“MFC 类向导”中,单击“确定”。
保存在编辑器中打开的 MFCAnimationWalkthroughView.cpp,但不要关闭它。
将动画对象添加到项目
在解决方案资源管理器中双击 MFCAnimationWalkthroughView.h,将其打开以进行修改。 在
CMFCAnimationWalkthroughView
类的定义之前,添加以下代码以创建自定义动画控制器,用于处理与动画对象的计划冲突。class CCustomAnimationController : public CAnimationController { public: CCustomAnimationController() { } virtual BOOL OnHasPriorityTrim(CAnimationGroup* pGroupScheduled, CAnimationGroup* pGroupNew, UI_ANIMATION_PRIORITY_EFFECT priorityEffect) { return TRUE; } };
在
CMFCAnimationWalkthroughView
类的末尾,添加以下代码。CCustomAnimationController m_animationController; CAnimationColor m_animationColor; CAnimationRect m_animationRect;
在
DECLARE_MESSAGE_MAP()
行的后面添加以下代码。void Animate(BOOL bDirection);
保存文件并将其关闭。
在 MFCAnimationWalkthroughView.cpp 中的文件顶部,在
#include
语句之后及所有类方法之前添加以下代码。static int nAnimationGroup = 0; static int nInfoAreaHeight = 40;
在
CMFCAnimationWalkthroughView
构造函数末尾添加以下代码。m_animationController.EnableAnimationTimerEventHandler(); m_animationController.EnablePriorityComparisonHandler(UI_ANIMATION_PHT_TRIM); m_animationColor = RGB(255, 255, 255); m_animationRect = CRect(0, 0, 0, 0); m_animationColor.SetID(-1, nAnimationGroup); m_animationRect.SetID(-1, nAnimationGroup); m_animationController.AddAnimationObject(&m_animationColor); m_animationController.AddAnimationObject(&m_animationRect);
找到
CAnimationWalthroughView::PreCreateWindow
方法,然后将它替换为以下代码。BOOL CMFCAnimationWalkthroughView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs m_animationController.SetRelatedWnd(this); return CView::PreCreateWindow(cs); }
找到
CAnimationWalkthroughView::OnDraw
方法,然后将它替换为以下代码。void CMFCAnimationWalkthroughView::OnDraw(CDC* pDC) { CMFCAnimationWalkthroughDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: add draw code for native data here CMemDC dcMem(*pDC, this); CDC& dc = dcMem.GetDC(); CRect rect; GetClientRect(rect); dc.FillSolidRect(rect, GetSysColor(COLOR_WINDOW)); CString strRGB; strRGB.Format(_T("Fill Color is: %d; %d; %d"), GetRValue(m_animationColor), GetGValue(m_animationColor), GetBValue(m_animationColor)); dc.DrawText(strRGB, rect, DT_CENTER); rect.top += nInfoAreaHeight; CBrush br; br.CreateSolidBrush(m_animationColor); CBrush* pBrushOld = dc.SelectObject(&br); dc.Rectangle((CRect)m_animationRect); dc.SelectObject(pBrushOld); }
在文件末尾添加以下代码。
void CMFCAnimationWalkthroughView::Animate(BOOL bDirection) { static UI_ANIMATION_SECONDS duration = 3; static DOUBLE dblSpeed = 35.; static BYTE nStartColor = 50; static BYTE nEndColor = 255; BYTE nRedColorFinal = bDirection ? nStartColor : nEndColor; BYTE nGreenColorFinal = bDirection ? nStartColor : nEndColor; BYTE nBlueColorFinal = bDirection ? nStartColor : nEndColor; CLinearTransition* pRedTransition = new CLinearTransition(duration, (DOUBLE)nRedColorFinal); CSmoothStopTransition* pGreenTransition = new CSmoothStopTransition(duration, (DOUBLE)nGreenColorFinal); CLinearTransitionFromSpeed* pBlueTransition = new CLinearTransitionFromSpeed(dblSpeed, (DOUBLE)nBlueColorFinal); m_animationColor.AddTransition(pRedTransition, pGreenTransition, pBlueTransition); CRect rectClient; GetClientRect(rectClient); rectClient.top += nInfoAreaHeight; int nLeftFinal = bDirection ? rectClient.left : rectClient.CenterPoint().x; int nTopFinal = bDirection ? rectClient.top : rectClient.CenterPoint().y; int nRightFinal = bDirection ? rectClient.right : rectClient.CenterPoint().x; int nBottomFinal = bDirection ? rectClient.bottom : rectClient.CenterPoint().y; CLinearTransition* pLeftTransition = new CLinearTransition(duration, nLeftFinal); CLinearTransition* pTopTransition = new CLinearTransition(duration, nTopFinal); CLinearTransition* pRightTransition = new CLinearTransition(duration, nRightFinal); CLinearTransition* pBottomTransition = new CLinearTransition(duration, nBottomFinal); m_animationRect.AddTransition(pLeftTransition, pTopTransition, pRightTransition, pBottomTransition); CBaseKeyFrame* pKeyframeStart = CAnimationController::GetKeyframeStoryboardStart(); CKeyFrame* pKeyFrameEnd = m_animationController.CreateKeyframe(nAnimationGroup, pBlueTransition); pLeftTransition->SetKeyframes(pKeyframeStart, pKeyFrameEnd); pTopTransition->SetKeyframes(pKeyframeStart, pKeyFrameEnd); pRightTransition->SetKeyframes(pKeyframeStart, pKeyFrameEnd); pBottomTransition->SetKeyframes(pKeyframeStart, pKeyFrameEnd); m_animationController.AnimateGroup(nAnimationGroup); }
在“项目”菜单上,单击“类向导”。
在“MFC 类向导”中的“类名”下选择“CMFCAnimationWalkthroughView”。
在“消息”选项卡上的“消息”框中,选择“WM_ERASEBKGND”,单击“添加处理程序”,然后单击“确定”。
在 MFCAnimationWalkthroughView.cpp 中,将
OnEraseBkgnd
实现替换为以下代码,以在重绘动画对象时减少其中的闪烁。BOOL CMFCAnimationWalkthroughView::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; }
将
CMFCAnimationWalkthroughView::OnAnimationStartforward
、CMFCAnimationWalkthroughView::OnAnimationStartbackward
和CMFCAnimationWalkthroughView::OnAnimationStop
的实现替换为以下代码。void CMFCAnimationWalkthroughView::OnAnimationStartforward() { Animate(TRUE); } void CMFCAnimationWalkthroughView::OnAnimationStartbackward() { Animate(FALSE); } void CMFCAnimationWalkthroughView::OnAnimationStop() { IUIAnimationManager* pManager = m_animationController.GetUIAnimationManager(); if (pManager != NULL) { pManager->AbandonAllStoryboards(); } }
保存文件并将其关闭。
使动画对象在窗口内居中
在解决方案资源管理器中双击 MFCAnimationWalkthroughView.h,将其打开以进行修改。 在
CMFCAnimationWalkthroughView
类的末尾添加以下代码(紧接在m_animationRect
的定义之后)。BOOL m_bCurrentDirection;
保存文件并将其关闭。
在“项目”菜单上,单击“类向导”。
在“MFC 类向导”中的“类名”下选择“CMFCAnimationWalkthroughView”。
在“消息”选项卡上的“消息”框中,选择“WM_SIZE”,单击“添加处理程序”,然后单击“确定”。
在 MFCAnimationWalkthroughView.cpp 中,将
CMFCAnimationWalkthroughView::OnSize
代码替换为以下代码。void CMFCAnimationWalkthroughView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); CRect rect; GetClientRect(rect); rect.top += nInfoAreaHeight; CRect rectAnim = m_animationRect; m_animationRect = CRect(CPoint(rect.CenterPoint().x - rectAnim.Width() / 2, rect.CenterPoint().y - rectAnim.Height() / 2), rectAnim.Size()); if (m_animationController.IsAnimationInProgress()) { Animate(m_bCurrentDirection); } }
在
CMFCAnimationWalkthroughView
构造函数开头添加以下代码。m_bCurrentDirection = TRUE;
在
CMFCAnimationWalkthroughView::Animate
方法的开头添加以下代码。m_bCurrentDirection = bDirection;
保存文件并将其关闭。
验证结果
- 生成并运行应用程序。 在“Animation”(动画)菜单上单击“Start Forward”(开始放映)。 此时应显示一个矩形,且该矩形会占据中心区域。 如果单击“Start Backward”(开始倒退),动画会倒转;如果单击“Stop”(停止),动画会停止。 矩形的填充颜色应随着动画的进行而改变,当前颜色应显示在动画窗口顶部。