C++ mfc位图读取一个完全黑色的位图

C++ mfc位图读取一个完全黑色的位图,c++,bitmap,mfc,C++,Bitmap,Mfc,我想使用位图读取当前视图窗口,对其进行一些更改,然后将位图输出回视图。程序应该读取一个白色窗口,并在此背景下绘制一个正方形。然而,我在最后一个窗口中看到的图像是黑色背景中的正方形 void CScribbleView::OnLButtonDown(UINT, CPoint point) { //CClientDC dc(this); //OnPrepareDC(&dc); HBITMAP initialMap; RECT t; BITMAP bm

我想使用位图读取当前视图窗口,对其进行一些更改,然后将位图输出回视图。程序应该读取一个白色窗口,并在此背景下绘制一个正方形。然而,我在最后一个窗口中看到的图像是黑色背景中的正方形

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);
}
这是输出:

我怀疑位图没有从我的原始DC正确读取。因此,我后来决定使用另一种检索DC的方法CClientDC,而不是GetClientDC()->m_hDC


现在,新的程序没有显示任何内容;它的白色背景与我最初使用的相同。这两个DC之间有什么区别?如何解决我的问题?

这些WinAPI函数都需要清理:
::CetDC
::CreateCompatibleDC
::CreateCompatibleBitmap
。请参阅其中每一项的文档。如果没有清理,您的程序可能会很快使用其10000 GDI资源限制并崩溃

如果您使用这些WinAPI函数的MFC版本,则不必担心清理问题(您仍应查看文档以确保)。这是双缓冲的MFC示例:

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);
}; 
您的目标可能是按照注释中的建议,在屏幕上绘制缓冲区。在这种情况下,您将
memdc
bitmap
声明为成员数据:

//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);
}   

好的,createCompatibleBitmap函数似乎不会创建包含客户端窗口中相同图像的位图。相反,它只是创建一个与客户端窗口大小相同的图像,所有像素颜色初始化为零(黑色)。无论如何,读取当前视图窗口是个坏主意。你到底想实现什么?说来话长。我正在做一个画画程序,就像画画一样。现在我正在画矩形。最初,当我按下并拖动鼠标时,我会在OnMouseMove函数中绘制一个新的矩形。然而,这就留下了一堆落后的矩形。因此,我决定在按下鼠标时将客户端视图保存在位图中。在OnMouseMove函数中,我只需在保存的视图上绘制,覆盖在拖动操作中创建的上一个矩形上。最好是将整个图形绘制到屏幕外的缓冲区中,然后将该缓冲区返回到视图窗口。是的,这就是我试图回答的问题,在CDC或CCC内部使用HDC通常是一个坏主意吗?例如,矩形(m_memdc.m_hDC,100100200200),这不是问题。您还可以依次使用
m_memdc.Rectangle(100100200200)
,这将调用核心WinAPI函数,即
::Rectangle(m_memdc.m_hDC,100100200200)
//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);
}