在windows开发当中做界面的主要技术之一就是使用MFC,通常我们看到的QQ,360,暴风影音这些漂亮的界面都可以用MFC来实现。今天我们来说一下如何用MFC美化对话框,默认情况下,对话框的背景如下:
那么,我们如何将它的背景变成如下界面呢,而且还要保留对话框的移动功能,漂亮背景如下:
为了实现美化对话框背景的效果,我们需要让我们的对话框响应WM_CTLCOLOR消息,每当我们的对话框或者它的子控件需要重绘时,我们的对话框都会收到这个消息,头文件增加 m_bkBrush 成员
class Cdemo123Dlg : public CDialog
{
public:
CBrush m_bkBrush;
}
因此,我们需要为对话框添加WM_CTLCOLOR的消息响应函数,完成对消息的处理,WM_CTLCOLOR的响应函数定义如下:
HBRUSH CMFCDialogUIDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
if (pWnd == this)
{
return m_bkBrush;
}
return hbr;
}
当我们的对话框需要重绘的时候,我们的对话框就会收到WM_CTLCOLOR消息,然后我们的对话框处理函数会调用OnCtlColor函数来处理该消息,在这个函数中,pDC代表我们要绘制的上下文环境,pWnd代表我们要绘制的窗口指针,nCtlColor代表我们要绘制的窗口类型,在函数的内部我们首先调用父类的OnCtlColor,目的是为了对该消息做默认处理,这是MFC消息响应函数的惯用写法,但是在我们这里,我们不能使用默认处理返回的画刷,所以我们需要做一个特殊的判断,如果pWnd指向的窗口地址是当前对话框,那么我们就返回m_bkBrush,这个画刷是一个图像画刷,它会在我们的对话框客户区绘制我们想让它显示的图片。下面我们看一下m_bkBrush是如何创建的,首先在我们的对话框的头文件中增加一个CBrush变量,变量名是m_bkBrush,然后在对话框的OnInitDialog中初始化它,OnInitDialog的定义如下:
BOOL CMFCDialogUIDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
CString strBmpPath = _T(".\\res\\Background.png");
CImage img;
img.Load(strBmpPath);
//MoveWindow(0, 0, img.GetWidth(), img.GetHeight());
CBitmap bmpTmp;
bmpTmp.Attach(img.Detach());
m_bkBrush.CreatePatternBrush(&bmpTmp);
//根据图片大小设置窗口大小
int nDstWidth = 582;//图片的宽
int nDstHeight = 404;//图片的高
//得到显示器大小
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
//再用MoveWindow
CRect rcTemp;
rcTemp.TopLeft() = CPoint(cx / 2 - nDstWidth / 2, cy / 2 - nDstHeight / 2);
rcTemp.BottomRight() = CPoint(cx / 2 + nDstWidth / 2, cy / 2 + nDstHeight / 2);
MoveWindow(&rcTemp);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
现在我们看一下,在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
再次编译,运行程序,效果如下:
现在这个对话框的背景已经完全符合我们的要求,但是它现在不能拖动,因为它的标题栏是假的,所以,我们最后一个目标就是让这个窗口可以拖动,如何才能让它移动呢?
Windows只允许我们拖动对话框的标题栏,当我们的鼠标在对话框上拖动的时候,对话框会收到一个WM_NCHITTEST消息,默认的消息处理函数会判断当前的鼠标是否在对话框的标题栏,如果在就返回HTCAPTION标志,否则就返回其它标志,当返回HTCAPTION标志的情况下,系统就会允许对话框拖动,所以我们可以欺骗windows系统,让WM_NCHITTEST的响应函数永远返回HTCAPTION标志就可以了,为对话框添加WM_NCHITTEST响应函数,代码如下:
注意:LRESULT ret = CDialogEx::OnNcHitTest(point); 编译不过,去掉 Ex
LRESULT CMFCDialogUIDlg::OnNcHitTest(CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
LRESULT ret = CDialogEx::OnNcHitTest(point);
return (ret == HTCLIENT) ? HTCAPTION : ret;
}
模拟标题栏拖动文章来源:https://www.toymoban.com/news/detail-459413.html
LRESULT CMainDlg::OnNcHitTest(CPoint point)
{
// TODO: Add your message handler code here and/or call default
UINT nHitTest = CDialog::OnNcHitTest(point);
if ((nHitTest == HTCLIENT) && (::GetAsyncKeyState(MK_LBUTTON) < 0))
{
CRect rectDlg;
GetWindowRect(rectDlg);//获得窗体的大小
if (point.y < rectDlg.top + 30)
{
nHitTest = HTCAPTION;
}
else
{
nHitTest = HTNOWHERE;
}
}
return nHitTest;
}
重新编译代码,现在的对话框背景已经美化完成,并且这个对话框可以拖动。文章来源地址https://www.toymoban.com/news/detail-459413.html
到了这里,关于MFC 给对话框添加图片背景的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!