0

In my MFC dialog program, i want to update a bitmap in the dialog window every 2 seconds. I use a memory bitmap buffer for drawing into, and OnTimer() is called from an MFC timer every 2seconds, and calls UpdateRateGraphics() which draws to a bitmap in memory. The OnPaint() function copys the memory bitmap to the screen window with bitblt(), whenever necessary. Initialization is done in OnInitDialog(). Drawing works, as long as i call the drawing function UpdateRateGraphics() from within OnPaint(), directly before the bitblt. When I call the drawing function from the timer function, which is what i want, only a black square is shown on the screen from the bitblt, but the bitmap content, at the moment only a somewhat shifted green square, is missing. Why is that?

GlobVars.h:
EXTERN HDC          memDC;                      // Device Context of a memory 
EXTERN HBITMAP      memBitmap;                  // A bitmap to draw onto, will be placed in the memory device context
EXTERN HBITMAP      *memBitmapOld;              // A bitmap to draw onto, will be placed in the memory device context
EXTERN HBRUSH       brush;                      // A GDI brush to define fill color etc.
EXTERN HBRUSH       brushOld;                   //


// Initialization, at the end of OnInitDialog():
CPaintDC    dc(this);
memDC = CreateCompatibleDC(dc.m_hDC);
memBitmap = CreateCompatibleBitmap(dc.m_hDC, 200, 200);
// Select it. An application cannot select a single bitmap into more than one DC at a time.
SelectObject(memDC, memBitmap);



void CmfritzmonDlg::UpdateRateGraphics()
{
    // Setup a GDIO brush object with fill color
    brush = CreateSolidBrush(RGB(0, 0xff, 0));
    // Select it
    brushOld = (HBRUSH) SelectObject(memDC, brush);
    // draw a rectangle using brush and memDC as destination
    Rectangle(memDC, 10, 10, 200, 200);
    SelectObject(memDC, brushOld);
    DeleteObject(brush);

    Invalidate();   // NEW, after adding this, it is working!
}



void CmfritzmonDlg::OnTimer(UINT_PTR nIDEvent)
{
    // cyclically called from SetTimer()
    UpdateRateGraphics();       // when called here, not ok !!!
    CDialogEx::OnTimer(nIDEvent);
}


void CmfritzmonDlg::OnPaint()
{
    if (IsIconic()) {
    } else {
        UpdateRateGraphics();       // When called here, OK !!!
        CPaintDC dc(this);
        BitBlt(dc.m_hDC, 0, 0, 200, 200, memDC, 0, 0, SRCCOPY);
    //  CDialogEx::OnPaint();
    }
}


void CmfritzmonDlg::OnDestroy()
{
    CDialogEx::OnDestroy();
    // Delete Objects for bitmap drawing
    SelectObject(memDC, memBitmapOld);
    DeleteObject(memBitmap);
    DeleteDC(memDC);
}
Fred
  • 1
  • 2
  • 1
    Don't have any code to look at. I'd first look at how you get an HDC within your OnTimer() handler, but as there is nothing to look at, there is nothing to say. – Joseph Willcoxson Jan 11 '17 at 15:53
  • Do you need to trigger a repaint after modifying the bit map in the `OnTimer()`? `InvalidateRect()`. https://msdn.microsoft.com/en-us/library/windows/desktop/dd145002(v=vs.85).aspx – Richard Chambers Jan 11 '17 at 16:07
  • 1
    Your rendering code doesn't take the time into account, so the rendered image doesn't change over time. Even if it was rendered, you wouldn't notice any difference. You need to trigger a repaint, so make sure the system generates a `WM_PAINT` message by calling [CWnd::Invalidate](https://msdn.microsoft.com/library/49a832ee-bc34-4126-88b3-bc1d9974f6c4.aspx#cwnd__invalidate) (or related member functions). – IInspectable Jan 11 '17 at 16:13
  • Wow, it works, just addes invalidate(); as a last line to to UpdateRateGraphics(). Thanks for the solution :) – Fred Jan 11 '17 at 19:36
  • While it is OK to call `Invalidate()` in `UpdateRateGraphics()` (meaning: my data have been updated, now update the display too), I can't see why you need to call `UpdateRateGraphics()` in `OnPaint()`. Paint requests (`WM_PAINT`/`OnPaint()`) may occur as a result of resizing/moving/unhiding etc of a part of (or the whole) window, and such an event doesn't warrant a recalculation of your data as well (eg just imagine having to retrieve these from a database, it would cause accesses depending on window drawing, which is of course not OK). Consider removing this call. – Constantine Georgiou Jan 12 '17 at 12:05
  • Why not just use CMemDC? It does it all under the hood. – Andrew Truckle Jan 17 '17 at 14:16

0 Answers0