locked
Painting the mainfram client area

    Question

  • Nowadays CMDIFrameWndEx has a member

    CMDIClientAreaWnd m_wndClientArea;

    which sits on top of, and looks after, its client area.

    It seems that  CMDIClientAreaWnd paints itself grey on response to WM_PAINT (and not WM_ERASEBKGND ).

    I want it another colour!

    So following one suggestion on the now-defunct MS newsgroups, in the PreTranslateMessage() of my derived main frame I tried:

    ==============

    BOOL CMyMainFrame::PreTranslateMessage( MSG *pMsg )
    {
     BOOL bResult = FALSE;
        // Look after redrawing of frame client area:
        if( pMsg->hwnd &&  (pMsg->hwnd == m_wndClientArea.m_hWnd) )
       {
           if( pMsg->message==WM_PAINT )
           {
              HDC  hDC = ::GetDC( m_wndClientArea.m_hWnd );
              RECT rect;
              m_wndClientArea.GetClientRect( &rect );
               // I don't really want it black but this
               // will do for testing the concept:
              HBRUSH hBrush = (HBRUSH)::GetStockObject( BLACK_BRUSH );
              ::FillRect( hDC, &rect, hBrush );
              ::ValidateRect( m_wndClientArea.m_hWnd , &rect );
              ::ReleaseDC( m_wndClientArea.m_hWnd, hDC );
              bResult = TRUE;
            }
       }
        if( !bResult )
       {
            bResult = CMDIFrameWndEx::PreTranslateMessage(pMsg);
       }
       return bResult;
    }

    ===========

    Now I am always nervous about doing anything non-standard with WM_PAINT messages because of the peculiar way in which they're queued, and my nervousness seems justified here.   The window is painted black (whoopee!) but...

    When I open a document, the black is momentarily painted the old default grey before the document fills the frame's client area  (as I'm using a tabbed MDI interface).

    Is there any obvious slight variation on this method which would stop this?

    Otherwise I may have to try Joe's, temporary detachment/attachment strategy.

    Dave


    David Webber
    Mozart Music Software
    http://www.mozart.co.uk
    For discussion and support see
    http://www.mozart.co.uk/mozartists/mailinglist.htm


    David Webber Author of Mozart music notation software http://www.mozart.co.uk
    Saturday, July 10, 2010 10:10 PM

All replies

  • First, when you handle a WM_PAINT, you need to call BeginPaint()/EndPaint() which happens automatically if you use CPaintDC, but you're not using that.  So call BeginPaint/EndPaint() instead of GetDC()/ReleaseDC().
     
    The background is first painted with the default brush (set as part of the WNDCLASS when the window is created) in response to WM_ERASEBKGND.  Then WM_PAINT is issued.  If there is a delay between WM_ERASEBKGND and WM_PAINT (as WM_PAINT is a low priority message), the default brush will be visible for awhile.  I would also intercept WM_ERASEBKGND and return TRUE so that no painting with the default brush is ever executed.
     
    -- David
     

    Efficiently access this forum with newsreaders like WLM, Thunderbird, and Forte Agent: http://communitybridge.codeplex.com
    Sunday, July 11, 2010 2:50 AM
  • "David Ching [MVP]" wrote in message news:17b38dd3-9aaf-4972-983f-dfced7341415@communitybridge.codeplex.com...

    First, when you handle a WM_PAINT, you need to call BeginPaint()/EndPaint() which happens automatically if you use CPaintDC, but you're not using that.  So call BeginPaint/EndPaint() instead of GetDC()/ReleaseDC().

    Ok - worth a try.  Results below.

    The background is first painted with the default brush (set as part of the WNDCLASS when the window is created) in response to WM_ERASEBKGND.  Then WM_PAINT is issued.  If there is a delay between WM_ERASEBKGND and WM_PAINT (as WM_PAINT is a low priority message), the default brush will be visible for awhile.  I would also intercept WM_ERASEBKGND and return TRUE so that no painting with the default brush is ever executed.

    I was in fact returning TRUE from WM_ERASEBKGND - at least part of the time to see if it made any difference.   It didn't.

    So now I have in my frame's PreTranslateMesage()

    ---------------------------------
       ...
     if( pMsg->hwnd &&  (pMsg->hwnd == m_wndClientArea.m_hWnd) )
     {
       if( pMsg->message==WM_ERASEBKGND )
       {
         bResult = TRUE;
       }
      else if( pMsg->message==WM_PAINT )
      {
        PAINTSTRUCT ps;
        m_wndClientArea.BeginPaint( &ps );
        HBRUSH hBrush = (HBRUSH)::GetStockObject( BLACK_BRUSH );
        ::FillRect( ps.hdc, &ps.rcPaint, hBrush );
        m_wndClientArea.EndPaint( &ps );
        bResult = TRUE;
       }
     }
      if( !bResult )
     {
       bResult = CMDIFrameWndEx::PreTranslateMessage(pMsg);
     }
      return bResult;
    ---------------------------------

    It looks a bit more MFC-ish and less Win32API-ish  but the result is the same:  FileNew flashes up the old grey background colour for a moment before the document appears (and exiting with a document showing shows the grey background for a moment after the document goes but before the frame window goes).

    It looks like the m_wndClientArea window, owned by the CMDIFrameWndEx is somehow getting WM_PAINT messages which don't go through the PreTranslateMessage() member function of the main frame window derived from CMDIFrameWndEx  - or that it is painting itself without getting a WM_PAINT. This feels very dodgy to me :-(

    But I feel I'm missing something simple somewhere.   I mean MS wouldn't put out a system where you couldn't draw reliably on your frame window's client area - would they?????

    Dave


    David Webber
    Mozart Music Software
    http://www.mozart.co.uk
    For discussion and support see
    http://www.mozart.co.uk/mozartists/mailinglist.htm


    David Webber Author of Mozart music notation software http://www.mozart.co.uk
    Sunday, July 11, 2010 10:01 AM

  • "David Webber" <dave@musical.demon.co.uk> wrote in message news:4656fbd8-7d13-43f4-b0c5-1c511be85e58@communitybridge.codeplex.com...

    .....
    But I feel I'm missing something simple somewhere.   I mean MS wouldn't put out a system where you couldn't draw reliably on your frame window's client area - would they?????

    Problem solved!

    It seems the CMDIFrameWndEx has a natty little virtual member which I found tucked away in the source code:

    CMDIFrameWndEx::OnEraseMDIClientBackground( CDC *pDC )

    This is a secret member because it is not listed in the virtual functions list in the class wizard (which until now I was happy to get back in VS 2010).

    But the name made it tempting enough to add manually:

    BOOL CMainFrame::OnEraseMDIClientBackground( CDC *pDC )
    {
       RECT rect;
       GetClientRect( &rect );
       CBrush Brush( RGB(0,127,0) );
       pDC->FillRect( &rect, &Brush );
       return TRUE;
    }

    and Bob is once again my uncle.

    Dave


    David Webber
    Mozart Music Software
    http://www.mozart.co.uk
    For discussion and support see
    http://www.mozart.co.uk/mozartists/mailinglist.htm


    David Webber Author of Mozart music notation software http://www.mozart.co.uk
    Sunday, July 11, 2010 10:37 AM
  • Great sleuthing, but that would make me lose my breakfast, had I been unfortunate enough to have eaten it  already!
     
    -- David


    BOOL CMainFrame::OnEraseMDIClientBackground( CDC *pDC )
    {
       RECT rect;
       GetClientRect( &rect );
       CBrush Brush( RGB(0,127,0) );
       pDC->FillRect( &rect, &Brush );
       return TRUE;
    }

    and Bob is once again my uncle.

    Dave


    Efficiently access this forum with newsreaders like WLM, Thunderbird, and Forte Agent: http://communitybridge.codeplex.com
    Sunday, July 11, 2010 1:16 PM

  • "David Ching [MVP]" wrote in message news:9c297ab0-feae-4181-acb1-7e6068a230c0@communitybridge.codeplex.com...

    Great sleuthing, but that would make me lose my breakfast, had I been unfortunate enough to have eaten it  already!

    Yes, it feels like sleuthing.   As OnEraseBkgnd() didn't seem to do anything, I was going to put a break point in the OnPaint() member of the CMDIClientAreaWnd which sits on top of the client area of the CMDIFrameWndEx., Then I found it didn't have one.    "Funny", I thought, "if it's not painting itself, something else must be painting it."    So I started scrolling through the source code of CMDIFrameWndEx, and voila! When you've ruled out everything which is impossible, what is left must be the truth, as my old mentor Sherlock used to say!

    Dave


    David Webber
    Mozart Music Software
    http://www.mozart.co.uk
    For discussion and support see
    http://www.mozart.co.uk/mozartists/mailinglist.htm


    David Webber Author of Mozart music notation software http://www.mozart.co.uk
    Sunday, July 11, 2010 5:16 PM