如何在CView中添加可显示于控件上方的Checkbox
解决CView派生类中Checkbox被图表控件遮挡的问题
问题分析
在CView派生类中添加的Checkbox始终被图表控件遮挡,尝试设置WS_EX_TOPMOST无效;将Checkbox父窗口设为图表控件虽能显示,但消息无法路由到CView。此外,图表控件调用Invalidate()时,Checkbox会再次被遮挡,仅用MoveWindow()模拟的“伪Invalidate”能临时解决。
原因说明
WS_EX_TOPMOST不适用于子窗口:SetWindowPos(&CWnd::wndTopMost)仅对顶级窗口生效,同级子窗口的层级由Z-order决定,该参数无法让Checkbox显示在其他子控件之上。- 缺少
WS_CLIPSIBLINGS风格:图表控件未设置WS_CLIPSIBLINGS时,重绘会覆盖兄弟控件的区域,导致Checkbox被遮挡。 - 父窗口变更导致消息路由中断:将Checkbox父窗口设为图表控件后,消息会先发送给图表控件而非CView,除非手动转发消息,否则CView无法接收Checkbox的消息。
解决方案
方案1:调整控件Z顺序+添加WS_CLIPSIBLINGS风格
保持Checkbox父窗口为CView,同时修改图表控件的创建参数和Checkbox的Z顺序:
void CMyView::OnInitialUpdate() { // ... // 给图表控件添加WS_CLIPSIBLINGS风格,防止重绘覆盖兄弟控件 m_wndCurveCtrl.Create(rcTemp, this, 123, WS_CHILD | WS_BORDER | WS_TABSTOP | WS_VISIBLE | WS_CLIPSIBLINGS); myButton.Create(_T("MyChxBox"), WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, CRect(100, 5, 200, 25), this, ID_BTN1); // 使用&CWnd::wndTop将Checkbox置于所有同级子控件顶层 myButton.SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW); }
方案2:修复重绘遮挡问题
针对图表控件调用Invalidate()导致的遮挡,确保图表控件重绘时仅绘制自身区域:
- 确保图表控件创建时包含
WS_CLIPSIBLINGS风格(同方案1)。 - 若无法修改图表控件的创建参数,可在CView的
OnPaint中或图表控件重绘完成后,重新将Checkbox置顶:
// 在CView的OnPaint或图表控件重绘完成后调用 myButton.SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
方案3:消息转发(若必须将Checkbox父窗口设为图表控件)
如果因布局需求必须将Checkbox父窗口设为图表控件,可通过消息转发让CView接收Checkbox的消息:
在图表控件类中添加消息映射,将Checkbox的消息转发给父窗口(CView):
BEGIN_MESSAGE_MAP(CMyCurveControl, CWnd) // ... 原有消息映射 ON_COMMAND(ID_BTN1, OnForwardButtonMsg) END_MESSAGE_MAP() void CMyCurveControl::OnForwardButtonMsg() { // 将消息转发给父窗口(CView) GetParent()->SendMessage(WM_COMMAND, MAKEWPARAM(ID_BTN1, BN_CLICKED), (LPARAM)myButton.GetSafeHwnd()); }
为什么“伪Invalidate”(MoveWindow())有效?
调用MoveWindow()时,窗口会触发重绘,同时Windows默认会将该窗口置于同级子控件的顶层,因此临时解决了遮挡问题。但这并非正规解决方案,添加WS_CLIPSIBLINGS并调整Z顺序才是根本解决方法。
内容的提问来源于stack exchange,提问作者Tom Tom
相关产品推荐
相关产品推荐

