本文参考: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 = CreateARGB32Bitmap(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位支持透明通道的位图
HBITMAP CreateARGB32Bitmap(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 = CreateARGB32Bitmap(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 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);
}
效果图: