使用 CDDS_ITEMPREPAINT 强制调用 OnCustomDraw

问题描述 投票:0回答:2

我的工具栏中有一个自定义滑块。为了在工具栏中显示滑块,它被包装在

CMFCToolBarButton
派生类中。

滑块使用

OnCustomDraw
来执行渲染:

BEGIN_MESSAGE_MAP(CCustomSlider, CSliderCtrl)
  ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
END_MESSAGE_MAP()

void CCustomSlider::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
  const auto lpcd = (LPNMCUSTOMDRAW)pNMHDR;
  std::cout << "Draw stage: " << lpcd->dwDrawStage << '\n'; // for debugging purposes

  switch (lpcd->dwDrawStage) {
  case CDDS_PREPAINT:
    *pResult = CDRF_NOTIFYITEMDRAW;
    break;
  case CDDS_ITEMPREPAINT: // custom drawing done here
    switch (lpcd->dwItemSpec) {
      // ...
    }
    break;
  }
}

(对于那些对自定义滑块感兴趣的人,我遵循了本教程)。

在我的应用程序的某个时刻,我必须强制重绘滑块,因为用户更改了其视觉样式。

我尝试了以下方法(包括组合)但没有成功:

  • slider.Invalidate();
  • slider.GetOwner()->SendMessage(WM_COMMAND, m_nID);
    m_nID
    是滑块发送的命令ID)
  • slider.SendNotifyMessageA(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);

包装纸也一样。我还尝试过强制重新绘制工具栏:

toolbar.AdjustLayout();
toolbar.Invalidate();
toolbar.RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);

当视觉样式发生变化时,应用程序的其余部分(包括工具栏)会正确刷新,但滑块不会。

如果我调整窗口大小,滑块会正确更新。

据我所知,我似乎没有向

OnCustomDraw
发送正确的消息。当我自己重画时,它显示draw stage
CDDS_PREPAINT
,而在调整大小时它被调用了几次,其中一些包括
CDDS_ITEMPREPAINT
,所以看来我只是要求一般更新而没有指明具体内容项目,但我不知道该怎么做。

总体问题是:如何强制重绘此控件?

c++ windows mfc redraw
2个回答
1
投票

到目前为止,我发现强制重绘的唯一方法是使用

CSliderCtrl::SetRangeMin
CSliderCtrl::SetRangeMax
方法,它们接收可选参数
BOOL bRedraw
:

slider.SetRangeMin(slider.GetRangeMin(), TRUE);

这个 hack 足以解决我遇到的问题,但看起来有点肮脏和间接

摘自MFC的源代码:

_AFXCMN_INLINE void CSliderCtrl::SetRangeMin(_In_ int nMin, _In_ BOOL bRedraw)
{ ASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETRANGEMIN, bRedraw, nMin); }

我没能找到的是所谓的幕后,当

bRedraw = TRUE


0
投票

另一种对我们有用的方法是调用 PostMessage(WM_SYSCOLORCHANGE, 0, 0);

© www.soinside.com 2019 - 2024. All rights reserved.