【发布时间】:2021-07-07 07:25:52
【问题描述】:
我在工具栏中有一个自定义滑块。为了在工具栏中显示滑块,它被包裹在一个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;
}
}
(对自定义滑块感兴趣的朋友,我关注了this tutorial)。
在我的应用程序的某个时刻,我不得不强制重绘滑块,因为用户改变了它的视觉风格。
我尝试了以下(包括组合)但没有成功:
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,所以看来我只是在呼吁一个将军更新不指明具体项目,但不知道怎么做。
总体问题是:如何强制重绘此控件?
【问题讨论】:
-
您是否尝试过使用
InvalidateRect使包含滑块的窗口区域 无效?或者尝试使窗口的整个客户区无效,看看它是否解决了问题。很久没写 MFC 代码了,但是我感觉你需要使窗口无效,而不是控件,在你的情况下。 -
@Afshin 是的,我尝试使用
slider.GetWindowRect()使其无效,然后在主应用程序窗口中调用InvalidateRect(),同时使用屏幕和客户端坐标,但什么也没有。 -
您是否在 CView 派生类中执行此操作?最好是销毁视图(不销毁附加文档,然后重新创建视图。
-
不完全是,我忘了提到我将滑块包装成
CMFCToolBarButton,以便在工具栏中显示它。我已更新问题以反映这一点。 -
不确定,但您可以尝试将
RDW_FRAME标志添加到RedrawWindow调用是否会改变任何内容?如果这不起作用,那么使用RDW_FRAMECHANGED标志调用SetWindowPos怎么样?我似乎记得任何一个都应用了更改主题时所需的某种修复,尽管我可能记错了。