【问题标题】:MFC Redraw window in paint application problemMFC重绘窗口在油漆应用问题
【发布时间】:2020-01-16 05:35:36
【问题描述】:

我正在尝试在 MFC 上编写 Paint,但在绘制新图形、移动或调整现有图形时重绘窗口出现问题。当我在每次鼠标移动后使用Invalidate()InvalidateRect(NULL) 时效果很好,但是在添加 3-4 个数字后应用程序崩溃,因为它无法及时重绘所有窗口。我试过InvalidateRect(FigureRect)RedrawWindow(FigureRect) 但它不能正常工作(出现污点)。

效果很好,但应用程序崩溃:

void CGraphicsEditorView::OnMouseMove(UINT nFlags, CPoint point)
{
    ...
    if (m_mouseDrugging && m_cursorInside)
    {
        m_figureSelected->Move(point);
        Invalidate();
    }
    ...
    CView::OnMouseMove(nFlags, point);
}

这是我的OnDraw 函数:

void CGraphicsEditorView::OnDraw(CDC* pDC)
{
    for (Figure* figure : figures)
        figure->Draw(pDC);
}

Figure 是一个抽象类,继承了 Rectangle、Ellipse 和 Triangle 类。

例如,矩形的Draw 函数:

void CRectangle::Draw(CDC* pDC) {
    pDC->SelectStockObject(NULL_BRUSH);

    CPen penBorder(penType, penWidth, borderColor);
    CBrush* br = (brushType == HS_TRANSPARENT) ? nullptr : new CBrush(brushType, fillColor);
    pDC->SelectObject(&penBorder);
    pDC->SelectObject(br);

    pDC->Rectangle(bound);
}

我是否正确地重绘了窗口? 提前感谢您的帮助。

【问题讨论】:

  • 只要“数字”的所有元素都是有效的,我不会立即看到会导致崩溃的东西,但是您显示的内容不足以完全确定这一点。例如,在调试器中运行它并查看崩溃实际发生的位置(您可能需要向上堆栈以找到调用库的代码部分,但这几乎可以肯定是您的代码而不是库的问题有问题)。
  • 感谢您的回答。图形只是矩形、椭圆和三角形。我向您展示了几乎所有的代码,除了 move 和 draw 函数。图形由表示为矩形的边界框的坐标绘制。移动是图形边界框坐标的简单更改。
  • 如上所说:在调试器中运行,看看究竟发生崩溃的地方。从您的代码来看,这绝对不是很明显。或者,至少,在这里发布完整的figure->Draw(pDC); 方法。
  • 我展示了矩形的完整绘图功能。对于其他图形,仅在椭圆中是相同的,调用椭圆函数,在三角形中调用多边形函数。
  • new CBrush 既是内存泄漏又是资源泄漏。当您遇到 10,000 个 GDI 资源泄漏时,您的程序将崩溃。

标签: c++ mfc paint invalidation redraw


【解决方案1】:

无效会导致WM_PAINT 被发送,并且它们以某种方式“异步”处理,因为WM_PAINT (OnDraw()) 是一个低优先级消息(在消息队列被清空之前处理)。这也可能导致“闪烁”。由于鼠标移动是在您移动鼠标时多次发送的消息,因此您不应该使窗口无效,最好不要在其中执行冗长/耗费 CPU 的操作。相反,我会考虑绘画和绘画的结合。以下链接中的详细信息(我过去回答过的相关问题):

Some controls are not drawing, seemingly at random

MFC window graphic is gone after minimizing/maximizing

Paint invalid areas of a window using Win32 API and GDI

Win32API) Why should I GetDC and ReleaseDC again and again?

至于崩溃,毫无疑问它们是实现错误的结果——WM_PAINT 消息处理的“异步”性质可能需要在这里做某事,例如某些变量可能已更改(在OnMouseMove() ),最后在OnDraw()访问时,可能会出现一些数据不一致的情况。

【讨论】:

  • 我将OnPaint() 函数添加到响应ON_WM_PAINT() 并从中调用OnDraw(CDC*) 函数。但是如果我删除所有Invalidate() 调用,我不明白如何调用窗口重绘。
  • 您可以在应用程序中的任何时候使用GetDC()/ReleaseDC() 函数而不是BeginPaint()/EndPaint() 函数执行自定义“绘图”(而不是通过Invalidate()/OnDraw()),这称为“绘画”和是OnDraw() 所做的。绘图直接执行。检查我的帖子,它描述得更详细。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-27
  • 1970-01-01
  • 2014-06-04
  • 1970-01-01
相关资源
最近更新 更多