VC的对话框应用程序界面十分粗糙,一点也不炫,我们会想给它加一个绚丽的背景。这可以通过加载位图实现,具体步骤可以参加博客:http://blog.csdn.net/gameloft9/article/details/23427895。
但是,我们会发现一个问题,就是控件不是透明的,背景图片被控件遮挡了,这十分影响界面的美观。怎么办呢?我们有两种方法解决:
第一种,设置控件的背景为透明的,然后返回一个跟背景颜色相同的画刷即可。系统会使用你返回的画刷进行重绘。但是这种方式,仅支持纯色的背景。所以这种方式可以略过。可能你会问,直接将控件背景设置为透明的背景图片不就显示出来了吗?为什么还要用画刷来重绘呢?
其实,我们加载的背景图片并不是真正的背景,只是覆盖在背景上的一幅图片而已。你把控件设置为透明的之后,对话框的背景就出来了,你会发现它并不是你加载的背景图片,而是纯色(比如黑色)。这就是为什么你设置为其它颜色的纯色背景后,还要用画刷来重绘的原因。
第二种,重绘控件。简单的来说就是将控件遮住的那部分背景,通过响应WM_CTLCOLOR消息,重绘到控件上。看起来彷佛控件是透明的一样,其实是将背景绘到了控件上而已。关于WM_CTLCOLOR可以参考博客:http://blog.csdn.net/gameloft9/article/details/23701755
在WM_CTLCOLOR的响应函数OnCtlColor()中添加代码如下:
HBRUSH CMFCDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
//这种情况除非背景是纯色才行
/* if(nCtlColor == CTLCOLOR_BTN)
{
pDC->SetBkMode(TRANSPARENT);
hbr = (HBRUSH) ::GetStockObject(NULL_BRUSH);
} */
UINT id = pWnd->GetDlgCtrlID();//获取控件ID
if(id == IDC_EDIT1 || id == IDC_CHECK1 || id == IDC_SLIDER1)//WM_CTLCOLOR消息仅支持7种控件的重绘,由nCtlColor标志控件类型,我们有其它的控件,所以不使用nCtlColor参数。
{
CBrush m_brush;
CBitmap m_bitmap;
BITMAP btpifo;
pDC->SetBkMode(TRANSPARENT);//将控件背景设置为透明的
m_bitmap.LoadBitmap(IDB_BTP_BK);//加载背景图片
m_bitmap.GetBitmap(&btpifo);
CRect rc;//保存按钮区域
pWnd->GetWindowRect(&rc);
ScreenToClient(&rc);
CDC memo_dc;//兼容DC
memo_dc.CreateCompatibleDC(pDC);
memo_dc.SelectObject(m_bitmap);
pDC->BitBlt(0,0,rc.Width(),rc.Height(),&memo_dc,rc.left,rc.top,SRCCOPY); //把父窗口背景图片画到按钮上
//释放资源
memo_dc.DeleteDC();
m_bitmap.DeleteObject();
hbr = (HBRUSH) ::GetStockObject(NULL_BRUSH);//获取特定的颜色的画刷,null_brush is used to draw nothing
}
// TODO: 如果默认的不是所需画笔,则返回另一个画笔
return hbr;
}
注:
这里采用了双缓冲绘图机制,可以防止重绘时控件有文字重影和闪烁的问题。如果你添加背景的绘图函数是StretchBlt那么会导致重绘控件的背景不是真正的背景,因为StretchBlt对图片进行了放缩,你DC中的被控件遮住的背景的位置和对话框上被遮住的位置就不是一致的。所以,采用BitBlt函数加载背景图片比较好,这样可以保证两者位置一致。