c++winapimfceditboxcommon-controls

Do I need to select HBRUSH when replacing background in the edit control?


My goal is to replace a background for the common-control's edit control. My current code does this:

HBITMAP hBmp = ::LoadBitmap(hInstance, MAKEINTRESOURCE(BKGND_ID));
HBRUSH hBkgndBrush = ::CreatePatternBrush(hBmp);
::DeleteObject(hBmp);


HBRUSH CDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

    // TODO:  Change any attributes of the DC here

    if(pWnd->GetDlgCtrlID() == MY_CTRL_ID && hBkgndBrush)
    {
        hbr = hBkgndBrush;

        //Do I need to select it?
        //pDC->SelectObject(hbr);   //This line?

        pDC->SetBkMode(TRANSPARENT);
    }

    // TODO:  Return a different brush if the default is not desired
    return hbr;
}

The question is, do I need to select hbr before returning it? (See commented out line above.) I seem to see it done both ways in different examples online.

EDIT: Also forgot to mention, I override WM_ERASEBKGND as such:

HDC hDc = ::GetDC(hWnd);
if(hDc)
{
    RECT rc = {0};
    ::GetClientRect(hWnd, &rc);

    ::FillRect(hDc, &rc, hBkgndBrush);

    ::ReleaseDC(hWnd, hDc);
}

EDIT2: I made a small sample MFC project to illustrate the issue. Basically, when I move the app quickly off the screen and then back, it creates this visual "glitch" but only if control doesn't have ES_MULTILINE style:

enter image description here


Solution

  • When background brush is created from bitmap using CreatePatternBrush, some "repeating artifacts" may occur during dialog resizing or moving.

    To remove these artifacts, force the child controls to repaint in response to ON_WM_WINDOWPOSCHANGED message:

    void CMyDialog::OnWindowPosChanged(WINDOWPOS *wndpos)
    {
        CDialog::OnWindowPosChanged(wndpos);
    
        CWnd *wnd = GetWindow(GW_CHILD);
        while (wnd)
        {
            wnd->Invalidate(TRUE);
            wnd = wnd->GetWindow(GW_HWNDNEXT);
        }
    }
    

    or

    void CMyDialog::OnWindowPosChanged(WINDOWPOS *wndpos)
    {
        CDialog::OnWindowPosChanged(wndpos);
        edit1.Invalidate(FALSE);
        edit2.Invalidate(FALSE);
        ...
    }
    

    OnCtlColor override will be as follows:

    HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* wnd, UINT nCtlColor)
    {
        if (nCtlColor == CTLCOLOR_DLG)
            return CDialogEx::OnCtlColor(pDC, wnd, nCtlColor); 
        pDC->SetBkMode(TRANSPARENT);
        return hBkgndBrush;
    }
    

    You can add other conditions based on wnd or nCtlColor to change the background of edit control only.