【问题标题】:Win32 MFC OnPaint Resizing and Redrawing handlingWin32 MFC OnPaint 调整大小和重绘处理
【发布时间】:2019-01-13 01:00:06
【问题描述】:

每次我调整我的绘图大小时如何处理这个问题似乎没有正确绘制。 我想我每次调整窗口大小时都需要调用 Invalidate() 但每次移动或调整窗口大小时不会自动调用 WM_PAINT 吗?

CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(rect);
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
{

    for(int ndx(0); ndx < rect.Width() - 150; ndx += 10)
    {
        dc.MoveTo( rect.left + 50, rect.bottom / 2 );

        dc.LineTo( rect.left + 50 + ndx, rect.bottom / 2 );

    }
    CBrush mybrush(RGB(30,30,30));
    dc.FillRect( CRect(rect.left + 10, rect.top + 10, rect.Width() / 4, rect.Height() / 4),&mybrush );
    CDialogEx::OnPaint();
}

调整大小之前:

调整大小后:

【问题讨论】:

  • WM_PAINT 消息在调整大小时生成,只要窗口类注册为CS_HREDRAW 和/或CS_VREDRAW 类样式。系统使用窗口类中指定的画笔自动擦除背景。这里的窗口类是指WNDCLASS,而不是CWnd。使用 Spy++ 检查窗口上的窗口类样式。

标签: c++ windows winapi mfc win32gui


【解决方案1】:

当您开始绘画并使用CPaintDC 时,调用再次尝试此操作并可能再次擦除背景的基类是没有意义的...

会发生什么。

  1. 您的CPaintDC 已创建
  2. BeginPaint 被调用,WM_ERASEBKGND 被发送。
  3. 你画你的东西。
  4. 您调用基类并使用新的CPaintDC 调用BeginPaint
  5. 因为EndPaint 未被调用,所以绘制区域未被验证。所以BeginPaint 被执行,WM_ERASEBKGND 被再次调用。
  6. 最后调用CPaintDC 的析构函数并验证客户区。

如果您开始使用CPaintDC/BeginPaint,切勿调用 OnPaint 基类函数!

【讨论】:

  • 你的意思是这个 CDialogEx::OnPaint();正确的?我尝试将其删除但仍然有相同的结果。
  • 虽然EndPaint要清除脏区似乎更合理,但确实是BeginPaint验证了无效区域。
【解决方案2】:

我不知道这是否是最优解。

  1. 在您的绘制代码中,在绘制之前,用背景色填充整个客户区:

      dc.FillSolidRect(&rect, ...);
    

    删除CDialogEx::OnPaint()

  2. 添加一个OnEraseBkgnd 处理程序:

      BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
        //...
        ON_WM_ERASEBKGND()
      END_MESSAGE_MAP()
    
      //...
    
      BOOL OnEraseBkgnd(CDC * pDC)
      {
        RedrawWindow();
        return TRUE;
      }
    
  3. 如果对话框闪烁,请使用 MFC 的 CMemDC(未记录)。

【讨论】:

  • 是的,是的。这解决了它。这需要处理 WM_ERASEBKGND。非常感谢先生。
【解决方案3】:

这解决了我的问题

第 1 步:BeginPaint()

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTestDrawDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(rect);

// draw background manually
EraseBkgnd(&dc);

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
{

    for(int ndx(0); ndx < rect.Width() - 150; ndx += 10)
    {
        dc.MoveTo( rect.left + 50, rect.bottom / 2 );

        dc.LineTo( rect.left + 50 + ndx, rect.bottom / 2 );

    }
    CBrush mybrush(RGB(30,30,30));
    dc.FillRect( CRect(rect.left + 10, rect.top + 10, rect.Width() / 4, rect.Height() / 4),&mybrush );
}
}

步骤:WM_ERASEBACKGND 上的 2 个 RedrawWindow()

BOOL CTestDrawDlg::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default

RedrawWindow();
return TRUE;
}

并手动绘制背景

void CTestDrawDlg::EraseBkgnd( CDC * pDC )
{
CRect rect;
GetClientRect(rect);
pDC->FillSolidRect(rect, RGB(255,255,255));

// paint whatever you want in the background

}

第 3 步:EndPaint()

【讨论】:

  • 在 OnEraseBkGnd 中调用重绘窗口绝对是错误的!
  • 是的,它的内存非常大。你能提供更好的方法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 2010-09-15
  • 1970-01-01
相关资源
最近更新 更多