{"id":563,"date":"2010-12-16T16:28:04","date_gmt":"2010-12-16T15:28:04","guid":{"rendered":"http:\/\/www.nuonsoft.com\/blog\/?p=563"},"modified":"2010-12-16T16:28:22","modified_gmt":"2010-12-16T15:28:22","slug":"the-new-mfc-animation-api","status":"publish","type":"post","link":"https:\/\/www.nuonsoft.com\/blog\/2010\/12\/16\/the-new-mfc-animation-api\/","title":{"rendered":"The New MFC Animation API"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>Microsoft Visual Studio 2010 Service Pack 1 includes a number  of enhancements and new features for MFC developers. One of those changes is an  animation API to make it easy for you to create animations in MFC applications.  This article will briefly introduce this animation API.<br \/>\nThis articles was also posted on <a href=\"http:\/\/www.codeguru.com\/cpp\/cpp\/cpp_mfc\/tutorials\/article.php\/c18243__2\/The-New-MFC-Animation-API.htm\" target=\"_blank\">Codeguru.com<\/a>.<br \/>\n<!--more--><\/p>\n<p>The main parts of this new API are:<\/p>\n<ul>\n<li>Animation transitions<\/li>\n<li>Animation values<\/li>\n<li>Animation controllers<\/li>\n<\/ul>\n<h2>Animation Transitions<\/h2>\n<p>The animation API uses transitions to animate values. The API  comes with a number of predefined transitions:<\/p>\n<ul>\n<li><strong>CAccelerateDecelerateTransition<\/strong>: The animated value  speeds up and then slows down again.<\/li>\n<li><strong>CConstantTransition<\/strong>: The  animated value will be kept at its initial value during the whole transition.<\/li>\n<li><strong>CCubicTransition<\/strong>: The  animated value will reach the target value with a specified velocity.<\/li>\n<li><strong>CDiscreteTransition<\/strong>: The  animated value will jump from the initial value directly to the target value  after a specified delay.<\/li>\n<li><strong>CInstantaneousTransition<\/strong>:  The animated value immediately jumps to the target value. The duration is always  zero.<\/li>\n<li><strong>CLinearTransition<\/strong>: The  animated value will go linearly from its initial value to its target value over  a specified duration.<\/li>\n<li><strong>CLinearTransitionFromSpeed<\/strong>:  Is similar to CLinearTransition, but instead of specifying a duration, you have  to specify a speed with which the animated value has to go from the initial  value to the target value. The duration of the transition is calculated  automatically based on the specified speed.<\/li>\n<li><strong>CSmoothStopTransition<\/strong>: The  animated value will go from its initial value to its target value, but the  transition will slow down towards the target value to reach the target with a  velocity of zero.<\/li>\n<li><strong>CParabolicTransitionFromAcceleration<\/strong>: The animated  value will reach its target value with a specified velocity and acceleration.<\/li>\n<li><strong>CReversalTransition<\/strong>: The  transition direction will be changed smoothly over a specified duration. The  final value of the animated value will be the same as the initial value.<\/li>\n<li><strong>CSinusoidalTransitionFromRange<\/strong>: The animated value will  fluctuate between a specified minimum and maximum during the duration of the  transition.<\/li>\n<li><strong>CSinusoidalTransitionFromVelocity<\/strong>: The animated value  will oscillate around the initial value during the duration of the transition.<\/li>\n<\/ul>\n<p>Most of the above predefined animation transitions are pretty  straightforward to use. All of them require at least the duration of the  transition and most of them require a target value. For example, the  CAccelerateDecelerateTransition transition has the following constructor:<\/p>\n<pre>CAccelerateDecelerateTransition(UI_ANIMATION_SECONDS duration,\r\n   \tDOUBLE finalValue,\r\n   \tDOUBLE accelerationRatio = 0.3,\r\n   \tDOUBLE decelerationRatio = 0.3)<\/pre>\n<p>The first parameter is the duration of the transition. It is  the time that it will take to go from the start value to the target value. The  second parameter is this target value. The next parameters are specific  algorithmic parameters which have default values in this case.<\/p>\n<p>CConstantTransition is special. It will keep the animation  value at its initial value during the whole transition, so its constructor is  simply as follows:<\/p>\n<pre>CConstantTransition(UI_ANIMATION_SECONDS duration)<\/pre>\n<p>There is also a CCustomTransition that you can use if none of  the above transitions deliver what you are looking for. It&#8217;s a bit more  complicated to use. You will have to derive your own class from  CCustomInterpolator and implement the InterpolateValue method and possibly a few  others.<\/p>\n<p>The next section will discuss animation values and will give  examples on how to actually use the above animation transitions. Note that you  need to initialize COM before the Windows Animation API will work. You can do  this by adding the following line in your InitInstance method:<\/p>\n<pre>CoInitialize(0);<\/pre>\n<p>And the following line in your ExitInstance method:<\/p>\n<pre>CoUninitialize();<\/pre>\n<p>Instead of using CoInitialize and CoUnitialize, you can simply use the following block in your InitInstance method:<\/p>\n<pre>if (!AfxOleInit())\r\n{\r\n   \tAfxMessageBox(_T(\"AfxOleInit failed\"));\r\n   \treturn FALSE;\r\n}<\/pre>\n<h2>Animation Values<\/h2>\n<p>The new API works by animating values. There are several  classes that encapsulate specific values and which can be animated with certain  transitions. The different animation value classes are as follows:<\/p>\n<ul>\n<li>CAnimationValue: Animates a single value. This could be used  to animate a transparency of an object or a rotation of an object.<\/li>\n<li>CAnimationPoint: Animates a point. A point contains and X  and Y coordinates. Both coordinates can be animated separately.<\/li>\n<li>CAnimationSize: Animates a size. A size contains a width and  height, both can be animated separately.<\/li>\n<li>CAnimationColor: Animates a color. A color contains an RGB  value. Each color component can be animated separately.<\/li>\n<li>CAnimationRect: Animates a rectangle. A rectangle contains a  left, top, right and bottom value and all of them can be animated separately.<\/li>\n<\/ul>\n<p>Creating an animation value is pretty straightforward. Just  create an instance of the animation value object you want, initialize it, add  animation transitions to it and specify its parameters like the target value.  For example, to define a color animation value, first define it as follows:<\/p>\n<pre>CAnimationColor m_animClr1;<\/pre>\n<p>Then the following line will initialize the start color to  red:<\/p>\n<pre>m_animClr1 = RGB(255,0,0);<\/pre>\n<p>And finally assign transitions to each color component:<\/p>\n<pre>  m_animClr1.AddTransition(new CLinearTransition(2, 0),\r\n  \tnew CLinearTransition(1, 255),\r\n  \tnew CLinearTransition(0.5, 128));<\/pre>\n<p>The above line adds 3 transitions:<\/p>\n<ul>\n<li>The red color component will go from 255 (=start value) to 0  over a period of 2 seconds.<\/li>\n<li>The green color component will go from 0 (=start value) to  255 over a period of 1 seconds.<\/li>\n<li>The blue color component will go from 0 (=start value) to  128 over a period of 0.5 seconds.<\/li>\n<\/ul>\n<p>Similarly, a rectangle animation could be defined as  follows:<\/p>\n<pre>  CAnimationRect m_animRect;\r\n  m_animRect = CRect(0, 0, 100 ,100);\r\n  m_animRect.AddTransition(new CAccelerateDecelerateTransition(2, 100),\r\n  \tnew CAccelerateDecelerateTransition(2, 100),\r\n  \tnew CAccelerateDecelerateTransition(2, 400),\r\n  \tnew CAccelerateDecelerateTransition(2, 200));<\/pre>\n<p>This animation starts with a rectangle with upper-left  coordinate (0, 0) and lower-right coordinate (100, 100). The transitions will  animate this rectangle to an upper-left coordinate (100, 100) and a lower-right  coordinate (400, 200) over a period of 2 seconds using an  acceleration-deceleration transition.<\/p>\n<p>Inside your WM_PAINT handler, you will use the animated  values from your animation variables to do your drawing. For example:<\/p>\n<pre>  int x1, y1, x2, y2;\r\n  m_animRect.GetLeft().GetValue(x1);\r\n  m_animRect.GetTop().GetValue(y1);\r\n  m_animRect.GetRight().GetValue(x2);\r\n  m_animRect.GetBottom().GetValue(y2);\r\n  COLORREF clr;\r\n  m_animClr1.GetValue(clr);\r\n  pDC-&gt;FillSolidRect(x1, y1, x2-x1, y2-y1, clr);<\/pre>\n<p>The above code is first querying the animated rectangle about  its current animated coordinates and the animated color variable about its  current color value. After that it simply draws a rectangle with those  coordinates and color.<\/p>\n<p>Working with the other animation value classes is pretty  similar.<\/p>\n<h2>Animation Controller<\/h2>\n<p>Now that you have learned about animation transitions and  animations values, it&#8217;s time to learn how it all fits together. The  CAnimationController class is the central part of the animation API. It will  keep track of all animation values and animation transitions. You simply create  one as a member variable in your class as follows:<\/p>\n<pre>  CAnimationController m_animCtrl;<\/pre>\n<p>The next step is to link it with your target window in which  you want to draw the animation:<\/p>\n<pre>  m_animCtrl.SetRelatedWnd(this);<\/pre>\n<p>You are not required to link an animation controller with a  window. Linking it will tell the animation API to send WM_PAINT messages to the  specified window during the animation which makes it easier for you to redraw a  frame of your animation. If you do not link the animation controller with a  window, you will have to manually invalidate your window at appropriate  intervals to redraw it. In this example we want the animation controller to send  WM_PAINT message periodically, so you also need to tell it to use an animation  timer:<\/p>\n<pre>  m_animCtrl.EnableAnimationTimerEventHandler();<\/pre>\n<p>Now it&#8217;s time to link your animation values with the  animation controller so it can take control of them:<\/p>\n<pre>  CAnimationGroup* pGroup = m_animCtrl.AddAnimationObject(&amp;m_animRect);\r\n  m_animCtrl.AddAnimationObject(&amp;m_animClr1);\r\n  pGroup-&gt;m_bAutodestroyAnimationObjects = FALSE;<\/pre>\n<p>The first line will add the m_animRect animation value to the  controller. Because this is the first animation value added to the controller,  the controller will create a new animation group and will return a pointer to  this group. The second line will add the m_animClr1 color animation value.  Because you are not specifying any animation group, the controller will add  m_animClr1 to the same animation group as m_animRect . The last line tells the  animation controller to not automatically delete the linked animation values.  This is done in this case because our animation values are member variables of  our class. Instead of defining animation values as member variables, you could  create an animation value using operator new, link it with the animation  controller in a specific group and tell the animation controller to  automatically delete objects when that animation group is destroyed. This makes  it easier to manage dynamically created animation variables.<\/p>\n<p>After all this, the animation controller is linked with  certain animation values and each animation value is linked with certain  animation transitions. Now it&#8217;s time to start the animation and this is simply  done with the following line:<\/p>\n<pre>  m_animCtrl.AnimateGroup(0);<\/pre>\n<p>This function required the ID of the group that you want to  animate. If you didn&#8217;t specify your own group ID earlier while adding your  animation variables to the controller, the default group ID 0 will be used. You  can add an animation variable to a specific group by setting the ID on the  animation variable as follows:<\/p>\n<pre>  m_animClr1.SetID(0, 1);\r\n  m_animCtrl.AddAnimationObject(&amp;m_animClr1);<\/pre>\n<p>The first line will set the group ID of m_animClr1 to 1 and  the second line will add the animation variable to the controller which will  then create a new group with ID 1. If you want to start this group, you need the  following line:<\/p>\n<pre>  m_animCtrl.AnimateGroup(1);<\/pre>\n<p>That&#8217;s it, when you run the application you will see that a  rectangle is changing color, position and size with a smooth animation  transition. The initial look of the window is as follows:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.nuonsoft.com\/images\/blog\/mfc_animation_start.jpg\" alt=\"\" width=\"445\" height=\"259\" \/><\/p>\n<p>After the smooth animation, the window will look as  follows:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.nuonsoft.com\/images\/blog\/mfc_animation_end.jpg\" alt=\"\" width=\"441\" height=\"256\" \/><\/p>\n<p>Download the following demo project to see it all working together:<br \/>\n<a href=\"http:\/\/www.nuonsoft.com\/downlds\/MFCAnimationAPIDemo.zip\">MFCAnimationAPIDemo.zip<\/a><\/p>\n<h2>Conclusion<\/h2>\n<p>This article serves as a brief introduction to the animation  API. The API includes some more advanced functionality like event handlers. For  example, you could configure an event handler that will be called each time the  status of the animation controller changes or each time a value of an animation  value changes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Microsoft Visual Studio 2010 Service Pack 1 includes a number of enhancements and new features for MFC developers. One of those changes is an animation API to make it easy for you to create animations in MFC applications. This article will briefly introduce this animation API. This articles was also posted on Codeguru.com.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,7,16,17],"tags":[102,45,30],"class_list":["post-563","post","type-post","status-publish","format-standard","hentry","category-c","category-mfc","category-microsoft","category-software-development","tag-animation-api","tag-visual-c-2010","tag-windows-7"],"_links":{"self":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/563","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/comments?post=563"}],"version-history":[{"count":4,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/563\/revisions"}],"predecessor-version":[{"id":568,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/posts\/563\/revisions\/568"}],"wp:attachment":[{"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/media?parent=563"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/categories?post=563"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.nuonsoft.com\/blog\/wp-json\/wp\/v2\/tags?post=563"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}