MFC 渐变色背景以及控件透明处理

mfc实现某对话框背景色渐变

如果是单文档视图结构,在OnDraw实现代码,如果是对话框结构,在该对话框所在的cpp里的OnPain函数【如果没有这个函数,请在类向导里派生】里实现如下代码即可,本示例是在对话框结构,某个对话框里实现的,效果如下附图

CPaintDC dc(this); // device context for painting
    CRect Rect;
	GetClientRect(Rect);
	CRect rectClient;
	CDC dcMen, dcBkgnd;
	CBitmap bitmapTemp, *pOldBitmap;
	GetClientRect(&rectClient);
	bitmapTemp.CreateCompatibleBitmap(&dc, rectClient.Width(), rectClient.Height());
	dcMen.CreateCompatibleDC(&dc);
	pOldBitmap = dcMen.SelectObject(&bitmapTemp);
	/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@主要代码@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
	int r1=217,g1=236,b1=235;
	int r2=255,g2=255,b2=235;
	for (int i=0;i<rectClient.Width();i++)
	{
		int r,g,b;
		r=r1+(i*(r2-r1))/rectClient.Width();
		g=g1+(i*(g2-g1))/rectClient.Width();
		b=b1+(i*(b2-b1))/rectClient.Width();
		dcMen.FillSolidRect(i,0,1,rectClient.Height(),RGB(r,g,b));
	}
	/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
	dc.BitBlt(0, 0, rectClient.Width(), rectClient.Height(), &dcMen, 0, 0, SRCCOPY);//绘制图片到主DC
	dcMen.SelectObject(pOldBitmap);//内存复位
	bitmapTemp.DeleteObject();

上面是横向渐变,纵向渐变只要修改几个参数 如:

int r1=217,g1=236,b1=235;
int r2=255,g2=255,b2=235;
for (int i=0;i<rectClient.Height();i++)
{
    int r,g,b;
    r=r1+(i*(r2-r1))/rectClient.Height();
    g=g1+(i*(g2-g1))/rectClient.Height();
    b=b1+(i*(b2-b1))/rectClient.Height();
    dcMen.FillSolidRect(0,i,rectClient.Width(),1,RGB(r,g,b));
}

MFC对话框添加了背景图后,会导致控件周围有阴影,很不美观,因此,我们需要将阴影进行透明化处理。此时需要使用到MFC中的消息函数OnCtlColor()。

HBRUSH CCPPDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
 
	//< TODO:  在此更改 DC 的任何特性
	if(nCtlColor == CTLCOLOR_STATIC )
	{
		pDC->SetBkMode(TRANSPARENT);//<设置背景透明
        pDC->SetTextColor(RGB(0,0,0));  
		hbr=(HBRUSH)::GetStockObject(NULL_BRUSH);
	}
	//< TODO:  如果默认的不是所需画笔,则返回另一个画笔
	return hbr;
}

注意的一点是如果有其他check radio等控件需要着背景色的时候,该段代码需要放在函数的最前面,且界面属性Clip Children属性需要设置为false,否则透明效果将会无效。

另外,当静态控件设置为透明背景之后更新静态文件上的文字会出现文字重叠的现象,有如下的解决方案

//方案一:
CRect rc;
GetDlgItem(IDC_STATIC_APPINFO)->GetWindowRect(&rc);
ScreenToClient(&rc);
InvalidateRect(&rc);
SetDlgItemText(IDC_STATIC_APPINFO,str);
//方案二
GetDlgItem(IDC_STATIC_APPINFO)->ShowWindow(SW_HIDE);
SetDlgItemText(IDC_STATIC_APPINFO,str);
GetDlgItem(IDC_STATIC_APPINFO)->ShowWindow(SW_SHOW);

说明:以上方法虽然能够解决文字重叠问题,但是会带来闪烁的问题,如果不是频繁快速的刷新是够用的,否则需要自绘控件解决。

但以上不能处理单选按钮和复选框的背景,需要添加以下代码

HBRUSH CCPPDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
 HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
 
 //< TODO: 在此更改 DC 的任何特性
 UINT id = pWnd->GetDlgCtrlID();
 if(id == IDC_RADIO_EXPMODE||IDC_RADIO_TRAINMODE||IDC_CHECK_TRACK||IDC_CHECK_SCENE||IDC_EXIT_BUTTON||IDC_MIN_BUTTON)
 {
  pDC->SetBkMode(TRANSPARENT);
  CRect rc;
  pWnd->GetWindowRect(&rc);
  ScreenToClient(&rc);
  CDC* dc = GetDC();
  pDC->BitBlt(0,0,rc.Width(),rc.Height(),dc,rc.left,rc.top,SRCCOPY); //<把父窗口背景图片先画到按钮上
  ReleaseDC(dc);
 
  hbr = (HBRUSH) ::GetStockObject(NULL_BRUSH);
 }   
 //< TODO: 如果默认的不是所需画笔,则返回另一个画笔
 return hbr;
}

效果图:

图中没有做RADIO控件的背景透明,当以上方法经过测试是有效的

 

猜你喜欢

转载自blog.csdn.net/Mr_sandman1994/article/details/83141179