|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionFlicker free animated drawing had been a very hot issue with Win32 and MFC. Many excellent articles are available to explain the techniques to get a flicker free animated effect. As many of the reader know that most popular technique has been to use off-screen DC (device context) to do the entire complex drawing and then copying this off-screen DC to the screen DC directly. This technique is also known as double buffering. C# is projected by Microsoft as the future for C++ programmers. So like many
other C++ programmers, I used some of my spare time to play around with C# to
have a feel of it. A few days back I was trying to write an application in C# to
simulate an analog clock. After establishing a base frame work and seeing my
clock work (with flicker of course) I was excited to use the old double
buffering technique to let my clock animate smoothly. But my first dilemma was
when I could not find functions like Double-buffering technique the old wayI was glad to know that there was a way in C# to use the old Win32 techniques
for smooth animation. Although one cannot find direct implementation for
functions like [DllImport("msvcrt.dll")]
public static extern int puts(string c);
The above declaration will declare the function named /// <summary>
/// Summary description for Win32Support.
/// Win32Support is a wrapper class that imports all the
/// necessary functions that are used in old
/// double-buffering technique for smooth animation.
/// </summary>
public class Win32Support
{
/// <summary>
/// Enumeration to be used for those Win32 function
/// that return BOOL
/// </summary>
public enum Bool
{
False = 0,
True
};
/// <summary>
/// Enumeration for the raster operations used in BitBlt.
/// In C++ these are actually #define. But to use these
/// constants with C#, a new enumeration type is defined.
/// </summary>
public enum TernaryRasterOperations
{
SRCCOPY = 0x00CC0020, // dest = source
SRCPAINT = 0x00EE0086, // dest = source OR dest
SRCAND = 0x008800C6, // dest = source AND dest
SRCINVERT = 0x00660046, // dest = source XOR dest
SRCERASE = 0x00440328, // dest = source AND (NOT dest)
NOTSRCCOPY = 0x00330008, // dest = (NOT source)
NOTSRCERASE = 0x001100A6, // dest = (NOT src) AND (NOT dest)
MERGECOPY = 0x00C000CA, // dest = (source AND pattern)
MERGEPAINT = 0x00BB0226, // dest = (NOT source) OR dest
PATCOPY = 0x00F00021, // dest = pattern
PATPAINT = 0x00FB0A09, // dest = DPSnoo
PATINVERT = 0x005A0049, // dest = pattern XOR dest
DSTINVERT = 0x00550009, // dest = (NOT dest)
BLACKNESS = 0x00000042, // dest = BLACK
WHITENESS = 0x00FF0062, // dest = WHITE
};
/// <summary>
/// CreateCompatibleDC
/// </summary>
[DllImport("gdi32.dll", ExactSpelling=true,
SetLastError=true)]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
/// <summary>
/// DeleteDC
/// </summary>
[DllImport("gdi32.dll", ExactSpelling=true,
SetLastError=true)]
public static extern Bool DeleteDC(IntPtr hdc);
/// <summary>
/// SelectObject
/// </summary>
[DllImport("gdi32.dll", ExactSpelling=true)]
public static extern IntPtr SelectObject(IntPtr hDC,
IntPtr hObject);
/// <summary>
/// DeleteObject
/// </summary>
[DllImport("gdi32.dll", ExactSpelling=true,
SetLastError=true)]
public static extern Bool DeleteObject(IntPtr hObject);
/// <summary>
/// CreateCompatibleBitmap
/// </summary>
[DllImport("gdi32.dll", ExactSpelling=true,
SetLastError=true)]
public static extern IntPtr CreateCompatibleBitmap(
IntPtr hObject, int width, int height);
/// <summary>
/// BitBlt
/// </summary>
[DllImport("gdi32.dll", ExactSpelling=true,
SetLastError=true)]
public static extern Bool BitBlt(
IntPtr hObject,
int nXDest, int nYDest,
int nWidth, int nHeight,
IntPtr hObjSource, int nXSrc, int nYSrc,
TernaryRasterOperations dwRop);
}
Now I can use this Graphics memDC;
Bitmap memBmp;
memBmp = new Bitmap(this.Width, this.Height);
Graphics clientDC = this.CreateGraphics();
IntPtr hdc = clientDC.GetHdc();
IntPtr memdc = Win32Support.CreateCompatibleDC(hdc);
Win32Support.SelectObject(memdc, memBmp.GetHbitmap());
memDC = Graphics.FromHdc(memdc);
clientDC.ReleaseHdc(hdc);
One important point to note here is that every call to the function
Once you have Graphics clientDC = this.CreateGraphics();
// do drawing in memDC
// do drawing in memDC
// do drawing in memDC
IntPtr hdc = clientDC.GetHdc();
IntPtr hMemdc = memDC.GetHdc();
// transfer the bits from memDC to clientDC
Win32Support.BitBlt(hdc, 0, 0, this.Width, this.Height,
hMemdc, 0, 0, Win32Support.TernaryRasterOperations.SRCCOPY);
clientDC.ReleaseHdc(hdc);
memDC.ReleaseHdc(hMemdc);
This will have dramatic effect on the animation that you have been trying to produce. The sample application uses this technique when you click the "Offscreen Drawing Using BitBlt" radio button. Double-buffering technique the .NET wayLuckily we can achieve the same goal without any direct help from Win32 API.
Image rendering in .NET is very simple and efficient compared to MFC. There are
two functions in The technique is same, but the way to implement it differs a little bit. In
the code fragment below, we are using a Bitmap offScreenBmp;
Graphics offScreenDC;
offScreenBmp = new Bitmap(this.Width, this.Height);
offScreenDC = Graphics.FromImage(offScreenBmp);
Provided that we have created Graphics clientDC = this.CreateGraphics();
// do drawing in offScreenDC
// do drawing in offScreenDC
// do drawing in offScreenDC
clientDC.DrawImage(offScreenBmp, 0, 0);
I will recommend this technique as it does not involve any call to unmanaged code and is simpler in nature. The sample application uses this technique when you click the "Offscreen Drawing Using Image" radio button.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||