1

Instead of drawing using Moveto and LineTo, I want to use a hand made bitmap, that I will fill with an array that I will create myself, and use that to fill the screen.

Right now, the array is just filled with red, But when I draw to the screen I get all black.

This is the code:

void CCGWorkView::OnDraw(CDC* pDC)
{
    CCGWorkDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    pDCToUse->FillSolidRect(&r, world.bg_color);

    BITMAPINFO bminfo;
    CPaintDC hdc(this);
    CRect rect;
    GetWindowRect(&rect);

    int h = rect.bottom - rect.top,
        w = rect.right - rect.left;
    int *bits = new int[w * h];

    HDC hdcMem = CreateCompatibleDC(hdc);
    HBITMAP bm = CreateCompatibleBitmap(hdc, w, h);

    SelectObject(hdcMem, bm);

    bminfo.bmiHeader.biSize = sizeof(bminfo.bmiHeader);
    bminfo.bmiHeader.biWidth = w;
    bminfo.bmiHeader.biHeight = h;
    bminfo.bmiHeader.biPlanes = 1;
    bminfo.bmiHeader.biBitCount = 32;
    bminfo.bmiHeader.biCompression = BI_RGB;
    bminfo.bmiHeader.biSizeImage = 0;
    bminfo.bmiHeader.biXPelsPerMeter = 1;
    bminfo.bmiHeader.biYPelsPerMeter = 1;
    bminfo.bmiHeader.biClrUsed = 0;
    bminfo.bmiHeader.biClrImportant = 0;

    for (int i = 0; i < w * h; i++) {
        bits[i] = RGB(255, 0, 0);
    }

    SetDIBits(hdcMem, bm, 0, h, bits, &bminfo, 0);

    BitBlt(hdc, rect.left, rect.top, w, h, hdcMem, rect.left, rect.top, SRCCOPY);

    DeleteDC(hdcMem);
    DeleteObject(bm);
    delete bits;
}
Shasi
  • 13
  • 4
  • Two points here, first `CPaintDC` paints on the window's client area, therefore you should have called `GetClientRect()` instead of `GetWindowRect()`. Second, you must select `bm` out of `hdcMem`, before destroying any of the two objects - select the previous bitmap (returned by the previous call to `SelectObject()`) into `hdcMem`. Not sure if these will solve your problem though, however the first one is quite likely. – Constantine Georgiou Dec 02 '19 at 21:31
  • And forgot to mention, in `BitBlt()' the `x` and 'y' coordinates (destination rectangle), as well as `x1` and `y1` (source rectangle) should all be 0. It will work as is though, because the `top` and `left` coordinates returned by `GetClientRect()` are 0 anyway. – Constantine Georgiou Dec 02 '19 at 21:48

1 Answers1

1

There are a couple of issues in your code.

First, you don’t need CPaintDC, as the pDC is passed into your OnDraw() function. This may have actually caused your black display, as the newly created DC has a one pixel black-and-white bitmap selected into it, and when you call CreateCompatibleBitmap(), that bitmap is also monochrome.

Second, SetDIBits() expect RGBQUAD colors (https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-rgbquad), NOT RGB.

And, as Constantine Georgiou suggested, you should de-select your bitmap out of DC before deleting it to avoid resource leaks, even if MFC handles it for you.

Here is modified code:

void CMFCApplication1View::OnDraw(CDC* pDC)
{
    CMFCApplication1Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    //pDCToUse->FillSolidRect(&r, world.bg_color);

    BITMAPINFO bminfo;
    CRect rect;
    GetClientRect(&rect);

    int h = rect.bottom - rect.top,
        w = rect.right - rect.left;
    int* bits = new int[w * h];

    HDC hdcMem = CreateCompatibleDC(pDC->m_hDC);
    HBITMAP bm = CreateCompatibleBitmap(pDC->m_hDC, w, h);

    HGDIOBJ hOld = SelectObject(hdcMem, bm);

    bminfo.bmiHeader.biSize = sizeof(bminfo.bmiHeader);
    bminfo.bmiHeader.biWidth = w;
    bminfo.bmiHeader.biHeight = h;
    bminfo.bmiHeader.biPlanes = 1;
    bminfo.bmiHeader.biBitCount = 32;
    bminfo.bmiHeader.biCompression = BI_RGB;
    bminfo.bmiHeader.biSizeImage = 0;
    bminfo.bmiHeader.biXPelsPerMeter = 1;
    bminfo.bmiHeader.biYPelsPerMeter = 1;
    bminfo.bmiHeader.biClrUsed = 0;
    bminfo.bmiHeader.biClrImportant = 0;

    RGBQUAD red = { 0, 0, 255, 0 };
    for (int i = 0; i < w * h; i++) {
        bits[i] = *((int*)&red);
    }

    SetDIBits(hdcMem, bm, 0, h, bits, &bminfo, DIB_RGB_COLORS);

    BitBlt(pDC->m_hDC, rect.left, rect.top, w, h, hdcMem, rect.left, rect.top, SRCCOPY);

    SelectObject(hdcMem, hOld);
    DeleteDC(hdcMem);
    DeleteObject(bm);
    delete[] bits;
}
Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27
  • 1
    The [`CPaintDC` c'tor](https://learn.microsoft.com/en-us/cpp/mfc/reference/cpaintdc-class#public-constructors) does not create a device context. It simply returns the result from calling [`CWnd::BeginPaint`](https://learn.microsoft.com/en-us/cpp/mfc/reference/cpaintdc-class#public-constructors), which wraps the call to [`BeginPaint`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-beginpaint). That's still a bug, as [`CView::OnDraw`](https://learn.microsoft.com/en-us/cpp/mfc/reference/cview-class#ondraw) gets called for reasons other than painting to the screen. – IInspectable Dec 03 '19 at 13:19