2
votes

I'm learning MFC and I'm trying to draw some lines on a MFC Dialog-based application main window, it shall be a rather simple task but while running I see no lines drawing on the dialog.

Following is the method I wrote:

// draw corner of a rectangle on specified device context
void CTestDrawCornerDlg::DrawCorner(
    CDC* pDC,
    const CornerType& type,
    const CPoint& position,
    const unsigned int& size
    )
{
    CPen pen(PS_SOLID, 5, RGB(0, 0, 0));
    CPen* pOldPen = pDC->SelectObject(&pen);

    CPoint pH, pV;
    // I could make following lines simply with a 2-lines block,
    //  but I'd leave it as it was to make it easier to understand.
    switch (type)
    {
    case LEFT_TOP:
        pH.x = position.x + size;
        pH.y = position.y;
        pV.x = position.x;
        pV.y = position.y + size;
        break;
    case LEFT_BOTTOM:
        pH.x = position.x - size;
        pH.y = position.y;
        pV.x = position.x;
        pV.y = position.y + size;
        break;
    case RIGHT_TOP:
        pH.x = position.x + size;
        pH.y = position.y;
        pV.x = position.x;
        pV.y = position.y - size;
        break;
    case RIGHT_BOTTOM:
        pH.x = position.x - size;
        pH.y = position.y;
        pV.x = position.x;
        pV.y = position.y - size;
        break;
    default: break;
    }
    pDC->MoveTo(position);
    pDC->LineTo(pH);
    pDC->MoveTo(position);
    pDC->LineTo(pV);

    pDC->SelectObject(pOldPen);
}

And I called this method in OnPaint method of Dialog class:

void CTestDrawCornerDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting
        // lines generated automatically when creating
        // MFC project are truncated for brevity
    }
    else
    {
        CDialogEx::OnPaint();
    }

    CPaintDC pDC(this);
    DrawCorner(&pDC, LEFT_TOP, CPoint(50, 50), 50);
}

I guess it's a newbie mistake but I just don't know what the mistake is. Thanks for help!

P.S. please download from following link the MFC project to re-create this problem: https://www.dropbox.com/s/exeehci9kopvgsn/TestDrawCorner.zip?dl=0

1
Your code is fine. Maybe you don't have ON_WM_PAINTBarmak Shemirani
ON_WM_PAINT was declared by default when creating the dialog project. I was trying to upload a small demo project to this post., but hasn't figured out how to do that right now ...Edward Zhang
I've made it work by moving the DrawCorner call to the very beginning of the OnPaint() method, i.e. before invocation of CDialogEx::OnPaint(). And then I can get the lines expected on dialog. Still open for who can answer why ...Edward Zhang
Your comments don't match your question. Don't use both CDialogEx::OnPaint() + CPaintDC. By the way, avoid uploading your project and adding external links. Show Minimal, Complete, and Verifiable example instead.Barmak Shemirani
Thanks Michael for editing my post to make the question clear. Hi Barmak, The project I uploaded is actually a minimal project which contains no more than default generated MFC codes and my code pasted in this post, which can be run to verify this problem. Thanks for sharing the link, very helpful.Edward Zhang

1 Answers

3
votes

You can change your code to use CDialogEx::OnPaint() + CClientDC as follows:

void CTestDrawCornerDlg::OnPaint()
{
    CDialogEx::OnPaint();
    CClientDC pDC(this);
    DrawCorner(&pDC, LEFT_TOP, CPoint(50, 50), 50);
}

or just use CPaintDC:

void CTestDrawCornerDlg::OnPaint()
{
    CPaintDC pDC(this);
    DrawCorner(&pDC, LEFT_TOP, CPoint(50, 50), 50);
}

But don't use OnPaint + CPaintDC

To see the problem, note how OnPaint and CPaintDC are defined in MFC:

void CDialog::OnPaint()
{
    CPaintDC dc(this);
    if (PaintWindowlessControls(&dc))
       return;
    Default();
}

CPaintDC::CPaintDC(CWnd* pWnd)
{
    if (!Attach(::BeginPaint(m_hWnd = pWnd->m_hWnd, &m_ps)))
        AfxThrowResourceException();
}

::BeginPaint is a core WinAPI function. It should only be called once in response to WM_PAINT, and it can't be used anywhere else.

CClientDC on the other hand uses ::GetDC which can be used pretty much anywhere, as long as window handle is available.