问题
I want to use a bitmap to read the current view window, make some changes to it and output the bitmap back to the view. The program is supposed to read a white window and draw a square against this background. However, the image that I see in the final window is a square in a black background.
void CScribbleView::OnLButtonDown(UINT, CPoint point)
{
//CClientDC dc(this);
//OnPrepareDC(&dc);
HBITMAP initialMap;
RECT t;
BITMAP bmpScreen;
GetClientRect(&t);
initialMap = CreateCompatibleBitmap(GetDC()->m_hDC,t.right-t.left,t.bottom-t.top);
HDC tempDC = CreateCompatibleDC(GetDC()->m_hDC);
SelectObject(tempDC,initialMap);
SelectObject(tempDC,getStockObject(BLACK_PEN);
SelectObject(tempDC,GetStockObject(WHITE_BRUSH));
Rectangle(tempDC,100,100,200,200);
BitBlt(GetDC()->m_hDC,clientR.left,clientR.top,clientR.right-clientR.left,t.bottom-clientR.top,tempDC,0,0,SRCCOPY);
}
This is the output:
I suspect that the bitmap was not properly read from my original DC. So I later decided to use a different way of retrieving DC, the CClientDC, instead of GetClientDC()->m_hDC.
void CScribbleView::OnLButtonDown(UINT, CPoint point)
{
CClientDC dc(this);
OnPrepareDC(&dc);
HBITMAP initialMap;
RECT t;
BITMAP bmpScreen;
GetClientRect(&t);
initialMap = CreateCompatibleBitmap(dc.m_hDC,t.right-t.left,t.bottom-t.top);
HDC tempDC = CreateCompatibleDC(dc.m_hDC);
SelectObject(tempDC,initialMap);
SelectObject(tempDC,getStockObject(BLACK_PEN);
SelectObject(tempDC,GetStockObject(WHITE_BRUSH));
Rectangle(tempDC,100,100,200,200);
BitBlt(dc.m_hDC,clientR.left,clientR.top,clientR.right-clientR.left,t.bottom-clientR.top,tempDC,0,0,SRCCOPY);
}
Now, the new program doesn't show anything; it is the same white background as I had originally started with. What is the difference between these two DC's and how can I fix my problem?
回答1:
These WinAPI functions all require cleanup: ::CetDC
, ::CreateCompatibleDC
, ::CreateCompatibleBitmap
. See documentation for each of them. Without cleanup, your program could quickly use its 10,000 GDI resource limit and crash.
You don't have to worry about cleanup if you use the MFC version of these WinAPI functions (you should still see the docs to make sure). This is MFC example for double-buffering:
void foo::OnLButtonDown(UINT nFlags, CPoint point)
{
CWnd::OnLButtonDown(nFlags, point);
CClientDC dc(this);
CRect rect;
GetClientRect(&rect);
//create memory dc
CDC memdc;
memdc.CreateCompatibleDC(&dc);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
memdc.SelectObject(bitmap);
//some random drawings:
memdc.SelectObject(GetStockObject(BLACK_PEN));
memdc.SelectObject(GetStockObject(GRAY_BRUSH));
memdc.Rectangle(10, 10, 100, 100);
//draw memory DC to destination DC
dc.BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY);
};
Your goal is probably to draw on screen buffer, as suggested in comments. In which case you declare memdc
and bitmap
as member data:
//declare member data
CDC m_memdc;
CBitmap m_bitmap;
CRect m_rect;
CPoint m_point;
void foo::initialize_once()
{
ASSERT(IsWindow(m_hWnd));
GetClientRect(&m_rect);
//create memdc
m_memdc.CreateCompatibleDC(0);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&m_memdc, m_rect.Width(), m_rect.Height());
m_memdc.SelectObject(bitmap);
//initialize memdc background color
m_memdc.FillSolidRect(m_rect, RGB(255,255,255));
}
void foo::OnLButtonDown(UINT nFlags, CPoint point)
{
__super::OnLButtonDown(nFlags, point);
m_point = point;
m_memdc.MoveTo(point);
};
void OnMouseMove(UINT nFlags, CPoint point)
{
__super::OnMouseMove(nFlags, point);
if (!(nFlags & MK_LBUTTON)) return;
m_point = point;
m_memdc.LineTo(point);
CClientDC dc(this);
dc.BitBlt(0, 0, m_rect.Width(), m_rect.Height(), &m_memdc, 0, 0, SRCCOPY);
}
来源:https://stackoverflow.com/questions/37873650/mfc-bitmap-reads-a-completely-black-bitmap