更改 MDI 应用程序框架区域的背景颜色。






4.93/5 (27投票s)
2007年4月12日
2分钟阅读

83415

914
本文档描述了如何通过子类化绘制背景的控件来更改框架窗口客户端区域的颜色。
引言
实际上,这是一个非常简单的任务。 难点在于弄清楚主框架窗口的背景部分并非由框架窗口本身处理。 它包含另一个窗口,填充框架边框内的区域。 该窗口被称为 m_hWndMDIClient
。
背景
为了完成这项任务,我的第一本能是在 CMainFrame
中捕获 WM_ERASEBKGND
并在那里执行 FillSolidRect
。 但我很快意识到这种方法除了使框架闪烁并在调整大小时显示红色外,什么也没做,否则灰色背景完全保持不变。 这不是我想要的。 突然间,这变成了一个小谜题。 为什么当我填充框架的 WM_ERASEBKGND
处理程序中的颜色时,框架的背景不会改变? 所以我开始寻找,我浏览了大量的 CMDIFrameWnd
和 CFrameWnd
代码,寻找会在框架上绘制的方法,但那里并没有太多内容。 我最终来到了 CMainFrame::OnCreate
方法,设置了一个断点并逐步执行了 CMDIFrameWnd::OnCreate
方法。 经过看似数小时的搜索,我在 CMDIFrameWnd::CreateClient
中发现了以下代码
// Create MDICLIENT control with special IDC
if ((m_hWndMDIClient = ::CreateWindowEx(dwExStyle, _T("mdiclient"), NULL,
dwStyle, 0, 0, 0, 0, m_hWnd, (HMENU)AFX_IDW_PANE_FIRST,
AfxGetInstanceHandle(), (LPVOID)&ccs)) == NULL)
{
TRACE(traceAppMsg, 0, _T("Warning: CMDIFrameWnd::OnCreateClient:
failed to create MDICLIENT.")
_T(" GetLastError returns 0x%8.8X\n"), ::GetLastError());
return FALSE;
}
很明显,框架窗口正在创建另一个窗口来充当其中心(直到今天我仍然不太清楚其背后的目的)。 因此,这段代码就派上用场了。 通过子类化客户端窗口 m_hWndMDIClient
,我能够干净地更改 MDI 框架窗口的颜色。
使用代码
要更改背景颜色,首先我们必须创建一个新的 CWnd
派生类,该类处理 WM_ERASEBKGND
消息并用不同的颜色填充窗口的客户端区域。 因此,让我们添加一个名为 CClientWnd
的类,它继承自 CWnd
#pragma once
// CClientWnd
class CClientWnd : public CWnd
{
DECLARE_DYNAMIC(CClientWnd)
public:
CClientWnd();
virtual ~CClientWnd();
protected:
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
DECLARE_MESSAGE_MAP()
};
并实现 OnEraseBkgnd
方法
// ClientWnd.cpp : implementation file
#include "stdafx.h"
#include "ClientWnd.h"
// CClientWnd
IMPLEMENT_DYNAMIC(CClientWnd, CWnd)
CClientWnd::CClientWnd()
{
}
CClientWnd::~CClientWnd()
{
}
BEGIN_MESSAGE_MAP(CClientWnd, CWnd)
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
// CClientWnd message handlers
BOOL CClientWnd::OnEraseBkgnd(CDC* pDC)
{
CRect Rect;
GetClientRect(&Rect);
//fill the entire client area with Red!
pDC->FillSolidRect(&Rect,RGB(255,0,0));
//return TRUE to indicate that we took care of the erasing
return TRUE;
}
现在唯一剩下的事情就是子类化窗口 m_hWndMDIClient
。 为了做到这一点,我们将覆盖 CMainFrame::OnCreateClient
方法,并在 CMainFrame
的类声明中将 m_Client
声明为私有变量。
class CMainFrame : public CMDIFrameWnd
{
......
protected:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
private:
CClientWnd m_Client;
};
OnCreateClient
的实现应该如下所示
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if (CMDIFrameWnd::OnCreateClient(lpcs, pContext))
{
m_Client.SubclassWindow(m_hWndMDIClient);
return TRUE;
}
return FALSE;
}
玩得开心!