MFC 对话框背景图片

在windows开发当中做界面的主要技术之一就是使用MFC,通常我们看到的QQ,360,暴风影音这些漂亮的界面都可以用MFC来实现。今天我们来说一下如何用MFC美化对话框,默认情况下,对话框的背景如下:

那么,我们如何将它的背景变成如下界面呢,而且还要保留对话框的移动功能,漂亮背景如下:

为了实现美化对话框背景的效果,我们需要让我们的对话框响应WM_CTLCOLOR消息,每当我们的对话框或者它的子控件需要重绘时,我们的对话框都会收到这个消息,

因此,我们需要为对话框添加WM_CTLCOLOR的消息响应函数,完成对消息的处理,WM_CTLCOLOR的响应函数定义如下:

 

 
  1. HBRUSH CMFCDialogUIDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)

  2. {

  3. HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

  4.  
  5. if (pWnd == this)

  6. {

  7. return m_bkBrush;

  8. }

  9.  
  10. return hbr;

  11. }

当我们的对话框需要重绘的时候,我们的对话框就会收到WM_CTLCOLOR消息,然后我们的对话框处理函数会调用OnCtlColor函数来处理该消息,在这个函数中,pDC代表我们要绘制的上下文环境,pWnd代表我们要绘制的窗口指针,nCtlColor代表我们要绘制的窗口类型,在函数的内部我们首先调用父类的OnCtlColor,目的是为了对该消息做默认处理,这是MFC消息响应函数的惯用写法,但是在我们这里,我们不能使用默认处理返回的画刷,所以我们需要做一个特殊的判断,如果pWnd指向的窗口地址是当前对话框,那么我们就返回m_bkBrush,这个画刷是一个图像画刷,它会在我们的对话框客户区绘制我们想让它显示的图片。下面我们看一下m_bkBrush是如何创建的,首先在我们的对话框的头文件中增加一个CBrush变量,变量名是m_bkBrush,然后在对话框的OnInitDialog中初始化它,OnInitDialog的定义如下:

 

 

 
  1. BOOL CMFCDialogUIDlg::OnInitDialog()

  2. {

  3. CDialogEx::OnInitDialog();

  4.  
  5. // 将“关于...”菜单项添加到系统菜单中。

  6.  
  7. // IDM_ABOUTBOX 必须在系统命令范围内。

  8. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

  9. ASSERT(IDM_ABOUTBOX < 0xF000);

  10.  
  11. CMenu* pSysMenu = GetSystemMenu(FALSE);

  12. if (pSysMenu != NULL)

  13. {

  14. BOOL bNameValid;

  15. CString strAboutMenu;

  16. bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);

  17. ASSERT(bNameValid);

  18. if (!strAboutMenu.IsEmpty())

  19. {

  20. pSysMenu->AppendMenu(MF_SEPARATOR);

  21. pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

  22. }

  23. }

  24.  
  25. // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动

  26. // 执行此操作

  27. SetIcon(m_hIcon, TRUE); // 设置大图标

  28. SetIcon(m_hIcon, FALSE); // 设置小图标

  29.  
  30. // TODO: 在此添加额外的初始化代码

  31.  
  32. CString strBmpPath = _T(".\\res\\Background.png");

  33.  
  34. CImage img;

  35.  
  36. img.Load(strBmpPath);

  37.  
  38. MoveWindow(0, 0, img.GetWidth(), img.GetHeight());

  39.  
  40. CBitmap bmpTmp;

  41.  
  42. bmpTmp.Attach(img.Detach());

  43.  
  44. m_bkBrush.CreatePatternBrush(&bmpTmp);

  45.  
  46. return TRUE; // 除非将焦点设置到控件,否则返回 TRUE

  47. }

现在我们看一下,在OnInitDialog中,我们都做了什么,首先,我们创建了一个CString变量strBmpPath,用它指向我们的图片文件,然后我们创建了一个CImage变量img,这个变量可以方便的加载各种格式的图像文件,所以我们使用它的目的是为了方便加载png格式的文件,MoveWindow的目的是为了调整我们的对话框客户区的大小,使客户区的大小与图片的大小一致,然后我们创建了一个CBitmap类型变量bmpTmp,使用它是因为CBrush的成员函数CreatePatternBrush的参数要求输入这种类型的参数,所以必须将img转换成CBitmap,转换的方法是bmpTmp.Attach(img.Detach()),img.Detach会释放图像的句柄,并且返回这个句柄,bmpTmp使用Attach绑定img返回的图像句柄,从而完成了对象类型的转换,最后调用CreatePatternBrush,这个函数的功能是使用传递给它的图像创建一个图像画刷,然后在OnCtlColor中,使用它填充对话框的背景,程序运行效果如下:

现在虽然程序的客户区已经变成了对话框的背景,但是对话框原来的标题栏和背景图片的标题栏重复,看起来很别扭,通过设置对话框的Border属性可以消除原来的标题栏,设置如下:

Border:None

再次编译,运行程序,效果如下:

现在的对话框背景已经和我们设想的基本一致,还有一点小瑕疵,大家仔细观察对话框的底边,左下角和右下角有多于的像素,下面我们通过代码消除它。

在OnInitDialog尾部追加如下代码:

 

 
  1. CRgn rgnTmp;

  2. RECT rc;

  3. GetClientRect(&rc);

  4. rgnTmp.CreateRoundRectRgn(rc.left + 3, rc.top + 3, rc.right - rc.left - 3, rc.bottom-rc.top -3, 6, 6);

  5. SetWindowRgn(rgnTmp, TRUE);

通过以上的代码可以让对话框变成一个圆角矩形,这样就可以去掉边角的点,程序最终运行效果如下:

现在这个对话框的背景已经完全符合我们的要求,但是它现在不能拖动,因为它的标题栏是假的,所以,我们最后一个目标就是让这个窗口可以拖动,如何才能让它移动呢?

Windows只允许我们拖动对话框的标题栏,当我们的鼠标在对话框上拖动的时候,对话框会收到一个WM_NCHITTEST消息,默认的消息处理函数会判断当前的鼠标是否在对话框的标题栏,如果在就返回HTCAPTION标志,否则就返回其它标志,当返回HTCAPTION标志的情况下,系统就会允许对话框拖动,所以我们可以欺骗windows系统,让WM_NCHITTEST的响应函数永远返回HTCAPTION标志就可以了,为对话框添加WM_NCHITTEST响应函数,代码如下:

 

 
  1. LRESULT CMFCDialogUIDlg::OnNcHitTest(CPoint point)

  2. {

  3. // TODO: 在此添加消息处理程序代码和/或调用默认值

  4. LRESULT ret = CDialogEx::OnNcHitTest(point);

  5. return (ret == HTCLIENT) ? HTCAPTION : ret;

  6. }

重新编译代码,现在的对话框背景已经美化完成,并且这个对话框可以拖动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值