希望上一篇日志不要被骂,但是大的公司确实有能力购买皮肤库。但是小作坊就希望程序员是个千面手,什么都能搞定。
下面说的另外一种美化方法就是我们这种劳动力被压榨之下,想出来的对策。
现在看到非常PP的软件,除了用别人写的控件皮肤库之外,最大的特点就是形状都有。什么样的图案,风格都有。
试想一下,我们做桌面的壁纸可以有多PP就有多PP,那么也就是说如果能够把图片资源转化成为我们的界面资源,那么我们的界面想多美就多美。因为只要别人设计的图美我们的界面就一定美。
在VC界面美化中,摈弃WINDOW的默认窗口,基本只要其框架和消息响应机制。其他需要对话框,控件的地方,我们都采用OwnerDraw的方式来实现这写对话框、控件的重现。
例如:对话框的美化。我们可以在MFC资源管理器中直接拖入一个空白对话框,然后选择对应的OwnerDraw属性。在对话框的OnPaint()函数中装载你想要的背景图片,那么整个Dialog的背景就是一副图片了。网上多数这样的程序是将客户区设有背景,或者这个窗口是有背景,但是保留有标题栏的对话框,虽然整个窗口都被背景图填满,但是有时候标题栏的存在会使刷新出现问题。那么我们有时候干脆去掉Dialog的Border属性,让他只有客户区,然后我们自己定义最大、最小、关闭按钮。
如下图所示,我用一张背景图作为Dialog的背景,然后自己放了三个Buttons在上面,自己定义三个Buttons的响应操作。而Buttons控件也是OwnerDraw属性,这样我们才可以将图片加载到Buttons。(当然是因为我们自己封装了新的继承CButton的类实现这个功能)
需要明白的是,默认的标题栏的功能有:当鼠标点击在标题栏区域的时候,可以实现窗口的拖动。在标题栏区域点击右键可以看到系统菜单。
如果我们去掉了标题栏,为了实现Dialog的美化,那么实现窗口拖动的动作需要自己写。
一般会Override CWnd的WM_LBUTTONDOWN消息处理函数。在处理函数中,判断鼠标的位置,然后发送点击了标题栏的消息就可以了。即假装点击了标题栏。
- void CMyCamDlg::OnLButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- CDialog::OnLButtonDown(nFlags, point);
- /*-------------------Sunny--------------------*/
- if(DRAGBORDER<=point.x && point.x<=m_WndWidth-DRAGBORDER && DRAGBORDER<=point.y && point.y<=m_WndHeight-DRAGBORDER)
- {
- // 当鼠标的坐标属于中间区域的时候,不发送拖动窗口的消息。
- // 拖动窗口的效果是通过模拟发送点击Caption的消息来实现的; WM_NCLBUTTONDOWN,HCAPTION;
- return;
- }
- else
- {
- PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y));
- }
- }
DRAGBORDER是我自己定义可拖动的边界的宽度。m_WndWidth,m_WndHeight是我获得的窗口的宽度、高度。
按钮的美化基本就是让按钮可以加载BITMAP图片,或者可以加载ICON图标。这样BUTTON就可以比WINDOWS的灰色按钮好看多了。
这两类出现比较多的控件,实现了图片化的化,其他控件也基本可以图片化。
有些例子,可以上国外的开源网站上学习。
CodeProject 就很好。
先说下,如何实现窗口贴上背景图。在Dialog去掉Border属性后。
在InitialDialog代码中写入代码,OnPaint()函数中写入代码:
- BOOL CMyCamDlg::OnInitDialog()
- {
- CDialog::OnInitDialog();
- // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
- // 执行此操作
- SetIcon(m_hIcon, TRUE); // 设置大图标
- SetIcon(m_hIcon, FALSE); // 设置小图标
- // TODO: 在此添加额外的初始化代码
- /*-------------------Sunny--------------------*/
- g_Util.SelectSkin(g_Util.m_SkinsVector,_T("orange"));
- // 设置窗口的大小,并初始化窗口背景位图的句柄;
- Skin();
- // Arrange Buttons
- ArrangeButtons();
- //return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
- }
可以看出来我选择了Orange皮肤,然后Skin()函数设置了窗口大小,窗口大小根据背景图片的大小来定。然后OnPaint()函数中画出这幅背景图。
- void CMyCamDlg::Skin()
- {
- // Get CtlPanel Dialog BkImage from the CtlPanelSkin class;
- CString strPath = _T("");
- strPath.Format(_T("%s//%s//%s"),g_Util.m_SkinPath, g_Util.m_CurrentSkinName,g_Util.m_SkinContainer.m_CtlPanelSkin.m_BkgImgName);
- // paste BkImage;
- BITMAPINFO bInfo;
- CBitmap tempCBMAP;
- m_hBKBMAP = (HBITMAP)::LoadImage(AfxGetInstanceHandle(), strPath, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE);
- tempCBMAP.Attach(m_hBKBMAP);
- tempCBMAP.GetObject(sizeof(bInfo),&bInfo);
- m_WndWidth = bInfo.bmiHeader.biWidth;
- m_WndHeight = bInfo.bmiHeader.biHeight;
- MoveWindow(100,200,m_WndWidth,m_WndHeight);
- tempCBMAP.Detach();
- tempCBMAP.DeleteObject();
- }
strPath中存储了背景图片的完整路径和图片名。
- void CMyCamDlg::OnPaint()
- {
- CPaintDC dc(this); // 用于绘制的设备上下文
- if (IsIconic())
- {
- //CPaintDC dc(this); // 用于绘制的设备上下文
- SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
- // 使图标在工作矩形中居中
- int cxIcon = GetSystemMetrics(SM_CXICON);
- int cyIcon = GetSystemMetrics(SM_CYICON);
- CRect rect;
- GetClientRect(&rect);
- int x = (rect.Width() - cxIcon + 1) / 2;
- int y = (rect.Height() - cyIcon + 1) / 2;
- // 绘制图标
- dc.DrawIcon(x, y, m_hIcon);
- }
- else
- {
- CDialog::OnPaint();
- }
- //Skin();
- /*-------------------Sunny--------------------*/
- // paste BkImage;
- CBitmap tempCBMAP;
- ASSERT(m_hBKBMAP!=NULL);
- tempCBMAP.Attach(m_hBKBMAP);
- //在内存中创建一个位图兼容设备
- //CWindowDC dc(this);
- CDC dcMemory;
- dcMemory.CreateCompatibleDC(&dc);
- //将图片选入兼容设备
- CBitmap *pOldBmp=dcMemory.SelectObject(&tempCBMAP);
- dc.BitBlt(0,0,m_WndWidth,m_WndHeight,&dcMemory,0,0,SRCCOPY);
- dcMemory.SelectObject(pOldBmp);
- tempCBMAP.Detach();
- // past the effect tool bar
- tempCBMAP.DeleteObject();
- dcMemory.DeleteDC();
- ReleaseDC(&dcMemory);
- }
m_hBKBMAP 在Skinner()中初始化的,就是背景图片资源的句柄,我保留了。当然也可以重新在OnPaint中加载,觉得没有这个必要。除非是前面没有加载图片资源。(LoadImage函数加载图片)。
源代码参考(我上载的资源:PC CameraUI2.0中有类似代码)