C ++ MFC重写OnPaint()不在另一台计算机上绘画

时间:2018-08-23 10:57:12

标签: c++ mfc

我向OnPaint()添加了代码,它在Windows 10笔记本电脑上可以正确绘制,但是该绘制未在另一台计算机上显示(Windows 8)。我是绘画的新手,我可能做错了什么-也许使用了invalidate和updatewindow。无论如何,这是我的代码:

我在对话窗口上绘画; OnPaint()的代码主要由Visual Studio创建-我只是在末尾添加了DrawValveImage()。另外,here是显示DrawValveImage()绘制的图片。我认为您无需查看DrawValveImage()的所有代码即可解决该问题;我认为我的错误是我对DrawValveImage()的调用的放置。也许OnPaint()不是自定义绘画的正确选择。

void CCleaningAndScreeningDlg::OnPaint()

{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);


    }
    else
    {
        CDialogEx::OnPaint();
    }

    DrawValveImage();

}

void CCleaningAndScreeningDlg::DrawValveImage()
{
    //my own drawing
    CClientDC* pDC = new CClientDC(this);
    pDC->SelectStockObject(NULL_BRUSH);
    COLORREF blueBorder = RGB(67, 99, 155);
    COLORREF blueFill = RGB(218, 227, 243);

    int x1 = 1050;
    int y1 = 50;
    int width = 300;
    int x2 = x1 + width;
    int y2 = y1 + width;


    CPen pen;
    CBrush brush;
    pen.CreatePen(PS_SOLID, 5, blueBorder);
    brush.CreateSolidBrush(blueFill);

    // select brush and pen
    pDC->SelectObject(&pen);
    pDC->SelectObject(&brush);

    if (valveImageDrawn == FALSE)
        pDC->Ellipse(x1, y1, x2, y2);

    DeleteObject(brush);
    DeleteObject(pen);
    DeleteObject(&brush);
    DeleteObject(&pen);


    int heightWidth = width;
    int smallHeightWidth = heightWidth / 7;
    int radiusFromOriginSmallCircle = heightWidth / 2.75;

    for (int circleIndex = 0; circleIndex < 10; circleIndex++) {
        POINT centerSmallCircle = FindPointOnCircle(POINT{ heightWidth / 2, heightWidth / 2 }, radiusFromOriginSmallCircle, (circleIndex * 360 / 10) - 90);
        int smallCircleX = centerSmallCircle.x - smallHeightWidth / 2 + x1;
        int smallCircleY = centerSmallCircle.y - smallHeightWidth / 2 + y1;
        rectangle smallCircleRect = { smallCircleX, smallCircleY, smallCircleX + smallHeightWidth, smallCircleY + smallHeightWidth };
        rectsSmallCircles[circleIndex] = smallCircleRect;

        bool greenFilled = false;
        if (valvePosition - 1 == circleIndex) {
            CPen pen;
            CBrush brush;
            COLORREF greenFill = RGB(181, 230, 29);
            pen.CreatePen(PS_SOLID, 5, blueBorder);
            brush.CreateSolidBrush(greenFill);
            pDC->SelectObject(&pen);
            pDC->SelectObject(&brush);
            pDC->Ellipse(smallCircleRect.x1, smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2);

            DeleteObject(brush);
            DeleteObject(pen);
            DeleteObject(&brush);
            DeleteObject(&pen);

            greenFilled = true; //if mouse clicked and green color is painted on the valve image
        }
        else {
            CPen pen;
            CBrush brush;
            pen.CreatePen(PS_SOLID, 5, blueBorder);
            brush.CreateSolidBrush(blueFill);
            pDC->SelectObject(&pen);
            pDC->SelectObject(&brush);
            pDC->Ellipse(smallCircleRect.x1, smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2);

            DeleteObject(brush);
            DeleteObject(pen);
            DeleteObject(&brush);
            DeleteObject(&pen);     
        }

        CString circleText;
        int CircleNumber = circleIndex + 1;
        circleText.Format(_T("%d"), CircleNumber);


        CRect testRect = { smallCircleRect.x1,
            smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2 };
        pDC->SetBkMode(TRANSPARENT);

        CClientDC dc(this);
        CFont font;
        VERIFY(font.CreateFont(
            30,                        // nHeight
            0,                         // nWidth
            0,                         // nEscapement
            0,                         // nOrientation
            FW_BOLD,                 // nWeight
            FALSE,                     // bItalic
            FALSE,                     // bUnderline
            0,                         // cStrikeOut
            ANSI_CHARSET,              // nCharSet
            OUT_DEFAULT_PRECIS,        // nOutPrecision
            CLIP_DEFAULT_PRECIS,       // nClipPrecision
            DEFAULT_QUALITY,           // nQuality
            DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
            _T("Arial")));                 // lpszFacename
        CFont* def_font = pDC->SelectObject(&font);
        pDC->DrawText(circleText, testRect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
        pDC->SelectObject(def_font);
        font.DeleteObject();



    }

    //redraw the combobox infront of the valve-image
    UpdateData(TRUE);
    comboPorts.Invalidate();
    comboPorts.UpdateWindow();

    valveImageDrawn = true;
}

1 个答案:

答案 0 :(得分:3)

OnPaint()是进行自定义绘画的正确方法。覆盖OnPaint()时,您应该调用基类的OnPaint()方法。您有责任自己绘制窗口的全部内容(子窗口除外)。

您只需要此代码:

void CCleaningAndScreeningDlg::OnPaint()
{
    CPaintDC dc(this); // constructor of CPaintDC calls ::BeginPaint()

    DrawValveImage( dc );  // pass device context to the drawing function

    // Destructor of CPaintDC automatically calls ::EndPaint()!
}

您可以看到我已经向DrawValveImage添加了一个参数。声明看起来像这样:

void DrawValveImage( CDC& dc );

确保在绘图功能中仅使用dc参数进行绘图。

这是错误

CClientDC* pDC = new CClientDC(this);

您不应创建任何其他设备上下文。

另一个错误的示例:

pDC->SelectObject(&pen);
pDC->SelectObject(&brush);

if (valveImageDrawn == FALSE)
    pDC->Ellipse(x1, y1, x2, y2);

DeleteObject(brush);
DeleteObject(pen);
DeleteObject(&brush);
DeleteObject(&pen);

首先,在删除所选对象之前,不要还原设备上下文的原始状态。当仍在设备上下文中选择对象时,无法正确删除该对象。要解决此问题,请存储返回值SelectObject()SelectStockObject(),这是指向设备上下文中先前选择的对象的指针(如果未选择,则有一个默认对象)。在删除对象之前,请调用SelectObject(),并传递存储的指针。

第二,为什么要删除两次对象?让对象在离开当前范围时自动销毁自身,或者调用DeleteObject() member 函数(非常需要)。

更正的代码:

auto pOldPen = dc.SelectObject(&pen);
auto pOldBrush = dc.SelectObject(&brush);

if (valveImageDrawn == FALSE)
    dc.Ellipse(x1, y1, x2, y2);

if(pOldPen) 
    dc.SelectObject(pOldPen);
if(pOldBrush) 
    dc.SelectObject(pOldBrush );

// No need for DeleteObject(), the destructor of each object will delete it at the
// end of the current scope (before the function returns). But if you actually need it
// (say you want to reuse the variable), it would look like this:
// pen.DeleteObject();
// brush.DeleteObject();

此代码是不必要的:

//redraw the combobox infront of the valve-image
UpdateData(TRUE);
comboPorts.Invalidate();
comboPorts.UpdateWindow();

只需设置对话框窗口的WS_CLIPCHILDREN样式(使用对话框编辑器)即可防止绘画代码在组合框上绘制。