GDI Problem - BitBlt() Doesn't Seem To Be Doing Anything
I'm using the GDI to draw to a memory bitmap, which is then copied to the window using BitBlt(). When I redraw the whole window it works correctly, but when I try to update only part of the window it doesn't redraw correctly and, after weeks of trying, I still can't work out why.
Below I've included the relevant code along with the values for one debug run.
When an area of the window needs to be updated I call this function to invalidate the updated region:
Code:
void RedrawActiveArea()
{
m_bRedrawActiveArea = true;
InvalidateRect(&m_rctActiveAreaRect, false);
}
The values of m_rctActiveAreaRect are {top=0 bottom=373 left=586 right=605}
Invalidating a region obviously causes OnPaint to be called:
Code:
void OnPaint()
{
RECT rctUpdateRect;
if (GetUpdateRect(&rctUpdateRect))
{
PAINTSTRUCT Ps;
CDC* pDC = BeginPaint(&Ps);
if (m_bFullRedraw)
{
m_pMainArea->FullRedraw(pDC);
m_bFullRedraw = false;
}
else if (bRedrawActiveArea)
{
m_pMainArea->DrawActiveArea(pDC);
m_bRedrawActiveArea = false;
}
else
{
m_pMainArea->CopyToWindow(pDC, m_rctUpdateRect);
}
EndPaint(&Ps);
}
}
Here rctUpdateRect is {top=0 bottom=373 left=586 right=605} as expected. bRedrawActiveArea is true so DrawActiveArea() is called.
For debugging purposes DrawActiveArea() is just drawing a green rectangle over the invalidated rectangle:
Code:
void CMainArea::DrawActiveArea(CDC* pdcWindowDC)
{
m_pdcMemDC->SelectObject(penGreenPen);
m_pdcMemDC->SelectObject(brshGreenBrush);
m_pdcMemDC->Rectangle(&m_rctActiveAreaRect);
int iReturn = pdcWindowDC->BitBlt(m_rctActiveAreaRect.left,
m_rctActiveAreaRect.top,
m_rctActiveAreaRect.right-m_rctActiveAreaRect.left,
m_rctActiveAreaRect.bottom-m_rctActiveAreaRect.top,
m_pdcMemDC,
m_rctActiveAreaRect.left,
m_rctActiveAreaRect.top,
SRCCOPY);
}
Here m_rctActiveAreaRect is the same as before: {top=0 bottom=373 left=586 right=605}.
A green rectangle should be drawn over the active area in the memory bitmap, and that area should then be copied to the window, so the green rectangle should be displayed on the window. Sadly, it doesn't happen and nothing changes in the window.
If, after this process, I drag another window over my window (causing the invalidated regions to be re-copied from the memory bitmap) the green rectangle appears. It therefore seems that the rectangle is being drawn to the memory bitmap, but is failing when being copied to the window. I therefore assumed that BitBlt() was failing, but it returns 1 and nonzero indicates success.
I'm therefore completely at a loss as to why the green rectangle isn't appearing on the window first time. All the numbers are as I'd expect them to be when I debug and everything looks right to me.
Can anyone suggest what might be going wrong?
Thanks for any advice you can offer.
Re: GDI Problem - BitBlt() Doesn't Seem To Be Doing Anything
Quote:
Originally Posted by
Gav80K
Below I've included the relevant code along with the values for one debug run.
Are you sure ???? as bRedrawActiveArea is not defined, initialized nor modified...should this actually be m_bRedrawActiveArea ??
Code:
else if (bRedrawActiveArea)
{
m_pMainArea->DrawActiveArea(pDC);
m_bRedrawActiveArea = false;
}
Re: GDI Problem - BitBlt() Doesn't Seem To Be Doing Anything
Since you are trying to use BitBlt, it might help if you show how you created your m_pdcMemDC. I also don't see any code showing you drawing into the m_pdcMemDC before the attempt to BitBlt it.
Also, in your code below, you have selected some objects into a DC, but you don't release them anywhere I can see. This can cause problems further down the road.
Quote:
Originally Posted by
Gav80K
Code:
void CMainArea::DrawActiveArea(CDC* pdcWindowDC)
{
m_pdcMemDC->SelectObject(penGreenPen);
m_pdcMemDC->SelectObject(brshGreenBrush);
m_pdcMemDC->Rectangle(&m_rctActiveAreaRect);
int iReturn = pdcWindowDC->BitBlt(m_rctActiveAreaRect.left,
m_rctActiveAreaRect.top,
m_rctActiveAreaRect.right-m_rctActiveAreaRect.left,
m_rctActiveAreaRect.bottom-m_rctActiveAreaRect.top,
m_pdcMemDC,
m_rctActiveAreaRect.left,
m_rctActiveAreaRect.top,
SRCCOPY);
}
Re: GDI Problem - BitBlt() Doesn't Seem To Be Doing Anything
Thanks for the replies. It seems the problem wasn't in the part of the code I included, but where I created the window. Unfortunately solving it creates a bigger problem.
I read that creating the window with WS_EX_COMPOSITED solved the GDI flicker issue. It did but it also lead to you having to redraw parts of the window unnecessarily, so I switch to using a memory bitmap which allowed you to copy invalidated areas to the window without having to redraw them. After implementing the memory bitmap I forgot to remove the WS_EX_COMPOSITED, so it was effectively triple buffered which was presumably why the updates to the bitmap weren't ending up on the window.
After removing WS_EX_COMPOSITED the drawing now works correctly. However, it also causes the whole program to break. For example, all timers created with SetTimer() stop working and the timer function never gets called, and the applications windows or no longer receiving paint messages when they become partially obscured by another window, so they don't get redrawn. It's like something is going wrong with the message queue.
I'm at a loss as to how changing:
Code:
LPCSTR szWinClass = AfxRegisterWndClass(0, LoadCursor(NULL, IDC_CROSS));
CreateEx(WS_EX_COMPOSITED, szWinClass, "Graph", WS_POPUP | WS_VISIBLE | WS_BORDER, *kprctPosition, I.m_pMainWnd, NULL);
to
Code:
LPCSTR szWinClass = AfxRegisterWndClass(0, LoadCursor(NULL, IDC_CROSS));
CreateEx(0, szWinClass, "Graph", WS_POPUP | WS_VISIBLE | WS_BORDER, *kprctPosition, I.m_pMainWnd, NULL);
could cause these problems. If I add the WS_EX_COMPOSITED back in everything starts working again.
Any idea what could have caused this?
Re: GDI Problem - BitBlt() Doesn't Seem To Be Doing Anything
Further to the above post, I've got three transparent overlay windows that can appear on top of the graph. All of them are created with WS_EX_COMPOSITED purely because I remember finding that if I didn't the whole program breaks. They're created like this
Code:
LPCSTR szWinClass = AfxRegisterWndClass(0, LoadCursor(NULL, IDC_ARROW));
CreateEx(WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TRANSPARENT,
szWinClass,
"LineOverlay",
WS_POPUP | WS_VISIBLE,
pntWinPos.x,
pntWinPos.y,
m_pchtChart->m_iChartWidth,
m_pchtChart->m_iChartHeight,
m_pchtChart->m_hWnd,
NULL);
If I remove the WS_EX_COMPOSITED from any one of these I get the problem where everything breaks. I hoped removing it from all of them would solve the problem, but sadly it doesn't. I assume I'm an invalid combination when creating the windows or something, but I can't see what's wrong.
Re: GDI Problem - BitBlt() Doesn't Seem To Be Doing Anything
Quote:
Originally Posted by
Gav80K
Further to the above post, I've got three transparent overlay windows that can appear on top of the graph. All of them are created with WS_EX_COMPOSITED purely because I remember finding that if I didn't the whole program breaks.
If you googled "WS_EX_COMPOSITED", you would find many issues with this style.
Regards,
Paul McKenzie