MFC界面美化方法

MFC的界面真的是很难看,但是我们可以通过一些方法对它进行美化,看看一下的几个方法。

●重绘对话框

先看看效果图再上代码:


首先先在StdAfx.cpp的文件中加入代码:

class CBitmapEx:public CBitmap
{
protected:
	BITMAP m_bmpStruct;
public:
	CBitmapEx(){memset(&m_bmpStruct,0,sizeof(BITMAP));} ;
	virtual~CBitmapEx(){} ;

	const int GetWidth()const{return m_bmpStruct.bmWidth;} ;
	const int GetHeight()const{return m_bmpStruct.bmHeight;} ;
	bool LoadBitmapEx(UINT nIDResource)
	{
		if (CBitmap::LoadBitmap(nIDResource))
		{
			GetBitmap(&m_bmpStruct);
			return true;
		}
		return false;
	}
};
这是自己写的继承CBitmap的类。

然后,创建几个位图的对象。

CBitmapEx m_bmpTopLeft;
	CBitmapEx m_bmpTopRepeat;
	CBitmapEx m_bmpTopRight;
	CBitmapEx m_bmpLeftRepeat;
	CBitmapEx m_bmpRightRepeat;
	CBitmapEx m_bmpBottomLeft;
	CBitmapEx m_bmpBottomRepeat;
	CBitmapEx m_bmpBottomRight;

在OnCreate函数中初始化这些对象,将准备好的位图和这些对象关联。

m_bmpTopLeft.LoadBitmapEx(DIALOG_TOP_LEFT);
 	m_bmpTopRepeat.LoadBitmapEx(DIALOG_TOP_REPEAT);
	m_bmpTopRight.LoadBitmapEx(DIALOG_TOP_RIGHT);
 
 	m_bmpLeftRepeat.LoadBitmapEx(DIALOG_LEFT_REPEAT);
 	m_bmpRightRepeat.LoadBitmapEx(DIALOG_RIGHT_REPEAT);
 
	m_bmpBottomLeft.LoadBitmapEx(DIALOG_BOTTOM_LEFT);
 	m_bmpBottomRepeat.LoadBitmapEx(DIALOG_BOTTOM_REPEAT);
 	m_bmpBottomRight.LoadBitmapEx(DIALOG_BOTTOM_RIGHT);
在OnNcPaint (WM_NCPAINT的消息映射,这个消息是用来处理frame的重绘的,具体的网址 点击打开链接)中加入如下代码:

CWindowDC mdc(this);
	CDC   dcMemory;
	dcMemory.CreateCompatibleDC(&mdc);
	CRect rcWnd;
	GetWindowRect(&rcWnd);
	rcWnd.OffsetRect(-rcWnd.TopLeft());

	CRect  rcTopLeft(rcWnd);
	rcTopLeft.right=m_bmpTopLeft.GetWidth()+rcTopLeft.left;
	rcTopLeft.bottom=m_bmpTopLeft.GetHeight()+rcTopLeft.top;
	CBitmap *pOldBitmap=dcMemory.SelectObject(&m_bmpTopLeft);
	mdc.BitBlt(rcTopLeft.left,rcTopLeft.top,rcTopLeft.Width(),rcTopLeft.Height(),
		&dcMemory,0,0,SRCCOPY);

	CRect  rcTopRepeat(rcWnd);
	rcTopRepeat.left=rcTopLeft.right;
	rcTopRepeat.bottom=rcTopLeft.bottom;
	rcTopRepeat.right=rcWnd.right-m_bmpTopRight.GetWidth(); 
	dcMemory.SelectObject(&m_bmpTopRepeat);
	mdc.StretchBlt(rcTopRepeat.left,rcTopRepeat.top,rcTopRepeat.Width(),rcTopRepeat.Height(),
		&dcMemory,0,0,m_bmpTopRepeat.GetWidth(),m_bmpTopRepeat.GetHeight(),SRCCOPY);

	CRect  rcTopRight(rcWnd);
	rcTopRight.left=rcTopRepeat.right;
	rcTopRight.bottom=rcTopRepeat.bottom;
	dcMemory.SelectObject(&m_bmpTopRight);
	mdc.BitBlt(rcTopRight.left,rcTopRight.top,rcTopRight.Width(),rcTopRight.Height(),
		&dcMemory,0,0,SRCCOPY);

	CRect  rcLeftRepeat;
	rcLeftRepeat.SetRect(rcWnd.left,rcTopLeft.bottom,m_bmpLeftRepeat.GetWidth(),rcWnd.bottom-m_bmpBottomLeft.GetHeight());
	dcMemory.SelectObject(&m_bmpLeftRepeat);
	mdc.StretchBlt(rcLeftRepeat.left,rcLeftRepeat.top,rcLeftRepeat.Width(),rcLeftRepeat.Height(),
		&dcMemory,0,0,m_bmpLeftRepeat.GetWidth(),m_bmpLeftRepeat.GetHeight(),SRCCOPY);

	CRect  rcRightRepeat(rcLeftRepeat);
	rcRightRepeat.left=rcTopRepeat.right;
	rcRightRepeat.right=rcWnd.right;
	dcMemory.SelectObject(&m_bmpRightRepeat);
	mdc.StretchBlt(rcRightRepeat.left,rcRightRepeat.top,rcRightRepeat.Width(),rcRightRepeat.Height(),
		&dcMemory,0,0,m_bmpRightRepeat.GetWidth(),m_bmpRightRepeat.GetHeight(),SRCCOPY);

	CRect  rcBottomLeft(rcWnd);
	rcBottomLeft.top=rcLeftRepeat.bottom;
	rcBottomLeft.right=rcLeftRepeat.right;
	dcMemory.SelectObject(&m_bmpBottomLeft);
	mdc.BitBlt(rcBottomLeft.left,rcBottomLeft.top,rcBottomLeft.Width(),rcBottomLeft.Height(),
		&dcMemory,0,0,SRCCOPY);

	CRect  rcBottomRepeat(rcWnd);
	rcBottomRepeat.left=rcBottomLeft.right;
	rcBottomRepeat.top=rcBottomLeft.top;
	rcBottomRepeat.right=rcWnd.right-m_bmpBottomRight.GetWidth();
	dcMemory.SelectObject(&m_bmpBottomRepeat);
	mdc.StretchBlt(rcBottomRepeat.left,rcBottomRepeat.top,rcBottomRepeat.Width(),rcBottomRepeat.Height(),
		&dcMemory,0,0,m_bmpBottomRepeat.GetWidth(),m_bmpBottomRepeat.GetHeight(),SRCCOPY);

	CRect  rcBottomRight(rcWnd);
	rcBottomRight.left=rcBottomRepeat.right;
	rcBottomRight.top=rcBottomRepeat.top;
	dcMemory.SelectObject(&m_bmpBottomRight);
	mdc.BitBlt(rcBottomRight.left,rcBottomRight.top,rcBottomRight.Width(),rcBottomRight.Height(),
		&dcMemory,0,0,SRCCOPY);
	dcMemory.SelectObject(pOldBitmap) ;

其实就是把图片重新画到frame上的过程。

然后在OnCtlColor(WM_CTLCOLOR的消息处理函数,这个消息是用来处理控件的颜色的,具体介绍的网址点击打开链接)中加入如下代码:

static CBrush brushDialog(RGB(240,240,240));

	if (nCtlColor == CTLCOLOR_DLG)
	{
		return brushDialog;
	}
	if(nCtlColor == CTLCOLOR_STATIC)
	{
		pDC->SetBkColor(RGB(240,240,240));
		HBRUSH m_bkBrush = ::CreateSolidBrush(RGB(240,240,240));
        return m_bkBrush;
	}

上面的代码是用来重绘对话框上控件的颜色的。

再在OnEraseBkgnd中重绘对话框的背景:

	CRect rcClient;	
	CBrush brushBkgrnd(RGB(240,240,240));

	GetWindowRect(&rcClient);
	ScreenToClient(&rcClient);
	pDC->FillRect(&rcClient, &brushBkgrnd);

再在OnNcHitTest(WM_NCHITTEST 发送到一个窗口,以确定窗口的一部分对应于一个特定的屏幕坐标,具体点击打开链接)中加入如下代码:

CPoint p(point) ;
	ScreenToClient(&p) ;
	if (p.y>=0&&p.y<=20)
	   return HTCAPTION   ;

这是指定窗口的一部分为非客户区,用来拖动窗口。

当然我们也可以用上面的方法来重写一个DLG的类,这样所有的对话框就都可以变成这种效果了。

就此就完成了对话框的重绘过程,上面需要的位图可以在这里下载。运用好这些消息处理,MFC也可以制作出很好看的对话框。

●重绘按钮

自己重绘一个按钮。

首先在PreSubclassWindow中 加入如下代码:

ModifyStyle(0, BS_OWNERDRAW);
允许进行按钮的重绘工作。

然后,创建一些我们需要使用的对象,代码如下:

        //按钮的外边框
	CPen m_BoundryPen;
	
	//鼠标指针置于按钮之上时按钮的内边框
	CPen m_InsideBoundryPenLeft;
	CPen m_InsideBoundryPenRight;
	CPen m_InsideBoundryPenTop;
	CPen m_InsideBoundryPenBottom;
	
	//按钮获得焦点时按钮的内边框
	CPen m_InsideBoundryPenLeftSel;
	CPen m_InsideBoundryPenRightSel;
	CPen m_InsideBoundryPenTopSel;
	CPen m_InsideBoundryPenBottomSel;
	
	//按钮的底色,包括有效和无效两种状态
	CBrush m_FillActive;
	CBrush m_FillInactive;
	
	//按钮的状态
	BOOL m_bOver;	//鼠标位于按钮之上时该值为true,反之为flase
	BOOL m_bTracking;	//在鼠标按下没有释放时该值为true
	BOOL m_bSelected;	//按钮被按下是该值为true
	BOOL m_bFocus;	//按钮为当前焦点所在时该值为true
初始化这些对象,在构造函数中进行:

m_BoundryPen.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0, 0, 0));
	m_InsideBoundryPenLeft.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(250, 196, 88)); 
	m_InsideBoundryPenRight.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(251, 202, 106));
	m_InsideBoundryPenTop.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(252, 210, 121));
	m_InsideBoundryPenBottom.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(229, 151, 0));
	
	m_FillActive.CreateSolidBrush(RGB(223, 222, 236));
	m_FillInactive.CreateSolidBrush(RGB(222, 223, 236));
	
	m_InsideBoundryPenLeftSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(153, 198, 252)); 
	m_InsideBoundryPenTopSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255));
	m_InsideBoundryPenRightSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(162, 189, 252));
	m_InsideBoundryPenBottomSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255));
	
	m_bOver = m_bSelected = m_bTracking = m_bFocus = FALSE;

重写绘制按钮底色的虚函数:

void CXPButton::DoGradientFill(CDC *pDC, CRect* rect)
{
	CBrush brBk[64];
	int nWidth = rect->Width();	
	int nHeight = rect->Height();
	CRect rct;
	
	for (int i = 0; i < 64; i ++)
	{
		if (m_bOver)
		{
			if (m_bFocus)
				brBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 3)));
			else
				brBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 5)));
		}
		else
		{
			if (m_bFocus)
				brBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 4)));
			else
				brBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 5)));
		}
	}
	
	for (i = rect->top; i <= nHeight + 2; i ++) 
	{
		rct.SetRect(rect->left, i, nWidth + 2, i + 1);
		pDC->FillRect(&rct, &brBk[((i * 63) / nHeight)]);
	}
	
	for (i = 0; i < 64; i ++)
		brBk[i].DeleteObject();
}
重写绘制按钮内边框的函数:

void CXPButton::DrawInsideBorder(CDC *pDC, CRect* rect)
{
	CPen *pLeft, *pRight, *pTop, *pBottom;
	
	if (m_bSelected && !m_bOver)
	{
		pLeft = & m_InsideBoundryPenLeftSel;
		pRight = &m_InsideBoundryPenRightSel;
		pTop = &m_InsideBoundryPenTopSel;
		pBottom = &m_InsideBoundryPenBottomSel;
	}
	else
	{
		pLeft = &m_InsideBoundryPenLeft;
		pRight = &m_InsideBoundryPenRight;
		pTop = &m_InsideBoundryPenTop;
		pBottom = &m_InsideBoundryPenBottom;
	}
	
	CPoint oldPoint = pDC->MoveTo(rect->left, rect->bottom - 1);
	CPen* pOldPen = pDC->SelectObject(pLeft);
	pDC->LineTo(rect->left, rect->top + 1);
	pDC->SelectObject(pRight);
	pDC->MoveTo(rect->right - 1, rect->bottom - 1);
	pDC->LineTo(rect->right - 1, rect->top);
	pDC->SelectObject(pTop);
	pDC->MoveTo(rect->left - 1, rect->top);
	pDC->LineTo(rect->right - 1, rect->top);
	pDC->SelectObject(pBottom);
	pDC->MoveTo(rect->left, rect->bottom);
	pDC->LineTo(rect->right - 1, rect->bottom);
	pDC->SelectObject(pOldPen);
	pDC->MoveTo(oldPoint);

	if (m_bSelected && !m_bOver)
		DrawFocusRect(pDC->m_hDC,rect);
}

添加消息响应WM_MOUSEMOVE,并且根据鼠标移动函数添加鼠标经过和离开按钮的消息:

BEGIN_MESSAGE_MAP(CXPButton, CButton)
	//{{AFX_MSG_MAP(CXPButton)
	ON_WM_MOUSEMOVE()
	ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
	ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CXPButton::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if (!m_bTracking)
	{
		TRACKMOUSEEVENT tme;
		tme.cbSize = sizeof(tme);
		tme.hwndTrack = m_hWnd;
		tme.dwFlags = TME_LEAVE | TME_HOVER;
		tme.dwHoverTime = 1;
		m_bTracking = _TrackMouseEvent(&tme);
	}
	
	CButton::OnMouseMove(nFlags, point);
}

分别处理各种情况,将标志的值设成相应的状态:
LRESULT CXPButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
	m_bOver = FALSE;
	m_bTracking = FALSE;
	InvalidateRect(NULL, FALSE);
	return 0;
}

LRESULT CXPButton::OnMouseHover(WPARAM wParam, LPARAM lParam)
{
	m_bOver = TRUE;
	InvalidateRect(NULL);
	return 0;
}
最后在DrawItem中绘制按钮:

void CXPButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	//从lpDrawItemStruct获取控件的相关信息
	CRect rect =  lpDrawItemStruct->rcItem;
	CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
	int nSaveDC=pDC->SaveDC();
	UINT state = lpDrawItemStruct->itemState;
	POINT pt ;
	TCHAR strText[MAX_PATH + 1];
	::GetWindowText(m_hWnd, strText, MAX_PATH);
	
	//画按钮的外边框,它是一个半径为5的圆角矩形
	pt.x = 5;
	pt.y = 5;
	CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);
	pDC->RoundRect(&rect, pt);
	
	//获取按钮的状态
	if (state & ODS_FOCUS)
	{
		m_bFocus = TRUE;
		m_bSelected = TRUE;
	}
	else
	{
		m_bFocus = FALSE;
		m_bSelected = FALSE;
	}
	
	
	if (state & ODS_SELECTED || state & ODS_DEFAULT)
	{
		m_bFocus = TRUE;
	}

	
	pDC->SelectObject(hOldPen);
	
	rect.DeflateRect(CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)));
	
	//根据按钮的状态填充按钮的底色
	CBrush* pOldBrush;
	if (m_bOver)
	{
		pOldBrush = pDC->SelectObject(&m_FillActive);
		DoGradientFill(pDC, &rect);
	}
	else
	{
		pOldBrush = pDC->SelectObject(&m_FillInactive);
		DoGradientFill(pDC, &rect);
	}
	
	//根据按钮的状态绘制内边框
	if (m_bOver || m_bSelected)
		DrawInsideBorder(pDC, &rect);
				
	pDC->SelectObject(pOldBrush);
	
	//显示按钮的文本
	if (strText!=NULL)
	{
		CFont* hFont = GetFont();
		CFont* hOldFont = pDC->SelectObject(hFont);
		CSize szExtent = pDC->GetTextExtent(strText, lstrlen(strText));
		CPoint pt( rect.CenterPoint().x - szExtent.cx / 2, rect.CenterPoint().y - szExtent.cy / 2);
		if (state & ODS_SELECTED) 
			pt.Offset(1, 1);
		int nMode = pDC->SetBkMode(TRANSPARENT);
		if (state & ODS_DISABLED)
			pDC->DrawState(pt, szExtent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
		else
			pDC->DrawState(pt, szExtent, strText, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);
		pDC->SelectObject(hOldFont);
		pDC->SetBkMode(nMode);
	}
	
	
	pDC->RestoreDC(nSaveDC);
}

到此漂亮的按钮就制作完了,如果有想直接用的朋友,可以去 这里下载

●如果有用到PropertySheet的朋友,也可以用到上述的方法去改变界面的样式,但是有一些不同的地方。

去除属性页标题:

在sheet的OnInitDialog函数中,添加如下代码:

	//去掉标题栏
	DWORD style =  GetStyle();
	style = style & ~WS_CAPTION;
	::SetWindowLong( GetSafeHwnd(), GWL_STYLE, style );

改变PropertyPage上的按钮,及和按钮在一行的标题栏的颜色:

需要我们去重写一个TabCtrl的类,并且在OnEraseBkgnd中加入如下代码:

CRect rect;
	GetWindowRect(&rect);
	ScreenToClient(&rect);
//		CBrush brush(GetSysColor(COLOR_3DFACE));	// Tab Control背景色
	CBrush brush(RGB(240,240,240));
	pDC->FillRect(rect,&brush);
	return TRUE;

在DrawItem里加入如下代码:

CRect rect;
	GetWindowRect(&rect);
	ScreenToClient(&rect);
//		CBrush brush(GetSysColor(COLOR_3DFACE));	// Tab Control背景色
	CBrush brush(RGB(240,240,240));
	pDC->FillRect(rect,&brush);
	return TRUE;
}

void COwnerDrawTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	TCHAR szTabText[64]={0};

    TC_ITEM     tci;
    tci.mask        = TCIF_TEXT;
    tci.pszText     = szTabText;
    tci.cchTextMax  = sizeof(szTabText)-1;
	CBrush m_brushBK(RGB(240,240,240));
    GetItem( lpDrawItemStruct->itemID, &tci);
    CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);    
    pDC->FillRect( &lpDrawItemStruct->rcItem, &m_brushBK);
    pDC->SetBkColor( RGB(240,240,240));

    if ((lpDrawItemStruct->itemState & ODS_SELECTED) && 
        (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
    {
        //Make the color of text of the selected tab to be BLUE.
        pDC->SetTextColor(RGB( 0,0 , 255));
    }
    //! 文字的位置可能的偏移
    pDC->TextOut(lpDrawItemStruct->rcItem.left+4,lpDrawItemStruct->rcItem.top+4,tci.pszText,lstrlen(tci.pszText));
最后在sheet的OnInitDialog中加入如下代码:

//更改TabCtrl颜色
	m_tabOwnerDraw.SubclassWindow( GetTabControl()->m_hWnd);
    m_tabOwnerDraw.ModifyStyle(0,TCS_OWNERDRAWFIXED);

希望这些美化MFC界面的小经验对大家有用。





  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MFC(Microsoft Foundation Class)是微软基于Windows操作系统开发的一套可视化程序设计的类库,其中对话框是MFC中常用的界面元素之一。想要对MFC对话框进行美化,可以采取以下几个方法。 首先,可以使用MFC自带的控件及样式来美化对话框。MFC提供了丰富的控件,如按钮、列表框、组合框等,可根据需求选择合适的控件,并设置其颜色、字体等属性,使界面更加美观。同时,还可以通过MFC提供的样式选择对话框的风格,如更改对话框的背景色,添加背景图片等。 其次,可以使用图形库来美化对话框。可以引入第三方图形库,如GDI+等,利用其强大的图形处理能力来实现更丰富的界面效果。通过绘制图形、实现渐变色等操作,可以使对话框更加生动、有趣。 另外,可以使用自定义控件来美化对话框。MFC允许开发者自定义控件,可以根据需求编写自己的控件,并在对话框中使用。这样可以实现更加个性化、独特的界面效果,提升用户体验。 最后,可以使用第三方界面库来美化对话框。市面上有许多成熟的界面库,如DuiLib、BCGControlBar等,这些库提供了丰富的界面控件和样式,可以直接使用它们提供的控件来进行界面美化,节省开发时间和精力。 综上所述,通过使用MFC自带的控件及样式、引入图形库、自定义控件、使用第三方界面库等方法,可以对MFC对话框进行美化,提升应用程序的界面效果和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春阳CYang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值