Solved

Flicker in CWnd

Posted on 1997-11-04
9
800 Views
Last Modified: 2013-11-20
I am drawing in a CWnd derived class using a CPaintDC device context. I am displaying real-time data that could change every 200 miliseconds. I have created rectangular areas in my client area for display and draw to them using the device context method DrawText. When the data does not change rapidly, the display flickers. Is there any way to draw to a CWnd derived object at this rate and not have it flicker?
0
Comment
Question by:JagerM
  • 4
  • 4
9 Comments
 
LVL 2

Expert Comment

by:anichini
ID: 1309315
You need to render into an offscreen bitmap and blit that into your CPaintDC. The step-by-step:

1) Add these members to your CWnd-derived class:

protected:
CDC *m_pMemDC; // memory dc
CBitmap *m_pBitmap, *m_pOldBitmap; // bitmap

2) Have your constructors include these lines:
m_pMemDC = NULL;
m_pBitmap = NULL;

3) Override your the WM_SIZE message and have it include these lines:

void CYourWnd::OnSize(UINT nType, int cx, int cy)
{
    if(m_pBitmap != NULL)
    {
        m_pMemDC->SelectObject(m_pOldBitmap);
        delete m_pBitmap;
    }
    if(m_pMemDC != NULL)
    {
       delete m_pMemDC;
    }
    m_pMemDC = new CDC;
    m_pBitmap = new CBitmap;
    m_pMemDC->CreateCompatibleDC(NULL); // use screen DC
    m_pBitmap->CreateCompatibleBitmap(NULL, cx, cy);
    m_pOldBitmap = m_pMemDC->SelectObject(m_pBitmap);
}

3) Make your WM_PAINT handler look like this:

void CYourWnd::OnPaint()
{
CPaintDC dc(this);
CDC *pDC = m_pMemDC;
CRect rectClip;
dc.GetClipBox(&rectClip);

doDraw(pDC); // draw your shtuff. Make sure to erase the drawing surface using FillRect or something

dc.BitBlit(rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(), m_pMemDC, rectClip.left, rectClip.top, SRCCOPY);
}

4) Override WM_ERASEBKGND with ClassWizard. Make it look like this:

BOOL CYourWnd::OnEraseBkgnd(CDC *pDC)
{
return TRUE;
}

5) Override WM_DESTROY and add these lines:

void CYourWnd::OnDestroy()
{
    if(m_pBitmap != NULL)
    {
        m_pMemDC->SelectObject(m_pOldBitmap);
        delete m_pBitmap;
    }
    if(m_pMemDC != NULL)
    {
       delete m_pMemDC;
    }
}

// END_CODE
A couple of caveats:

This doesn't handle printing. In general, you shouldn't use offscreen drawing when drawing to a printer DC. A simple check in your OnPaint can determine if you are printing or not.
If you wanted to be really suave, you'd pass the clip rect to your doDraw() function and only redraw the parts that were going to be blitted anyway.

Hope this helps.
0
 

Author Comment

by:JagerM
ID: 1309316
This doesn't seem to work. I keep getting a first chance exception from the CreateCompatibleBitmap() method in the OnSize() routine.
0
 
LVL 8

Expert Comment

by:MikeP090797
ID: 1309317
When using CreateCompatibleDC and CreateCompatibleBitmap the first param should be a dc handle and not a NULL. you can obtain the handle by calling CClientDC dc(this); dc->m_hdc
0
 
LVL 2

Expert Comment

by:anichini
ID: 1309318
Already figured this one out. Waiting for a comment form anichini. Sorry.
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:JagerM
ID: 1309319
Answering for credit I hope?

0
 
LVL 2

Accepted Solution

by:
anichini earned 100 total points
ID: 1309320
1. A little bitter? It doesn't seem like EE has a method to hold a dialog between expert and asker. How do you expect to be given credit for something that hasn't been tested? If there is a way to hold this dialog, please inform me of it. It wasn't my intent to not award any points, only clarify the answer.

2. As far as the solution goes. Do you have to have members (CDC* and CBitmap* 's) or can you just create the variables you need in OnPaint(), do the drawing, and repalce all GDI resources? I have a CRect member that holds the cleint rect and is updated every time OnSize() is called. This can be used for the CreateCompatibleBitmap call.

3. Fooling around with this type of solution, there still seems to be noticeable flicker? I'm basically redrawing every 200mS, is this going to happen no matter what or should there be absolutely no flicker?

No hard feelings.

0
 

Author Comment

by:JagerM
ID: 1309321
1) Not bitter at you, but at the way EE is set up. I don't like EE's interface and it can be frustrating at times. For example, it would be nice for the asker to be able to divvy up points among multiple experts, because I agree that I shouldn't get full credit for an answer that didn't work 100% the way it should, and MikeP probably should have gotten some points for pointing out the problem, etc.

As for getting credit for something that hasn't been tested: You have to understand that I have a real job that I get paid for, and that I answer these questions for free. I don't have time to completely test every answer I post. I usually test answers that I haven't ever done before. But I have a lot of experience with what you are trying to do - I've written a lot of offscreen drawing apps, and I know that the above method works. I just screwed up one of the details when writing the answer.

2) You could do that, but creating a DC/bitmap can be expensive, so its best to do the creation/destruction only when you need to (when the size of the window changes)

3) There shouldn't be a flicker. Make sure that the only drawing command you send to the CPaintDC is the bitblt call. Can you post a comment with the relevant portions of your code, perhaps I can figure out whats going on by taking a look.

0
 
LVL 2

Expert Comment

by:anichini
ID: 1309322
I got it working this morning and it looks great. I noticed memory leaks for a CBitmap and CDC members and found that my CWnd derived class's OnDestroy wasn't getting called for some reason. Any thoughts? I put that code into the destructor and it works fine. Thanks for your help, this is a great trick to know!
0
 

Author Comment

by:JagerM
ID: 1309323
If you just delete your window without calling DestroyWindow() on it, overriden OnDestroy methods will not get called:

so if you do this:
delete pMyWnd;

instead you should do this:
pMyWnd->DestroyWindow();
delete pMyWnd;

The reason: when the destructor is called, it first calls all the derived classes' destructors. The derived classes' destructors all remove their entries from the vtable for the object (it's part of the C++ language definition). By the time it gets to CWnd::~CWnd, where DestroyWindow is called if the window has not already been destroyed, your override of OnDestroy has been erased by CYourWnd::~CYourWnd.

0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now