|
Introduction
(or why did I write this?)
I just got tired of having to do all the silly GDI+ initialization/deinitialization and double-buffering stuff, every time I wanted to use it. Pain in the behindment. So this class basically takes all that work away. All you do is implement a Draw function that takes a Graphics object, and the class does all the other GDI+ related stuff.
Usage
Ok. To use this puppy, all you've got to do is this:
- Derive your class from
CGdiPlusHelper, and (unless you've got some weird special needs), leave the tUseDoubleBuffering template argument alone. Double buffering REALLY speeds up the drawing speed, and helps eliminate flicker.
- Do NOT implement the
WM_PAINT message. Instead, implement a function with the following prototype: void Draw(Graphics* g, int nWidth, int nHeight);
This will be your main drawing function. You can use the passed in Graphics object to do all your drawing.
CHAIN_MSG_MAP the CGdiPlusHelper class, preferably as far in front of your MSG_MAP as possible. Oh, if you want to force a redraw on the window, call SetDirty and only then Invalidate. Otherwise, in double-buffered mode, it'll just reuse the same cached bitmap as before.
Note that the header file will automatically link in GdiPlus.lib, include GdiPlus.h, and using namespace GdiPlus;
it. i.e., You're all set to go to use GDI+ by just including this file.
Requirements
You need to install WTL7 and Microsoft Platform SDK to get WTL (although I THINK you only need it for the demo.) and GDI+.
Version History:
- 5/23/2002: Original article submission
Credits
Thanks to Alex Farber and his great article, which really contains all the CachedBitmap etc. stuff I used.
I also loosely based the drawing algorithm in the demo on Mazdak's article.
Speaking of Copyright
(you knew it was coming...)
The code is completely, utterly, and absolutely free. Feel free to use it in private or commercial applications, modify it, sit on it, or print it out and use it for toilet paper. God knows I've ignored enough copyrights from CodeProject to have the nerve to make my own. :) One thing though -- if this code messes up your computer or puts your project seven months behind schedule, it's not my fault. None of it is my fault. Not even that "format c:" somewhere in there. Er, just kidding. :) Oh yeah, needless to say, you can't claim this code as your own. (i.e., I'd hate for someone to reprint this code, and copyright the hell out of it. Not sure if that's possible anyhow, but it would suck. Greatly.)
P.S. Probably a pointless thing to say, but if you're going to rate the article badly, at least take the time to write a comment saying how I could improve it, or what you find inadequate about it...
| You must Sign In to use this message board. |
|
| | Msgs 1 to 18 of 18 (Total in Forum: 18) (Refresh) | FirstPrevNext |
|
 |
|
|
Thanks for the code, it really helps.
But.. I notice that all memory bitmaps are deleted when SetDirty is called. If all that is needed is a redraw, wouldn't it be enough to just clear (fill with background color or pattern) and re-draw onto them?
Maybe it would be better to have two types of 'dirty', one for the occasion when the size or format of the bitmap changes, and another for if only the contents change.
Just my 2c
Lex
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 CQTTDemoView: - Override OnEraseBackground to return TRUE.
- Override OnDraw: where:
to: QBufferDC bufferDC ( pDC ); Graphics g ( bufferDC.GetSafeHdc () );
QBufferDC: - On the constructor class QBufferDC: where: // Get the clipping boundary of the mother DC, in logical coordinates CRect rcClip; VERIFY ( pDC->GetClipBox ( rcClip ) != ERROR );
// Transform to device coordinates (pixels), and normalize pDC->LPtoDP ( rcClip); rcClip.NormalizeRect ();
if ( m_bufferBitmap.ReserveBitmap ( pDC, rcClip.Size () ) ) { ... ...
#ifdef QBUFFER_DEMO // In demo mode, change the color slightly so we can see which parts are updated if ( m_bDemoMode ) col ^= RGB ( rand () % 32, rand () % 32, rand () % 32 ); #endif
// Get the mother DC's clipping boundary in logical coordinates and fill it. VERIFY ( pDC->GetClipBox ( rcClip ) != ERROR );
// Transform to device coordinates (pixels), and normalize pDC->LPtoDP ( rcClip );
if ( mapmode != MM_TEXT ) { // Other mapping modes may lead to roundof errors, causing artefacts // on the screen. To compensate, we inflate the bounding rectangle with two pixels. CSize szPixels ( 2, 2 ); DPtoLP ( &szPixels ); rcClip.InflateRect ( szPixels.cx, szPixels.cy ); }
// DAKOT removed: //FillSolidRect ( rcClip, col );
// Initialize accumulation of boundary information SetBoundsRect ( NULL, DCB_ENABLE | DCB_ACCUMULATE | DCB_RESET );
// DAKOT added here: FillSolidRect ( rcClip, col ); }
to: // Get the clipping boundary of the mother DC, in logical coordinates CRect rcClip, rcBitmap; VERIFY ( pDC->GetClipBox ( rcClip ) != ERROR );
// Transform to device coordinates (pixels), and normalize rcBitmap.CopyRect ( &rcClip ); pDC->LPtoDP ( rcBitmap ); rcBitmap.NormalizeRect ();
if ( m_bufferBitmap.ReserveBitmap ( pDC, rcBitmap.Size () ) ) { ... ...
#ifdef QBUFFER_DEMO // In demo mode, change the color slightly so we can see which parts are updated if ( m_bDemoMode ) col ^= RGB ( rand () % 32, rand () % 32, rand () % 32 ); #endif
/************ COMMENTED by VMONSTER // Get the mother DC's clipping boundary in logical coordinates and fill it. VERIFY ( pDC->GetClipBox ( rcClip ) != ERROR );
// Transform to device coordinates (pixels), and normalize pDC->LPtoDP ( rcClip );
if ( mapmode != MM_TEXT ) { // Other mapping modes may lead to roundof errors, causing artefacts // on the screen. To compensate, we inflate the bounding rectangle with two pixels. CSize szPixels ( 2, 2 ); DPtoLP ( &szPixels ); rcClip.InflateRect ( szPixels.cx, szPixels.cy ); } ************/
// DAKOT removed: //FillSolidRect ( rcClip, col );
// Initialize accumulation of boundary information SetBoundsRect ( NULL, DCB_ENABLE | DCB_ACCUMULATE | DCB_RESET );
// DAKOT added here: FillSolidRect ( rcClip, col ); }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
CQTTDemoView: - Override OnEraseBackground to return TRUE.
- Override OnDraw: where: Graphics g ( pDC->GetSafeHdc () ); to: QBufferDC bufferDC ( pDC ); Graphics g ( bufferDC.GetSafeHdc () );
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This code works as advertized it has smooth redraws and flicker free. However the CPU usage is very high. I implemented this in an MFC dialog based application and I have 70% CPU usage when my program runs without causing any redraws and as soon as I do the CPU usage goes to 100%.
It surely maybe the way I am using it. In my Draw function I am doing the following:
I am using GDI+'s drawimage function to draw all my graphics.
I can comment out either the DrawBackGround function or the drawing of my buttons and either cuts the CPU usage to about half of what it was.
I seems that the code spends alot of time in the createoffscreengraphics even if nothing is changing.
Any suggestions?
// Fill background with image DrawBackGround( pGraphics, nWidth, nHeight );
// Display all buttons loaded from xml file std::vector<Button*>::iterator it; Button *pB = NULL;
for (it = vButtons.begin(); it != vButtons.end(); ++it) { pB = *it; if( m_CurrentPanel == pB->PanelName ) pB->Draw( pGraphics, m_ActiveButton ); }
// Display the current Time if( m_CurrentPanel == "main" ) //&& c_Theme.Status == "ON") DisplayTime( pGraphics );
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Unfortunately there is nothing you can do. If you want low CPU usage (in fact any acceptable performace) ditch GDI+ in favor of GDI. Currently, GDI+ it is absolutely useless for performance critical applications. GDI+ 1.0 has no hardware acceleration, hence the cpu usage is colossal. You'll have to wait for GDI+ 2.0... :(
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Not a clue, sorry.
At the very least it should be part of Longhorn (if thats anything like XP, I dont know much about it).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
hi
can anybody help me to implement this class in an already existing MFC 6.0 project? i'm not really familiar with ATL/WTL but i don't want to copy all methods and members in every view.
just by including the header into the project, i get this error message: "syntax error : missing ';' before identifier 'MESSAGE_HANDLER'"
i think this is due to the missing ATL support (which i don't really want)
i'd appriciate any hints...
|
| Sign In·View Thread·PermaLink | 4.00/5 (1 vote) |
|
|
|
 |
|
|
Yes, I meet the same problem with, I don't know how to solve it, who can give an answer?
thanks
Best regards
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
I have a class that provides double-buffering support with a single line that only requires a CDC pointer.
I use it for existing MFC 6.0 projects and can provide it if you like.
Craig.
Craig Muller Z Systems cmuller@zsystems.ca www.zsystems.ca
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
I still get flicker when I resize the window. Is this by design? Or is something wrong?
thanks!
r.S.
|
| Sign In·View Thread·PermaLink | 2.00/5 (2 votes) |
|
|
|
 |
|
|
actually what I'm doing is displaying the view in a splitter window... that is to say that I'm deriving my View class from CWindowImpl and not CFrameWindowImpl...
I verifed that the flickering does not happen with a CFrameWindowImpl derived class...
weird...
r.S.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Probably doesn't override WM_ERASEBKGRND, You need to override that and prevent the default background paint. Don't know about this WTL stuff. Also, I don't use the cached buffering. Here is some code I changed for another project I found on this or another site:
in ::OnDraw or OnPaint
CRect rect; GetClientRect(&rect); Rect rc(rect.left, rect.top, rect.Width(), rect.Height()); Bitmap bmp(rect.Width(), rect.Height()); Color cw; // Block for Graphics Graphics g(pDC->GetSafeHdc()); g.SetSmoothingMode(SmoothingModeHighQuality); g.SetInterpolationMode(InterpolationModeHighQualityBicubic); g.SetPixelOffsetMode(PixelOffsetModeHighQuality); if (m_bDoubleBuffer) { Graphics* memgraph = Graphics::FromImage(&bmp); memgraph ->SetSmoothingMode(SmoothingModeHighQuality); memgraph ->SetInterpolationMode(InterpolationModeHighQualityBicubic); memgraph ->SetPixelOffsetMode(PixelOffsetModeHighQuality); memgraph->FillRectangle(m_pBrushes[6], rect.left, rect.top, rect.Width(), rect.Height()); for (int i = 0; i < 6; i++) { memgraph->FillPath(m_pBrushes[i], & m_Paths[i]); memgraph->DrawPath(m_pPens[i], & m_Paths[i]); } g.DrawImage(&bmp, rect.left, rect.top, rect.right, rect.bottom); delete memgraph; } else { for (int i = 0; i < 6; i++) { g.FillPath(m_pBrushes[i], & m_Paths[i]); g.DrawPath(m_pPens[i], & m_Paths[i]); } };
Also need something similiar to this:
BOOL CQTTDemoView::OnEraseBkgnd(CDC* pDC) { // TODO: Add your message handler code here and/or call default if (m_bDoubleBuffer) return TRUE; else return CScrollView::OnEraseBkgnd(pDC); }
Marty
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
"windows picture and fax viewer" can preview almost every kinds of images. i was wondering about how they did it
Thanks.
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Um, thanks, but I'm not sure what your question has to do with my article.....?
---------------------------------------- ----I said my name wasn't important ---------------------------SlartiBartFast
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
You said it all. Less restriction naturally wins my points
Best regards, Paul.
Paul Selormey, Bsc (Elect Eng), MSc (Mobile Communication) is currently Windows open source developer in Japan.
|
| Sign In·View Thread·PermaLink | 1.50/5 (2 votes) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|