c++winapiatlwtl

How can I draw something in my subclassed controls paint method on top of the default paint outcome?


I am currently trying to subclass a CRichEditCtrl in my application. This is the subclass class:

class FileEdit : public CWindowImpl<FileEdit, CRichEditCtrl>
{
    DECLARE_WND_CLASS(L"FileEdit");
public:
    BEGIN_MSG_MAP_EX(FileEdit)
        MSG_WM_PAINT(OnPaint)
        MSG_WM_LBUTTONUP(OnLButtonUp)
    END_MSG_MAP()

    bool Init();

private:
    void OnPaint(CDCHandle dc);
    void OnLButtonUp(UINT nFlags, CPoint point);
};

My paint method looks like this:

void FileEdit::OnPaint(CDCHandle dc)
{
    PAINTSTRUCT ps;
    if (!dc)
    {
        dc = BeginPaint(&ps);
    }
    POINT p[2];
    p[0].x = 1;
    p[0].y = 1;

    p[1].x = 5;
    p[1].y = 5;
    Polygon(dc, p, 2);

    EndPaint(&ps);
}

This does indeed draw the polygon I want, but that is the only thing it does paint, as well. I am pretty sure why this is happening. I am accepting the Paint message, I am handling it, and then it is done. I don't go through the default routine which would paint the background white for example.

However, I would actually like to have it like this:

  1. Go through the default paint routine, which would happen, if I don't specify a custom paint routine
  2. Paint the things I request in FileEdit::OnPaint-method.

I still want the usual paint routine, but I just want to add a few things "on top" afterwards.

Is there any way to accomplish this? Maybe I could pass the PAINTSTRUCT to a base method?

Thanks in advance


Solution

  • The cleanest way to customize WM_PAINT handler is to find a way to insert your code in the middle of BeginPaint and EndPaint pair. Standard control handler has its own calls so it would be the best to get called back between those, when such opportunity exists. For example, common controls such as listview and treeview do provide this opportunity by sending NM_CUSTOMDRAW notification, however edit control is not that flexible.

    The task is, of course, much easier if you handle the painting completely, in which case you just handle the message yourself without thinking too much about standard handler.

    An edit-specific solution which works well (meaning that it is compatible with standard control implementation, which is not necessarily true for other controls; it is also for simple edit control, not rich edit control) is to:

    1. Provide your own WM_PAINT handler
    2. Call DefWindowProc to let the control do standard painting with its own BeginPaint and EndPaint
    3. Then continue in your handler by getting HDC using GetDC and ReleaseDC (as opposed to BeginPaint and EndPaint) and updating the obtained DC with your customizations.

    A WTL handler of subclasses edit control might look like:

    LRESULT OnPaint(CDCHandle)
    {
        if(!(GetStyle() & ES_READONLY)) // Just an example how to make custom draw optional
        {
            DefWindowProc();
            CClientDC Dc(m_hWnd);
            // TODO: Paint using Dc
        } else
            SetMsgHandled(FALSE);
        return 0;
    }
    

    See also: