65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (27投票s)

2007年4月12日

2分钟阅读

viewsIcon

83415

downloadIcon

914

本文档描述了如何通过子类化绘制背景的控件来更改框架窗口客户端区域的颜色。

Screenshot - MDIFrameBackground.jpg

引言

实际上,这是一个非常简单的任务。 难点在于弄清楚主框架窗口的背景部分并非由框架窗口本身处理。 它包含另一个窗口,填充框架边框内的区域。 该窗口被称为 m_hWndMDIClient

背景

为了完成这项任务,我的第一本能是在 CMainFrame 中捕获 WM_ERASEBKGND 并在那里执行 FillSolidRect。 但我很快意识到这种方法除了使框架闪烁并在调整大小时显示红色外,什么也没做,否则灰色背景完全保持不变。 这不是我想要的。 突然间,这变成了一个小谜题。 为什么当我填充框架的 WM_ERASEBKGND 处理程序中的颜色时,框架的背景不会改变? 所以我开始寻找,我浏览了大量的 CMDIFrameWndCFrameWnd 代码,寻找会在框架上绘制的方法,但那里并没有太多内容。 我最终来到了 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;
}

玩得开心!

© . All rights reserved.