VC++ 不规则窗体的实现(二)

不规则窗体多用于程序启动窗口,要实现不规则窗体,背景一般都会采用贴图的方式,图片格式首先肯定是png格式了。

加载png图片,这里建议用GDI+接口实现比较方便:

1、GDI+资源初始化

// 库声明

#include <GdiPlus.h>
using namespace Gdiplus;

ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

2、png图片的加载

char szFileName[] = ".\\res\\BkImage.png";
int nszBufSize = strlen(szFileName) + 1;
DWORD nwszBufSize = MultiByteToWideChar(CP_ACP, 0, szFileName, nszBufSize, NULL, 0);
wchar_t * wszFileName = new wchar_t[nwszBufSize];
wmemset(wszFileName, 0, nwszBufSize);
int nRet = MultiByteToWideChar(CP_ACP, 0, szFileName, nszBufSize, wszFileName, nwszBufSize);
Gdiplus::Image * pImage = Gdiplus::Image::FromFile(wszFileName);
if (pImage->GetLastStatus() != Ok)
{
    // 加载失败了
}

delete pImage;
pImage = NULL;
delete wszFileName;
wszFileName = NULL;

3、窗体背景的绘制:

BOOL OnInitDialog()
{
    // 修改窗体为分层窗口,窗体将不会再响应WM_PAINT消息
    ModifyStyleEx(0, WS_EX_LAYERED); 
    // 或SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
    // 设置窗体背景像素透明色
    ::SetLayeredWindowAttributes(m_hWnd, RGB(0xFF, 0xFF, 0xFF), 0xFF, LWA_COLORKEY | LWA_ALPHA);
    // 通知窗口和所有子窗口重绘
    ::RedrawWindow(m_hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
    // 由于窗体可以响应WM_PAINT消息了,所以绘制代码可以在WM_PAINT消息事件里面去实现
    //DrawBackgroundImage();
}

void DrawBackgroundImage()
{

    //获取窗口绘图DC句柄
    HDC hDC = ::GetDC(m_hWnd);
    //创建与窗口绘图DC兼容的内存DC
    HDC hMemDC = ::CreateCompatibleDC(hDC);
    //获取窗体客户区显示区域大小
    CRect rcClient;
    GetClientRect(rcClient);
    //分配与窗体客户区显示区域大小相等的背景位图内存空间(绘图画布)
    BITMAPINFO bitmapinfo;
    bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitmapinfo.bmiHeader.biBitCount = 32;//32位位图支持alpha透明度
    bitmapinfo.bmiHeader.biHeight = rcClient.Height();
    bitmapinfo.bmiHeader.biWidth = rcClient.Width();
    bitmapinfo.bmiHeader.biPlanes = 1;
    bitmapinfo.bmiHeader.biCompression = BI_RGB;
    bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
    bitmapinfo.bmiHeader.biYPelsPerMeter = 0;
    bitmapinfo.bmiHeader.biClrUsed = 0;
    bitmapinfo.bmiHeader.biClrImportant = 0;
    bitmapinfo.bmiHeader.biSizeImage = bitmapinfo.bmiHeader.biWidth * bitmapinfo.bmiHeader.biHeight * bitmapinfo.bmiHeader.biBitCount / 8;
    HBITMAP hBitmap = ::CreateDIBSection(hMemDC, &bitmapinfo, 0, NULL, 0, 0);
    //交换背景位图
    HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemDC, hBitmap);

    //开始画图操作,直接对hMemDC操作,就不要用hDC了
    DrawBk(hMemDC, rcClient);

    //内存绘制好的图像更新到窗口
    CPoint DestPt(0, 0);
    CSize psize(rcClient.Width(), rcClient.Height());
    BLENDFUNCTION blendFunc32bpp;
    blendFunc32bpp.AlphaFormat = AC_SRC_ALPHA;
    blendFunc32bpp.BlendFlags = 0;
    blendFunc32bpp.BlendOp = AC_SRC_OVER;
    blendFunc32bpp.SourceConstantAlpha = 255;
    ::UpdateLayeredWindow(m_hWnd, hDC, NULL, &psize, hMemDC, &DestPt, 0, &blendFunc32bpp, ULW_COLORKEY);
    //::AlphaBlend(hDC, rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), hMemDC, rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), blendFunc32bpp);

    //释放资源
    ::SelectObject(hMemDC, hOldBitmap);
    ::DeleteObject(hBitmap);
    ::DeleteDC(hMemDC);
    ::ReleaseDC(m_hWnd, hDC);
}

void OnPaint()
{
    // 绘制代码
    DrawBackgroundImage();
    CDialog::OnPaint();
}

这种方法实现的效果图(蓝色背景是Windows桌面背景):

窗体上的子控件显示出来了。

4、GDI+资源释放

GdiplusShutdown(gdiplusToken);

优点:子控件不用自绘。

缺点: 主窗体背景不够圆润,有毛边,网上说需要对非完全透明的像素进行处理,才能去掉锯齿(试了一下,但是没成功)。

附加:无标题栏窗口的移动,只需要在ON_WM_LBUTTONDOWN消息事件里面添加如下代码即可:

PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, 0L); 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值