C++ 异形窗口

本文参考:Duilib源码

原理:分层窗口,通过定时器和手动触发绘画窗口
由于GDI对透明通道支持不是很好,最好选择GDI+进行绘画。

1.设置窗口属性WS_EX_LAYERED和绘画定时器
 DWORD dwStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
 SetWindowLong(hWnd, GWL_EXSTYLE, dwStyle | WS_EX_LAYERED);
 ::SetTimer(hWnd, LAYEREDUPDATE_TIMERID, 10L, NULL);
2.UpdateLayeredWindow绘画窗口并且支持透明度设置
void onPaint()
{
	if (::IsIconic(hWnd))return 0;
	 RECT rtWindow;
     GetWindowRect(hWnd, &rtWindow);
     COLORREF *pOffscreenBits = NULL;
     PAINTSTRUCT ps;
     HDC hdc = BeginPaint(hWnd, &ps);
     HDC hDcOffscreen = ::CreateCompatibleDC(hdc);
     //创建支持透明通道的BITMAP,pOffscreenBits位图的起始位置,默认色值为ARGB。默认值为0
     HBITMAP hbmpOffscreen = CreateRGBA32Bitmap(hdc, rtWindow.right - rtWindow.left, rtWindow.bottom - rtWindow.top, &pOffscreenBits);
     HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(hDcOffscreen, hbmpOffscreen);

	 RECT rtPaint = { 0,0,rtWindow.right - rtWindow.left, rtWindow.bottom - rtWindow.top };
     PaintContent(hDcOffscreen, rtPaint);
     
	//绘画分层窗口,将BITMAP展示出来,如果PaintContent内容为空,则整个界面什么都没有,因为完全透明
	BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
 	SIZE sizeWnd = { rtWindow.right - rtWindow.left, rtWindow.bottom - rtWindow.top };
    POINT ptPos = { rtWindow.left, rtWindow.top };
	POINT ptSrc = { 0,0 };
	UpdateLayeredWindow(hWnd, hdc, &ptPos, &sizeWnd, hDcOffscreen, &ptSrc, 0, &bf, ULW_ALPHA);
    DeleteDC(hDcOffscreen);
    DeleteObject(hbmpOffscreen);
    EndPaint(hWnd, &ps);
}
//创建32位支持透明通道的位图RGBA
HBITMAP CreateRGBA32Bitmap(HDC hDC, int cx, int cy, COLORREF** pBits)
{
	LPBITMAPINFO lpbiSrc = NULL;
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	if (lpbiSrc == NULL) return NULL;

	lpbiSrc->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbiSrc->bmiHeader.biWidth = cx;
	lpbiSrc->bmiHeader.biHeight = cy;
	lpbiSrc->bmiHeader.biPlanes = 1;
	lpbiSrc->bmiHeader.biBitCount = 32;
	lpbiSrc->bmiHeader.biCompression = BI_RGB;
	lpbiSrc->bmiHeader.biSizeImage = cx * cy;
	lpbiSrc->bmiHeader.biXPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biYPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biClrUsed = 0;
	lpbiSrc->bmiHeader.biClrImportant = 0;

	HBITMAP hBitmap = CreateDIBSection(hDC, lpbiSrc, DIB_RGB_COLORS, (void**)pBits, NULL, NULL);
	delete[] lpbiSrc;
	return hBitmap;
}
//通过gdi的方式实现支持Alpha填充背景色的功能
void DrawColor(HDC hDC, const RECT& rc, DWORD color)
{
    COLORREF* pColors = nullptr;
    HDC hMemDC = ::CreateCompatibleDC(hDC);
    HBITMAP hBitMap = CreateRGBA32Bitmap(hDC, rc.right - rc.left, rc.bottom - rc.top, &pColors);
    ::SelectObject(hMemDC, hBitMap);

    COLORREF* pTempOffscreenBits = NULL;
    for (LONG y = 0; y < rc.bottom - rc.top; ++y) {
        for (LONG x = 0; x < rc.right - rc.left; ++x) {
            pTempOffscreenBits = pColors + y * (rc.right - rc.left) + x;
           
            *pTempOffscreenBits = color;
        }
    }
    BLENDFUNCTION bf = { AC_SRC_OVER, 0, GetAValue(color), AC_SRC_ALPHA };
    AlphaBlend(hDC, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hMemDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, bf);
    DeleteObject(hBitMap);
    DeleteDC(hMemDC);
}
void DrawPng(HDC hDC,RECT rtDest)
{
	int w = 0, h = 0, channels = 0;
	stbi_uc* pdata = stbi_load("icon_user_disk.png", &w, &h, &channels, 4);
    if (pdata)
    {
		COLORREF* pColors = nullptr;
		HDC hMemDC = ::CreateCompatibleDC(hDC);
		HBITMAP hBitMap = CreateRGBA32Bitmap(hDC, w, h, &pColors);
		::SelectObject(hMemDC, hBitMap);
        //BGRA -> RGBA
        COLORREF* dest = (COLORREF*)pdata;
        for (int x = 0;x < w;++x)
        {
            for (int y = 0;y < h;++y)
            {
                stbi_uc* bDestColorBits = (stbi_uc*)(&pColors[x * h + y]);
                stbi_uc* bsrcColorBits = (stbi_uc*)(&dest[x * h + y]);
                /* BGRA -> RGBA */
                bDestColorBits[3] = bsrcColorBits[3];
                bDestColorBits[2] = bsrcColorBits[0];
                bDestColorBits[1] = bsrcColorBits[1];
                bDestColorBits[0] = bsrcColorBits[2];
            }
        }
		BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
		AlphaBlend(hDC, rtDest.left, rtDest.top, rtDest.right - rtDest.left, rtDest.bottom - rtDest.top, hMemDC, 0, 0, w, h, bf);
		DeleteObject(hBitMap);
		DeleteDC(hMemDC);
    }
	STBI_FREE(pdata);
}
void PaintContent(HDC hDc, RECT rcPaint)
{
	RECT rtPaint = { 0,0,rcPaint.right - rcPaint.left, rcPaint.bottom - rcPaint.top };
	RECT rcItem1 = { rtPaint.left + 10,rtPaint.top + 10,rcItem1.left + 100,rcItem1.top + 100 };

	RECT rcItem2 = { rcItem1.right + 10,rtPaint.top + 10,rcItem2.left + 100,rcItem2.top + 100 };
	//DrawColor(hDc, rcItem1, 0xad00ff00);

	HICON hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_SMALL));
	DrawIcon(hDc, rcItem2.right + 10, rcItem2.top, hIcon);
	::SetBkMode(hDc, TRANSPARENT);
	::SetTextColor(hDc, RGB(255, 0, 0));
	std::wstring strText = L"Hellow word!!中国";
	DrawText(hDc, strText.c_str(), strText.size(), &rcItem2, DT_SINGLELINE | DT_VCENTER);

	RECT rcItem3 = { rcItem1.right + 10,rcItem1.bottom + 10,rcItem3.left + 100,rcItem3.top + 100 };
	Gdiplus::Image img(L"E:\\work\\PMS\\yiletu\\xiaoyi\\xyBar\\binx86\\Debug\\skin\\res\\yiletoo.png");
	Gdiplus::Graphics g(hDc);
	g.DrawImage(&img, (INT)rcItem3.left, (INT)rcItem3.top);
    Gdiplus::Font ft(L"宋体", 18);
    Gdiplus::PointF pt = { (REAL)rcItem3.right + 10.0f,(REAL)rcItem3.top };
    Gdiplus::SolidBrush b(Color(0x99, 0xff, 0, 0));
    g.SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
    g.SetPixelOffsetMode(PixelOffsetModeDefault);
    g.SetCompositingMode(CompositingModeSourceOver);
    g.SetCompositingQuality(CompositingQualityDefault);
    g.DrawString(strText.c_str(), strText.size(), &ft, pt, &b);

    Gdiplus::RectF rtf = { (REAL)rcItem1.left,(REAL)rcItem1.top,(REAL)rcItem1.right - rcItem1.left,(REAL)rcItem1.bottom - rcItem1.top };
    g.FillRectangle(&b, rtf);
}

效果图:
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值