Introduction
In this article, I want to show a simple workaround for a bug in the MFC Feature Pack, and explain how I arrived at the solution.
Background
When you open the attached application and move your mouse, you will notice that the folder icon of the first edit control flickers heavily.
To find the cause of this problem, I used WinSpector, but Spy++ works as well. Open up Spy++ and show the messages sent to the first edit control. When you move the mouse above the control, you will see many WM_NCPAINT
-messages:
So let's look up the MFC source code, to find out what the CMFCEditBrowseCtrl
does with the WM_NCPAINT
-Message. The code is located in the file afxeditbrowsectrl.cpp.
BEGIN_MESSAGE_MAP(CMFCEditBrowseCtrl, CEdit)
...
ON_WM_NCPAINT()
...
END_MESSAGE_MAP()
...
void CMFCEditBrowseCtrl::OnNcPaint()
{
CEdit::OnNcPaint();
...
OnDrawBrowseButton(&dc, rect, m_bIsButtonPressed, m_bIsButtonHighlighted);
...
}
Stepping further into OnDrawBrowseButton
we arive at CMFCVisualManagerWindows::OnDrawBrowseButton
(located in afxvisualmanagerwindows.cpp)
BOOL CMFCVisualManagerWindows::OnDrawBrowseButton(...)
{
...
pDC->FillRect(rect, &(GetGlobalData()->brWindow));
...
}
So everythime, the button is drawn via WM_NCPAINT
, the visualmanager first erases the area, and then redraws everything. This causes the flickering.
Many methods of MFC-Feature Pack classes are declared virtual
, so to workaround this issue, we can easily add our own, customized implementation instead.
Using the Code
To remove the flicker, replace the CMFCEditBrowseCtrl
with this fixed implementation:
class CMFCEditBrowseCtrlNoFlicker : public CMFCEditBrowseCtrl
{
public:
void OnDrawBrowseButton(CDC* pDC, CRect rect, BOOL bIsButtonPressed, BOOL bIsButtonHot) override
{
CMemDC dc(*pDC, rect);
__super::OnDrawBrowseButton(&dc.GetDC(), rect, bIsButtonPressed, bIsButtonHot);
}
};
In this implementation, we use a CMemDC
, i.e., we buffer all drawing commands. So technically, the button is still erased and redrawn many times, but since only the final result is drawn on the screen, the flickering is gone.
History
- 2018-04-03: First version (skip drawing when flags did not change)
- 2018-04-16: Updated implementation with CMemDC (fixes missing redraw after minimizing the application)