如何在启动时绘制CDockablePane的背景

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

我有一个从 CDockablePane 派生的可停靠窗格(附加到带有视图的框架),其中包含两个间隔开的编辑控件。我希望这些控件之间的空间绘制在该窗格的默认背景颜色上。相反,当我的应用程序。启动背景是透明的。当我(自动)隐藏/显示窗格时,该背景是透明的 - 显示其后面视图中的任何内容。

我做了以下事情:

  1. 重写 OnSize() 并调用 DoPaint() (参见下面的代码)。 这样,当我调整窗格大小或停靠窗格时,背景就会重新绘制得很好。 启动时,在窗格和视图显示在屏幕上之前,OnSize() 会被调用六次,因此没有任何帮助。

  2. 添加了 OnEraseBkgnd() 并调用了 DoPaint()(见下文)。 看起来 OnEraseBkgnd() 在启动时根本没有被调用。 此修复是由旧的 codeguru 帖子建议的。
  3. 重写 OnShowWindow() 并调用 DoPaint()。 启动时,OnShowWindow() 在窗格显示之前被调用五次,但没有任何帮助。
  4. 我还应该在哪里调用 DoPaint() ? (我不太清楚启动时调用了哪些方法。是否有网络资源或书籍可以阅读有关该主题的内容?)

谢谢你。

编辑:

下面是代码的一部分 - 它创建了两个由 cmdDelta.y 间隔开的编辑控件。我此时不绘制或擦除任何内容,只需重新定位 OnSize() 中的控件即可。

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); }


visual-c++ mfc
1个回答
0
投票
COutputWnd

窗口。删除了列表窗口和选项卡控件。问题立即变得明显(无需添加两个控件),即它是透明的,不会擦除其背景。使用

SpyXX
实用程序检查窗口,发现其类的背景画笔设置为 COLOR_3DFACE(对话框背景的标准颜色)。
那么为什么它不起作用呢?检查了MFC头文件和源代码,找到了罪魁祸首:

COutputWnd

源自

CDockablePane
CPane
<-
CBasePane
。 <-
CBasePane
有一个
OnEraseBkgnd()
覆盖,您可以在文件
afxbasepane.cpp
: 中找到它 BOOL CBasePane::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; }

即不做任何事情,返回
TRUE

,表示不需要进一步擦除。这可能是因为所有这些“窗格”窗口都应该让其客户区域完全被另一个控件(选项卡、树视图等)覆盖,因此“不需要”擦除背景。但在这里您已经删除了原始的选项卡控件,并且(禁用的)背景被揭开。因此,有多种解决方案,所有解决方案都涉及覆盖

OnEraseBkgnd()
,您的选择取决于偏好:

A。使用 Visual Manager 背景颜色(首选)

BOOL COutputWnd::OnEraseBkgnd(CDC* pDC) { DoPaint(pDC); // Fill background with the standard theme color return TRUE; // No further erasing is required }

DoPaint()

CBasePane
的一个方法,它的实现也在afxbasepane.cpp中,就在
OnEraseBkgnd()
下面;致电
CMFCVisualManager::OnFillBarBackground()

B.使用默认(WNDCLASS)背景颜色

BOOL COutputWnd::OnEraseBkgnd(CDC* pDC) { return CWnd::OnEraseBkgnd(pDC); // Erase background using the class background brush. }

此实现“恢复”原始 
OnEraseBkgnd()

行为,以规避

CBasePane
中的覆盖。原始实现(在
CWnd
中)使用类背景画笔填充背景。它设置为
COLOR_3DFACE
,这是对话框背景的标准 Windows 颜色。

C.使用自定义背景颜色

HBRUSH hBrYellow = CreateSolidBrush(RGB(255, 255, 0)); // Yellow Brush BOOL COutputWnd::OnEraseBkgnd(CDC* pDC) { RECT rct; GetClientRect(&rct); FillRect(pDC->m_hDC, &rct, hBrYellow); // Fill the client area with the yellow brush return TRUE; // No further erasing is required }

您还应该删除所有其他 
GetDC()

/

DoPaint()
/
ReleaseDC()
调用(例如在
OnSize()
或其他地方)。在您的
Beep(1000,50);
实现中放置
OnEraseBkgnd()
调用,以获得有关调用时间和调用频率的声音指示。应该在窗口放大时调用它(因此必须擦除其新发现的背景),但在缩小窗口时不应调用它 - 但我不知道重新定位两个控件的效果。我宁愿在代码重新定位控件后将
CDockablePane::OnSize(nType, cx, cy);
调用移至
COutputWnd::OnSize()
中。
    

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