MFC:重绘GroupBox控件

12 篇文章 0 订阅

转自:https://www.codeproject.com/Articles/5573/CXPGroupBox-XP-style-groupbox-and-window-style-gro

不得不服,国外的一些开源代码确实很不错,而且那些热衷于专业的人很专注,而且很有分享精神。

XPGroupBox.h 文件内容如下:

#if !defined(AFX_XPGROUPBOX_H__F70D755B_9C4B_4F4A_A1FB_AFF720C29717__INCLUDED_)
#define AFX_XPGROUPBOX_H__F70D755B_9C4B_4F4A_A1FB_AFF720C29717__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif 

class CXPGroupBox : public CButton
{
	DECLARE_DYNAMIC(CXPGroupBox);

public:
	CXPGroupBox();
	virtual ~CXPGroupBox();

	enum XPGroupBoxStyle { XPGB_FRAME = 0, XPGB_WINDOW = 1 };

// Operations
public:
   virtual CXPGroupBox&	SetBorderColor(COLORREF clrBorder);
   virtual CXPGroupBox&	SetCatptionTextColor(COLORREF clrText);
   virtual CXPGroupBox& SetBackgroundColor(COLORREF clrBKClient);
   virtual CXPGroupBox&	SetBackgroundColor(COLORREF clrBKTilte,  COLORREF clrBKClient);
   virtual CXPGroupBox&	SetXPGroupStyle(XPGroupBoxStyle eStyle); 
    
   virtual CXPGroupBox& SetText(LPCTSTR lpszTitle);
   virtual CXPGroupBox& SetFontBold(BOOL bBold);
   virtual CXPGroupBox& SetFontName(const CString& strFont, BYTE byCharSet = ANSI_CHARSET);
   virtual CXPGroupBox& SetFontUnderline(BOOL bSet);
   virtual CXPGroupBox& SetFontItalic(BOOL bSet);
   virtual CXPGroupBox& SetFontSize(int nSize);
   virtual CXPGroupBox& SetFont(LOGFONT lf);

   virtual CXPGroupBox& SetAlignment(DWORD dwType);

// Overrides
public:
	virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
	protected:
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
	virtual void PreSubclassWindow();

protected:
	void UpdateSurface();
	void ReconstructFont();
	afx_msg void OnPaint();

	DECLARE_MESSAGE_MAP()

private:
	CString				_titleName;
	DWORD				_dwAlignment;
	LOGFONT				_lFont;
	CFont				_font;

	COLORREF			_borderClr;
	COLORREF			_titleBkClr;
	COLORREF			_clientBkClr;
	COLORREF			_titleTextClr;
	
	XPGroupBoxStyle		_gboxType;
};

#endif // !defined(AFX_XPGROUPBOX_H__F70D755B_9C4B_4F4A_A1FB_AFF720C29717__INCLUDED_)
XPGroupBox.cpp 文件内容如下:
#include "stdafx.h"
#include "XPGroupBox.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNAMIC(CXPGroupBox,CButton);

CXPGroupBox::CXPGroupBox()
{
    _titleName = _T("");
	
	_borderClr = ::GetSysColor(COLOR_3DSHADOW);
	_clientBkClr = ::GetSysColor(COLOR_BTNFACE);

	_titleTextClr = ::GetSysColor(COLOR_WINDOWTEXT);
	_titleBkClr = ::GetSysColor(COLOR_BTNFACE);
	
	_gboxType = XPGB_FRAME;
	_dwAlignment = SS_LEFT;
}

CXPGroupBox::~CXPGroupBox()
{
}

BEGIN_MESSAGE_MAP(CXPGroupBox, CButton)
	ON_WM_PAINT()
END_MESSAGE_MAP()

void CXPGroupBox::OnPaint() 
{
	CPaintDC dc(this);

   	CRect	rectClient;
	GetClientRect(rectClient);
	
	// Defalte Rect
	rectClient.DeflateRect(1, 1);
	
	// Get Text Rect 
	CSize sizeText;
	CRect rectText, rectFrame;
	CRect rectTitle, rectContent;
	
	CFont *pOldFont = dc.SelectObject(&_font);
  		
	// get Text if need
	if (_titleName.IsEmpty())
	{ 
        GetWindowText(_titleName);
		if (! _titleName.IsEmpty() )
			_titleName = _T(" ") + _titleName + _T(" ");
	}
	
	if (!_titleName.IsEmpty())
	{
		sizeText = dc.GetTextExtent(_titleName);
	}
	else
	{
		sizeText.cx = 0;
		sizeText.cy = 0;
	}
	
	if (_gboxType == XPGB_FRAME )		// Frame style
	{
		// Calculate Text Rect 
		switch (_dwAlignment)
		{
		case SS_LEFT:	
			rectText.top = rectClient.top;
			rectText.left = rectClient.left + 10;
			
			rectText.bottom = rectText.top + sizeText.cy;
			rectText.right = rectText.left + sizeText.cx;
			break;
		case SS_CENTER:	
			rectText.top = rectClient.top;
			rectText.left = rectClient.left + (rectClient.Width() - sizeText.cx) / 2 ;
			
			rectText.bottom = rectText.top + sizeText.cy;
			rectText.right = rectText.left + sizeText.cx;
			break;
		case SS_RIGHT	:
			rectText.top = rectClient.top;
			rectText.right = rectClient.right -10 ;
			
			rectText.bottom = rectText.top + sizeText.cy;
			rectText.left = rectText.right - sizeText.cx;
			break;
		}
		
		//  Calculate Frame rect
		rectFrame.left = rectClient.left;
		rectFrame.top = rectClient.top + sizeText.cy / 2;
		
		rectFrame.right = rectClient.right;
		rectFrame.bottom = rectFrame.top + rectClient.Height() - sizeText.cy / 2; 
		
		// Draw Frame border
		CPen penFrame;
		CBrush brushBKFrame(_titleBkClr);
		
		penFrame.CreatePen(PS_SOLID, 1, _borderClr);
		
		CPen* pOldPen = dc.SelectObject(&penFrame);
		CBrush* pOldBrush = (CBrush*)dc.SelectStockObject(NULL_BRUSH);
		
		dc.RoundRect(rectFrame, CPoint(10, 10)); 
		
		dc.SelectObject(pOldPen);
		dc.SelectObject(pOldBrush); 
		
		dc.IntersectClipRect(rectText);
		dc.FillSolidRect(rectText, _titleBkClr);
	}
	else  // Windows Style
	{
		// Calculate Title size
		rectTitle.top = rectClient.top;
		rectTitle.left = rectClient.left ;
		
		rectTitle.right = rectClient.right;
		rectTitle.bottom = rectClient.top + sizeText.cy + 4;
		
		// Draw Title round rect
		CPen penFrame;
		CBrush brushBKTitle(_titleBkClr);
		CBrush brushBKContent(_clientBkClr);
		
		penFrame.CreatePen(PS_SOLID, 1, _borderClr);
		
		CPen* pOldPen = dc.SelectObject(&penFrame);
		CBrush* pOldBrush = dc.SelectObject(&brushBKTitle);
		
		dc.RoundRect(rectClient, CPoint(10, 10)); 
		
		dc.SelectObject(pOldBrush); 
		
		// Draw content area
		rectContent.left = rectClient.left;
		rectContent.top = rectClient.top + sizeText.cy + 4;
		
		rectContent.right = rectClient.right;
		rectContent.bottom = rectContent.top + rectClient.Height() - sizeText.cy - 4; 
		
		pOldBrush = dc.SelectObject(&brushBKContent); 
		
		dc.Rectangle(rectContent);  
		
		dc.SelectObject(pOldPen);
		dc.SelectObject(pOldBrush); 
		
		// Calculate Text Rect 
		switch (_dwAlignment)
		{
		case SS_LEFT:	
			rectText.top = rectTitle.top + 2;
			rectText.left = rectTitle.left + 2 ;
			
			rectText.bottom = rectText.top + sizeText.cy;
			rectText.right = rectText.left + sizeText.cx ;
			break;
		case SS_CENTER:	
			rectText.top = rectTitle.top + 2;
			rectText.left = rectTitle.left + (rectTitle.Width() - sizeText.cx) / 2 ;
			
			rectText.bottom = rectText.top + sizeText.cy;
			rectText.right = rectText.left + sizeText.cx ;
			break;
		case SS_RIGHT	:
			rectText.top = rectTitle.top + 2;
			rectText.right = rectClient.right - 2  ;
			
			rectText.bottom = rectText.top + sizeText.cy;
			rectText.left = rectText.right - sizeText.cx;
			break;
		}
	}
    
	COLORREF clrOldText = dc.SetTextColor(_titleTextClr);
	UINT nMode = dc.SetBkMode(TRANSPARENT);
	
	dc.DrawText(_titleName, &rectText, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_NOCLIP ); //DT_END_ELLIPSIS);
	
	// restore DC
	dc.SetBkMode(nMode);
    dc.SetTextColor(clrOldText);
    dc.SelectObject(pOldFont);
}

BOOL CXPGroupBox::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{
	dwStyle |= BS_ICON;
	return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}

BOOL CXPGroupBox::PreCreateWindow(CREATESTRUCT& cs) 
{
	cs.style |= BS_ICON;
	return CButton::PreCreateWindow(cs);
}

void CXPGroupBox::PreSubclassWindow() 
{
	CButton::PreSubclassWindow();

	//modified the style to avoid text overlap when press tab 
	ModifyStyle(0, BS_ICON);

	// Get Defalut Font 
	CFont* cf = GetFont();
	if (cf !=NULL)
	{
		cf->GetObject(sizeof(_lFont), &_lFont);
	}
	else
	{
		GetObject(GetStockObject(SYSTEM_FONT),sizeof(_lFont), &_lFont);
	}

	ReconstructFont();
}

void CXPGroupBox::ReconstructFont()
{
	_font.DeleteObject();
	BOOL bCreated = _font.CreateFontIndirect(&_lFont);

	ASSERT(bCreated);
}

void CXPGroupBox::UpdateSurface()
{
	CRect (rc);
	GetWindowRect(rc);
	RedrawWindow();

	GetParent()->ScreenToClient(rc);
	GetParent()->InvalidateRect(rc, TRUE);
	GetParent()->UpdateWindow();
}

CXPGroupBox& CXPGroupBox::SetXPGroupStyle(XPGroupBoxStyle eStyle) 
{
   _gboxType = eStyle;
   UpdateSurface();
   return *this;
}

CXPGroupBox& CXPGroupBox::SetFont(LOGFONT lf)
{
	CopyMemory(&_lFont, &lf, sizeof(_lFont));
	ReconstructFont();
	UpdateSurface();
	return *this;
}

CXPGroupBox& CXPGroupBox::SetFontBold(BOOL bBold)
{
	_lFont.lfWeight = bBold ? FW_BOLD : FW_NORMAL;
	ReconstructFont();
	UpdateSurface();
	return *this;
}

CXPGroupBox& CXPGroupBox::SetFontName(const CString& strFont, BYTE byCharSet)
{
	_lFont.lfCharSet = byCharSet;

	_tcscpy(_lFont.lfFaceName,strFont);
	ReconstructFont();
	UpdateSurface();

	return *this;
}

CXPGroupBox& CXPGroupBox::SetFontUnderline(BOOL bSet)
{
	_lFont.lfUnderline = bSet;
	ReconstructFont();
	UpdateSurface();

	return *this;
}

CXPGroupBox& CXPGroupBox::SetFontItalic(BOOL bSet)
{
	_lFont.lfItalic = bSet;
	ReconstructFont();
	UpdateSurface();

	return *this;	
}

CXPGroupBox& CXPGroupBox::SetFontSize(int nSize)
{
	CFont cf;
	LOGFONT lf;

	cf.CreatePointFont(nSize * 10, _lFont.lfFaceName);
	cf.GetLogFont(&lf);

	_lFont.lfHeight = lf.lfHeight;
	_lFont.lfWidth  = lf.lfWidth;

	ReconstructFont();
	UpdateSurface();

	return *this;
}

CXPGroupBox& CXPGroupBox::SetBorderColor(COLORREF clrBorder)
{
	_borderClr = clrBorder;
	UpdateSurface();
	return *this;
}

CXPGroupBox& CXPGroupBox::SetCatptionTextColor(COLORREF clrText) 
{
	_titleTextClr = clrText;
	UpdateSurface();
	return *this;
}

CXPGroupBox& CXPGroupBox::SetBackgroundColor(COLORREF clrBKClient)
{
	_titleBkClr = clrBKClient;
	_clientBkClr = clrBKClient;
	UpdateSurface();
	return *this;
}

CXPGroupBox& CXPGroupBox::SetBackgroundColor(COLORREF clrBKTilte,  COLORREF clrBKClient)
{
	_titleBkClr = clrBKTilte;
	_clientBkClr = clrBKClient;
	UpdateSurface();
	return *this;
}

CXPGroupBox& CXPGroupBox::SetText(LPCTSTR lpszText)
{
	if (IsWindow(this->GetSafeHwnd())) 
	{
		_titleName = lpszText;
		_titleName = _T(" ") + _titleName + _T(" ");
		UpdateSurface();
	}
	
	return *this;
}

CXPGroupBox& CXPGroupBox::SetAlignment(DWORD dwType)
{
	switch (dwType)
	{
	default	: ASSERT(false);
	case SS_LEFT:	
		_dwAlignment = SS_LEFT;
		break;
	case	SS_CENTER:	
		_dwAlignment = SS_CENTER;
		break;
	case	SS_RIGHT	:
		_dwAlignment = SS_RIGHT;
		break;
	}
	UpdateSurface();
	
	return *this;
}
接下来就简单了,在对话框中随便添加几个GroupBox进行测试,将它们的类型设置成CXPGroupBox,测试的结果如下:


  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值