Win32 MFC OnPaint 调整大小和重绘处理

Win32 MFC OnPaint Resizing and Redrawing handling

每当我调整我的绘图大小时,如何处理这个问题,我的绘图似乎不正确。 我想我每次调整 window 大小时都需要调用 Invalidate() 但不是每次移动或调整 window 大小时自动调用 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();
}

调整大小前:

调整大小后:

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

会发生什么。

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

如果您开始使用 CPaintDC/BeginPaint,请不要调用 OnPaint baseclass 函数!

不知道这个是不是最优解

  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(未记录)。

这解决了我的问题

第 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 步:结束绘制()