如何在程序启动时绘制CDockablePane的背景
问题:CDockablePane停靠窗格背景透明异常
我有一个继承自CDockablePane的停靠窗格(附加到带视图的框架),内部包含两个间隔排列的编辑控件。预期控件之间的空白区域显示窗格默认背景色,但程序启动时背景呈透明状态,自动隐藏/显示窗格后问题依旧,会透出后方视图的内容。
已尝试的无效方案
- 重写
OnSize()并调用DoPaint():仅在调整窗格大小或停靠时能正常重绘背景,但启动时OnSize()在窗格和视图显示前被调用6次,无法解决初始透明问题。 - 添加
OnEraseBkgnd()并调用DoPaint():启动时该函数完全未被触发,方案来自旧版CodeGuru帖子。 - 重写
OnShowWindow()并调用DoPaint():启动时OnShowWindow()在窗格显示前被调用5次,同样无效。
请问还应在何处调用DoPaint()?另外,我对程序启动阶段的方法调用流程了解不多,有没有可学习的资源或书籍?
可行解决思路
1. 重写OnPaint()方法
在COutputWnd中添加OnPaint()消息处理,直接在其中调用DoPaint(),确保窗格显示时强制渲染背景:
// 在类声明中添加 afx_msg void OnPaint(); // 消息映射中添加 ON_WM_PAINT() // 实现代码 void COutputWnd::OnPaint() { CPaintDC dc(this); DoPaint(&dc); // 确保子控件正常绘制 CDockablePane::OnPaint(); }
2. 修正OnEraseBkgnd()实现
原代码中额外获取DC的写法错误,应直接使用传入的pDC,并返回TRUE跳过系统默认擦除逻辑:
BOOL COutputWnd::OnEraseBkgnd(CDC* pDC) { DoPaint(pDC); return TRUE; // 告知系统已自行处理背景擦除 }
3. 初始化完成后强制重绘
在主框架初始化完成后,主动触发窗格的重绘操作:
// 例如在主框架的OnCreate末尾或InitInstance中 m_wndOutputPane.Invalidate(); m_wndOutputPane.UpdateWindow();
4. 检查窗格样式
确认停靠窗格未设置WS_EX_TRANSPARENT扩展样式,同时确保子控件的布局没有覆盖整个窗格客户区,留出的间隔区域确实属于窗格自身。
程序启动流程学习资源
- 《MFC Windows程序设计》(Jeff Prosise著):MFC开发经典书籍,详细讲解程序初始化流程、消息机制及控件生命周期。
- MFC官方文档:重点关注
CWinApp::InitInstance()、主框架创建流程、CDockablePane的初始化逻辑部分。 - 调试跟踪:通过Visual Studio断点跟踪程序启动时
CDockablePane的构造、创建、显示相关函数,直观梳理调用顺序。
附原代码
class CSerialPortEdit : public CRichEditCtrl { .... }; class COutputWnd : public CDockablePane { public: COutputWnd() { }; public: CSerialPortEdit m_wndPortEdit; CMFCEditBrowseCtrl m_cmdLine; CFont m_cmdFont; public: virtual ~COutputWnd(); void UpdateFonts(); protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnSetFocus(CWnd* pOldWnd); afx_msg BOOL OnEraseBkgnd(CDC* pDC); DECLARE_MESSAGE_MAP() }; int COutputWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; // Create port edit: const DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN; if (!m_wndPortEdit.Create(dwStyle, CRect(0,0,0,0), this, IDC_SERIAL_EDIT)) { TRACE0("Failed to create port window\n"); return -1; // fail to create } // Create command line: const DWORD edStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | WS_TABSTOP | ES_AUTOHSCROLL | ES_MULTILINE | ES_WANTRETURN; if (!m_cmdLine.CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), NULL, edStyle, CRect(0,0,0,0), this, IDC_COMMAND_EDIT)) { TRACE0("Failed to create command line\n"); return -1; // fail to create } m_cmdLine.SetMargins(4, 4); m_cmdLine.EnableFileBrowseButton(); UpdateFonts(); return 0; } void COutputWnd::OnSize(UINT nType, int cx, int cy) { CDockablePane::OnSize(nType, cx, cy); CDC* pdc = GetDC(); DoPaint(pdc); // redraw background ReleaseDC(pdc); m_wndPortEdit.SetWindowPos (NULL, 0, 0, cx, cy-cmdSize.y-cmdDelta.y-2, SWP_NOACTIVATE | SWP_NOZORDER); m_cmdLine.SetWindowPos (NULL, 0, cy-cmdSize.y-2, cx, cmdSize.y, SWP_NOACTIVATE | SWP_NOZORDER); } void COutputWnd::OnSetFocus(CWnd* pOldWnd) { CDockablePane::OnSetFocus(pOldWnd); m_wndPortEdit.SetFocus(); } BOOL COutputWnd::OnEraseBkgnd(CDC* pDC) { CDC* pdc = GetDC(); DoPaint(pdc); // redraw background ReleaseDC(pdc); return CWnd::OnEraseBkgnd(pDC); }
内容的提问来源于stack exchange,提问作者Manuela Arcuri
相关产品推荐
相关产品推荐

